This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] Fix last_write_time tests for filesystems that don't support very small times.
ClosedPublic

Authored by vsapsai on Jan 31 2018, 11:27 AM.

Details

Summary

APFS minimum supported file write time is -2^63 nanoseconds, which doesn't go
as far as file_time_type::min() that is equal to -2^63 microseconds on macOS.

This change doesn't affect filesystems that support file_time_type range only
for in-memory file time representation but not for on-disk representation. Such
filesystems are considered as SupportsMinTime.

rdar://problem/35865151

Diff Detail

Repository
rL LLVM

Event Timeline

vsapsai created this revision.Jan 31 2018, 11:27 AM

Don't like removing new_time = file_time_type::min() + MicroSec(1); part of the test_write_min_time but it escapes file_time_type::min() check. If somebody can explain the purpose of this test, I'd be glad to preserve it for filesystems that support very small times.

Hahnfeld requested changes to this revision.Feb 1 2018, 6:30 AM

Can you please add a summary that describes which filesystem this problem can be seen with? I think outside people can't access rdar tickets, so I can only guess that it's related to APFS? Further guessing the filesystem supports negative timestamps in general but not file_time_type::min() (which probably is -2 ** 63)?

Don't like removing new_time = file_time_type::min() + MicroSec(1); part of the test_write_min_time but it escapes file_time_type::min() check. If somebody can explain the purpose of this test, I'd be glad to preserve it for filesystems that support very small times.

I think the idea was to have something slightly larger than file_time_type::min() which generally makes sense for testing corner cases. However, there is no equivalent check for file_time_type::max() so I'd like to hear @EricWF whether we should keep it.

This revision now requires changes to proceed.Feb 1 2018, 6:30 AM
vsapsai edited the summary of this revision. (Show Details)Feb 1 2018, 3:05 PM

Can you please add a summary that describes which filesystem this problem can be seen with? I think outside people can't access rdar tickets, so I can only guess that it's related to APFS? Further guessing the filesystem supports negative timestamps in general but not file_time_type::min() (which probably is -2 ** 63)?

Good suggestion for explaining the problem with file_time_type::min() in more detail. Also PR35990 has some details on how different filesystems handle file_time_type::min(). As the change doesn't fix the PR, I don't think it is worth mentioning it in the commit message but it can be still useful in code review discussion.

Hahnfeld resigned from this revision.Feb 2 2018, 12:38 AM

Good suggestion for explaining the problem with file_time_type::min() in more detail. Also PR35990 has some details on how different filesystems handle file_time_type::min(). As the change doesn't fix the PR, I don't think it is worth mentioning it in the commit message but it can be still useful in code review discussion.

If there is an upstream bug report, please link to that one. With that information the changes look good, but I'd like @EricWF to accept.

LGTM except the removal of the test. I think it's probably valuable to keep around on platforms that allow it.

What do you think?

libcxx/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
360 ↗(On Diff #132233)

I would really love to keep this test. I think it has the ability to detect incorrect integer arithmetic in last_write_time when UBSAN is enabled.

Could we maybe add another check like SupportsAlmostMinTime where that checks ::min() + MicroSec(1)?

vsapsai added inline comments.Feb 13 2018, 5:56 PM
libcxx/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
360 ↗(On Diff #132233)

What about nesting removed part in TimeIsRepresentableByFilesystem like

if (TimeIsRepresentableByFilesystem(new_time)) {
    TEST_CHECK(!ec);
    TEST_CHECK(tt >= new_time);
    TEST_CHECK(tt < new_time + Sec(1));

    ec = GetTestEC();
    last_write_time(p, Clock::now());

    new_time = file_time_type::min() + MicroSec(1);

    last_write_time(p, new_time, ec);
    tt = last_write_time(p);

    if (TimeIsRepresentableByFilesystem(new_time)) {
        TEST_CHECK(!ec);
        TEST_CHECK(tt >= new_time);
        TEST_CHECK(tt < new_time + Sec(1));
    }
}

As for me, I don't like how it looks. So maybe the same approach but with a flag like

bool supports_min_time = false;
if (TimeIsRepresentableByFilesystem(new_time)) {
    TEST_CHECK(!ec);
    TEST_CHECK(tt >= new_time);
    TEST_CHECK(tt < new_time + Sec(1));
    supports_min_time = true;
}

ec = GetTestEC();
last_write_time(p, Clock::now());

new_time = file_time_type::min() + MicroSec(1);

last_write_time(p, new_time, ec);
tt = last_write_time(p);

if (supports_min_time && TimeIsRepresentableByFilesystem(new_time)) {
    TEST_CHECK(!ec);
    TEST_CHECK(tt >= new_time);
    TEST_CHECK(tt < new_time + Sec(1));
}

Yet another option is to leverage that APFS truncates time to supported value, something like

if ((old_tt < new_time + Sec(1)) && TimeIsRepresentableByFilesystem(new_time))

I don't like it because it implicitly relies on time truncation which is not guaranteed for all filesystems and it is slightly harder to understand than boolean.

How do you like these ideas? SupportsAlmostMinTime can also work but I'd like to avoid repeating + MicroSec(1) part in 2 places.

EricWF added inline comments.Feb 13 2018, 9:51 PM
libcxx/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
360 ↗(On Diff #132233)

The first option seems fine to me.

vsapsai updated this revision to Diff 135003.Feb 19 2018, 5:48 PM
  • Add back existing test but run it only when file system supports min time.
vsapsai marked an inline comment as done.Feb 19 2018, 5:49 PM

I am going to commit this change as I've addressed the review comments. If anybody has anything else to add, we can discuss that in post-commit review.

This revision was not accepted when it landed; it landed in state Needs Review.Feb 28 2018, 3:30 PM
This revision was automatically updated to reflect the committed changes.