src,fs: calculate times as unsigned long#13281
Conversation
test/parallel/test-fs-utimes.js
Outdated
There was a problem hiding this comment.
Needs a newline at the end of the file
|
"Dry run" CI: https://ci.nodejs.org/job/node-test-commit/10219/ |
test/parallel/test-fs-utimes.js
Outdated
test/parallel/test-fs-utimes.js
Outdated
There was a problem hiding this comment.
I think it would help with readability if you could add a comment explaining why these magic values are magic (I had to dig into the libuv sources, and I’m still not quite sure I got it right). ;)
There was a problem hiding this comment.
Tryied to hint with the name, but will add a comment.
src/node_file.cc
Outdated
There was a problem hiding this comment.
I think it would be a good idea if you could leave a comment here, explaining why this is needed.
And just so I get it right; this is needed because tv_sec overflows? I think the real problem in that case is that we don’t check for overflows in libuv during fs__utime_handle, which we probably should? Am I getting it totally wrong?
|
delint @ added comments |
src/node_file.cc
Outdated
There was a problem hiding this comment.
These changes seem unrelated, and I don’t think they are actually changing anything?
There was a problem hiding this comment.
They remove warnings, but I'll kick them out since I have a more "warning reducing" PR cooking
test/parallel/test-fs-utimes.js
Outdated
There was a problem hiding this comment.
That’s not really a comment explaining what’s happening…
It’s not like (signed long) 2159345162531 == -2135622133469 – it’s more complicated than that, it definitely relates to how the Windows API deals with timestamps.
There was a problem hiding this comment.
It's almost that simple https://github.com/nodejs/node/blob/master/deps/uv/src/win/fs.c#L91
NTFS stores times in nanoseconds in a uint64_t but when uv converts it down to long we get 2's complement.
There was a problem hiding this comment.
Hm. Then maybe we should cast back to unsigned only on Windows?
But really, I’m not sure whether this is the right approach, or if we are better off throwing in utimes if the time is not representable as a long…
There was a problem hiding this comment.
I added to the comment why it's not a problem in POSIX, because there timestamps are stored in two fields struct {long t_sec, long t_usec}, and neither can overflow.
The problem is just how we convert from the NTFS uint64_t that hold nanoseconds, back to seconds.
IMHO This change is safe, since even the numbers from NTFS if properly converted to seconds fit in a long and in a double. (notice that the actual call to utimesSync divides these numbers by 1000). Also no FS will give us negative times, and the paper mentioned in the bug (interpretation-of-ntfs-timestamps), says we just need to interpret it right.
You might be right in that the calculations in https://github.com/nodejs/node/blob/master/deps/uv/src/win/fs.c#L91 should be done with uint
297a69c to
1e4c0c8
Compare
|
more cleanup. |
addaleax
left a comment
There was a problem hiding this comment.
Thanks for the updates! Looks good assuming we’re switching back to not doing 32-bit math.
src/node_file.cc
Outdated
There was a problem hiding this comment.
Y2k38 bug? ;) I think doing the math in uint64_t (or double because it’s getting converted anyway) as you had it before was fine, is there any reason to switch?
There was a problem hiding this comment.
This whole fix turns Y2K38 to something like Y3K16
But there's a bug when doing static_cast<uint64_t> since the MSB is 1, it blows up to a huge number.
Also long (a.k.a. int32_t) to uint32_t is faster / stabler anyway.
There was a problem hiding this comment.
*static_cast<uint64_t>
There was a problem hiding this comment.
This whole fix turns Y2K38 to something like Y3K16
Ah, right. (Still not great, but yes, it’s better.)
But there's a bug when doing
static_cast<uint64_t>since the MSB is 1, it blows up to a huge number.
You have the overflow problem anyway, though? Also, this doesn’t happen if you cast to double directly.
There was a problem hiding this comment.
since casting to double is a calculation is comes out a negative double.
Maybe a reinterpret_cast<uint64_t> or static_cast<uint64_t>(static_cast<uint32_t>()) first inner one to convince the compiler it's a positive number...
There was a problem hiding this comment.
@refack The thing is, I’m not sure you can count on long being 32-bit on all those odd systems that Node supports. unsigned long is the right thing anyway if you are reading from a long.
There was a problem hiding this comment.
That was my initial thought but the linter was angry at me:
for
(static_cast<unsigned long>(s->st_##name.tv_sec) * 1e3)
it spet out
src/node_file.cc:483: Use int16/int64/etc, rather than the C type long [runtime/int] [4]
got the same for:
(unsigned long)(s->st_##name.tv_sec) * 1e3)
There was a problem hiding this comment.
That was my initial thought
Good that we agree, though. :)
but the linter was angry at me:
// NOLINT(runtime/int) should help, although I’m not sure where exactly you need to place that
test/parallel/test-fs-utimes.js
Outdated
No thank you! Just linter: https://ci.nodejs.org/job/node-test-linter/9444/ |
|
fs dates on windows is a gift that keeps on giving. Would it be bad to have the 2k38 test use |
good idea 👍 (even though there it's kept as seconds, not millis) |
|
"Dry run" CI: https://ci.nodejs.org/job/node-test-commit/10275/ |
|
@refack yeah that's why i suggested increasing the number to a full second, but your method is nicer and a lot clearer what it's testing for. I was interested in seeing if all the other platforms would handle 2k38, seems like most of them did fine at least. :) |
PR-URL: nodejs#13281 Fixes: nodejs#13255 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
|
Should this land in LTS? Does it have any chance of changing behavior? |
|
|
This is not landing cleanly, ca you please backport with relevant commits |
Fixes: #13255
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
fs