Skip to content

unix: fix utime/futime timestamp rounding errors#2747

Merged
vtjnash merged 3 commits into
libuv:v1.xfrom
bnoordhuis:node-fix32369
Nov 28, 2020
Merged

unix: fix utime/futime timestamp rounding errors#2747
vtjnash merged 3 commits into
libuv:v1.xfrom
bnoordhuis:node-fix32369

Conversation

@bnoordhuis

@bnoordhuis bnoordhuis commented Mar 21, 2020

Copy link
Copy Markdown
Member

uv_fs_utime() and uv_fs_futime() receive the timestamp as
a double and then convert it to struct timeval or struct timespec
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second.

Fixes: nodejs/node#32369 (partially)
CI: https://ci.nodejs.org/job/libuv-test-commit/1806/
CI: https://ci.nodejs.org/job/libuv-test-commit/1817/
CI: https://ci.nodejs.org/job/libuv-test-commit/1825/

Comment thread src/unix/fs.c Outdated
t.tv_sec = x;
t.tv_nsec = 1e9 * uv__frac(x);

/* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, when can we remove this? I'm only asking because WASI wants nanosecond precision.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge this and open a PR that removes it.

@bnoordhuis bnoordhuis force-pushed the node-fix32369 branch 2 times, most recently from 3745b86 to c57bf54 Compare March 27, 2020 23:13
@bnoordhuis

Copy link
Copy Markdown
Member Author

FTR, this is how the test fails on Windows:

19:15:03 # Assertion failed in c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2017\test\test-fs.c on line 821:
`s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime`
(2119191946.955162 == -14245440.000000)

@stale

stale Bot commented May 6, 2020

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale Bot added the stale label May 6, 2020
@vtjnash

vtjnash commented Jul 28, 2020

Copy link
Copy Markdown
Member

Perhaps our time computation is overflowing in a similar way here https://github.com/libuv/libuv/blame/master/src/win/fs.c#L146? or just doesn't like the casts to unsigned? or the filesystem doesn't support negative times?

vtjnash pushed a commit to vtjnash/libuv that referenced this pull request Nov 6, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 6, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 6, 2020
Without `volatile`, the x87 hardware may re-organize the comparison math and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
@stale stale Bot removed the stale label Nov 6, 2020
@vtjnash

vtjnash commented Nov 6, 2020

Copy link
Copy Markdown
Member

I ended up changing some of the details of the PR (in particular, fmod was the wrong function to emulate here—we needed floor), and also fixed the equivalent problems on Windows

CI: https://ci.nodejs.org/job/libuv-test-commit/2085/

vtjnash pushed a commit to bnoordhuis/libuv that referenced this pull request Nov 10, 2020
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 10, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 10, 2020
Without `volatile`, the x87 hardware may re-organize the comparison math and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
@vtjnash

vtjnash commented Nov 10, 2020

Copy link
Copy Markdown
Member

Tests are a bit too aggressive for some of our CI filesystems, but intended to show that it works correctly on at least some of the configurations. Will need to back off on those slightly then merge this. Anyone willing to review?

@vtjnash

vtjnash commented Nov 16, 2020

Copy link
Copy Markdown
Member

bump for (re)review

vtjnash pushed a commit to bnoordhuis/libuv that referenced this pull request Nov 18, 2020
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 18, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 18, 2020
Without `volatile`, the x87 hardware may re-organize the comparison math and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
vtjnash added a commit to vtjnash/libuv that referenced this pull request Nov 18, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to vtjnash/libuv that referenced this pull request Nov 18, 2020
Without `volatile`, the x87 hardware may re-organize the comparison math and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
@cjihrig

cjihrig commented Nov 18, 2020

Copy link
Copy Markdown
Contributor

I already signed off on Ben's changes, but my LGTM still stands if you want to move this forward.

@vtjnash

vtjnash commented Nov 18, 2020

Copy link
Copy Markdown
Member

Thanks. I'd changed enough about it that I felt it needed a re-confirmation before merging.

I've got most tests functioning now (https://ci.nodejs.org/job/libuv-test-commit/2088/), but need to update a couple more.

@vtjnash vtjnash force-pushed the node-fix32369 branch 3 times, most recently from 5fed6f5 to bed5761 Compare November 19, 2020 22:16
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 19, 2020
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
vtjnash added a commit to bnoordhuis/libuv that referenced this pull request Nov 19, 2020
Without `volatile`, the x87 hardware may re-organize the comparison math and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
@vtjnash

vtjnash commented Nov 19, 2020

Copy link
Copy Markdown
Member

Final CI, for most recent fixup commit is not showing any related failures: https://ci.nodejs.org/job/libuv-test-commit/2090/. Should be ready for someone to land now!

bnoordhuis and others added 3 commits November 28, 2020 10:48
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Without `volatile`, the x87 hardware may re-organize the comparison math
and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@vtjnash vtjnash merged commit dde9815 into libuv:v1.x Nov 28, 2020
JeffroMF pushed a commit to JeffroMF/libuv that referenced this pull request May 16, 2022
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
JeffroMF pushed a commit to JeffroMF/libuv that referenced this pull request May 16, 2022
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
JeffroMF pushed a commit to JeffroMF/libuv that referenced this pull request May 16, 2022
Without `volatile`, the x87 hardware may re-organize the comparison math
and end up with the wrong answer.

Fixes: one bullet point item of
    libuv#2655 and the tests from
    libuv#849 in certain build configurations
PR-URL: libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Jul 23, 2025
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv/libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Jul 23, 2025
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv/libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Jul 23, 2025
Without `volatile`, the x87 hardware may re-organize the comparison math
and end up with the wrong answer.

Fixes: one bullet point item of
    libuv/libuv#2655 and the tests from
    libuv/libuv#849 in certain build configurations
PR-URL: libuv/libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Dec 16, 2025
`check_utime()` already calls `uv_fs_stat()`, no point in doing it
twice.

PR-URL: libuv/libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Dec 16, 2025
`uv_fs_utime()` and `uv_fs_futime()` receive the timestamp as
a `double` and then convert it to `struct timeval` or `struct timespec`
where necessary but the calculation for the sub-second part exhibited
rounding errors for dates in the deep past or the far-flung future,
causing the timestamps to be off by sometimes over half a second on
unix, or to be reinterpreted as unsigned and end up off by more than
just sign but many also decades.

Fixes: nodejs/node#32369 (partially)
PR-URL: libuv/libuv#2747
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Dec 16, 2025
Without `volatile`, the x87 hardware may re-organize the comparison math
and end up with the wrong answer.

Fixes: one bullet point item of
    libuv/libuv#2655 and the tests from
    libuv/libuv#849 in certain build configurations
PR-URL: libuv/libuv#2747
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fs.Stat fails on pre-epoch mtime (<1970-01-01T00:00:00Z)

3 participants