Skip to content

Fix test_futimens_nodefs under Windows - #27801

Merged
sbc100 merged 1 commit into
emscripten-core:mainfrom
sbc100:fix_test_futimens_nodefs_windows
Sep 29, 2026
Merged

sbc100 merged 1 commit into
emscripten-core:mainfrom
sbc100:fix_test_futimens_nodefs_windows

Conversation

@sbc100

@sbc100 sbc100 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

In #27794 we clamped sub-second timestamps near the 1-second boundary
to prevent double-precision rounding from incrementing the second.
However, under Windows, Node.js (libuv) converts Unix timestamps to
Windows FILETIME (100-nanosecond intervals since Jan 1, 1601 UTC):

filetime = (time + 11644473600) * 10000000;

Adding the 11.6 billion second epoch offset reduces floating-point
precision (1 ULP becomes ~1.9 microseconds). When tv_nsec was close
to 1e9 (e.g. 999,999,900 ns in test_futimens), adding the offset
still rounded the result up into the next integer second on Windows.

Instead of performing floating-point clamping near maxSec, round
tv_nsec down to the nearest 10 microseconds (10,000 ns). This leaves
sufficient headroom below the next whole second while preserving
sub-millisecond timestamp precision.

See: #25280

In emscripten-core#27794 we clamped sub-second timestamps near the 1-second boundary
to prevent double-precision rounding from incrementing the second.
However, under Windows, Node.js (`libuv`) converts Unix timestamps to
Windows `FILETIME` (100-nanosecond intervals since Jan 1, 1601 UTC):

  filetime = (time + 11644473600) * 10000000;

Adding the 11.6 billion second epoch offset reduces floating-point
precision (1 ULP becomes ~1.9 microseconds). When `tv_nsec` was close
to 1e9 (e.g. 999,999,900 ns in `test_futimens`), adding the offset
still rounded the result up into the next integer second on Windows.

Instead of performing floating-point clamping near `maxSec`, round
`tv_nsec` down to the nearest 10 microseconds (10,000 ns). This leaves
sufficient headroom below the next whole second while preserving
sub-millisecond timestamp precision.

See: emscripten-core#25280
@sbc100
sbc100 force-pushed the fix_test_futimens_nodefs_windows branch from aaa62fb to fac100a Compare September 29, 2026 20:55
@sbc100 sbc100 changed the title Fix test_futimens_nodefs under Windows. NFC Fix test_futimens_nodefs under Windows Sep 29, 2026
Comment thread src/lib/libsyscall.js
Comment on lines +1102 to +1103
tv_nsec = (tv_nsec / 10000 | 0) * 10000;
return (tv_sec + (tv_nsec / 1e9)) * 1000;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A little less readable, but avoids one lossy round.

Suggested change
tv_nsec = (tv_nsec / 10000 | 0) * 10000;
return (tv_sec + (tv_nsec / 1e9)) * 1000;
return (tv_sec * 1000) + ((tv_nsec / 10000 | 0) / 100);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Gemini seems sure that these are equivalent, especially since the consumer of these values fs.utimesSync expects seconds anyway, so we do do the decide by 1000 there anyway: basically we do utimes(arg, atime / 1000, mtime / 1000).

I kind of like the proposed approach in this PR for readability.

@sbc100
sbc100 merged commit f99d501 into emscripten-core:main Sep 29, 2026
42 checks passed
@sbc100
sbc100 deleted the fix_test_futimens_nodefs_windows branch September 29, 2026 23:00
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.

2 participants