APFS mtime timestamp numeric precision (rounding) error

Number:rdar://41226928 Date Originated:June 18 2018
Status:Open Resolved:
Product:APFS Product Version:10.13.5 (17F77)
Classification:Severe Bug Reproducible:Always

APFS (presumably the driver) on macOS 10.13 (up to an including at least 10.13.5 (17F77)) has a numeric precision / rounding error for file modification & other file metadata timestamps.

I am unsure (due to a lack of syscall source code on macOS) if this is a bug in the utime(2) call itself as implemented in macOS 10.13, or the APFS driver, but the driver seems more likely to me (since the syscall is relatively un-complex and not at all new).

This same bug was also reported from the Ruby programming language, and the openradar report of it is the only way I was able to decisively narrow this down:
http://www.openradar.me/33734892 or https://github.com/lionheart/openradar-mirror/issues/18144

I can confirm that this is reproducible using only C syscalls.

Steps to Reproduce:

I have isolated one of the numeric values that causes incorrect precision handling / rounding, 1529011085547.0, from various test sources. 

This value always causes this problem on only macOS 10.13, using APFS. macOS 10.12 and lower, other BSD platforms, linuxes, Windows, etc, do not have this issue. (AIX appears to also have the issue, but... oh well.)

When this value is sent to utime(2) (for either atime, mtime, or both), the respective value as read from the file metadata in stat(2) will no longer be what it was set to, and instead somehow ends up being 9223372036.854776

In my case, this patch to the libuv cross-platform I/O library written in C always reproduces this issue in it's tests: https://github.com/Fishrock123/libuv/commit/29527a82e87871e48b976248b62b3be2c369b3d7

Here is a test run from the libuv project's infrastructure showing platforms which it does and does not fail on: https://ci.nodejs.org/view/libuv/job/libuv-test-commit/929/  (Some test failures are from other tests, and not every failure if from this patch.)

Attached is a C-only version. Compile it by running `cc apfs-precision-error.c` and then run the created `a.out` to get comparison output.

Expected Results:

After setting the mtime to 1529011085547.0 using utime(2)
stat(2) should return mtime values that equal 1529011085547.0

Actual Results:

After setting the mtime to 1529011085547.0 using utime(2)
stat(2) returns mtime values that equal 9223372036.854776


10.13.5 (17F77)


Default configuration macOS 10.13 on colleagues' computers seems to also reproduce this always.

### apfs-precision-error.c

#include <stdio.h>
#include <sys/stat.h>
#include <utime.h>
#include <fcntl.h>

const char* path = "./.temp";
const double controlValue = 1529011085547.0;

int main(int argc, const char *argv[])
    open(path, O_CREAT);

    struct utimbuf buf;
    buf.actime = controlValue;
    buf.modtime = controlValue;
    utime(path, &buf);

    struct stat s;
    stat(path, &s);

    double converted_atime = (unsigned long)s.st_atimespec.tv_sec + (s.st_atimespec.tv_nsec / 1000000000.0);
    double converted_mtime = (unsigned long)s.st_mtimespec.tv_sec + (s.st_mtimespec.tv_nsec / 1000000000.0);

    printf("atime - Actual: %f, Expected: %f\n", converted_atime, controlValue);
    printf("mtime - Actual: %f, Expected: %f\n", converted_mtime, controlValue);


Apple Response

Apple has replied to this issue with the following:

After reviewing your feedback, we have some additional information for you, or some additional information, or action is necessary for this issue:

This behaves correctly.

Unless it was mysteriously fixed, I am quite sure that whoever review this ticket is wrong, because I provided very clear evidence that it worked incorrectly.

By Jeremiah.Senkpiel at Aug. 6, 2021, 5:03 a.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!