Skip to content

Fix utime() syscall #16460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 10, 2022
Merged

Fix utime() syscall #16460

merged 8 commits into from
Mar 10, 2022

Conversation

tiran
Copy link
Contributor

@tiran tiran commented Mar 9, 2022

Fix off by factor 1000: FS.utime() expects mtime and atime in seconds.

times == NULL is now correctly handled. utimes(path, NULL)
updates atime and mtime to current time.

https://nodejs.org/api/fs.html#fsutimespath-atime-mtime-callback

Fixes: #16458
Signed-off-by: Christian Heimes christian@python.org

Fix off by factor 1000: ``FS.utime()`` expects mtime and atime in seconds.

``times == NULL`` is now correctly handled. ``utimes(path, NULL)``
updates atime and mtime to current time.

https://nodejs.org/api/fs.html#fsutimespath-atime-mtime-callback

Fixes: emscripten-core#16458
Signed-off-by: Christian Heimes <christian@python.org>
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

Thanks!

I'm curious to see if any tests fail.. if they don't it means we lack coverage.

@tiran
Copy link
Contributor Author

tiran commented Mar 9, 2022

Thanks!

I'm curious to see if any tests fail.. if they don't it means we lack coverage.

I compiled test_utime.c manually and patched the JS code. The test failed for me because errno was not reset to 0. I wonder if the test is actually executed...

The test file now resets errno, checks return values, and tests for utime(path, NULL)

@tiran tiran marked this pull request as ready for review March 9, 2022 19:55
@@ -32,20 +33,35 @@ void test() {
// will fail
struct utimbuf t = {1000000000, 1000000000};

utime("writeable", &t);
errno = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm .. if this line is needed.. how was the test passing before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have no clue ...

Copy link
Collaborator

Choose a reason for hiding this comment

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

What test are you running that fails if you remove this line?

./tests/runner core2.test_utime works fine for on HEAD.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I executed the test manually with $ emcc -s NODERAWFS -o test_utime.js test_utime.c && node test_utime.js. The test failed with error message RuntimeError: Aborted(Assertion failed: !errno, at: test_utime.c,37,test). My guess is that some function earlier left errno != 0.

From man errno(3):

The value in errno is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno. The value of errno is never set to zero by any system call or library function.

In other words, if you want to use errno for error checking, then you have to reset errno to 0 before a function call and check it immediately after the function call.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I'm only confused about how that test was passing before.

It sounds like the tests passes because its not run with NODERAWFS today? i.e. ./tests/runner core2.test_utime does not set NODERAWFS. Perhaps we should annotate that test with also_with_noderawfs

var mtime = (seconds*1000) + (nanoseconds/(1000*1000));
if (!times) {
var atime = Date.now()/1000;
var mtime = atime;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems a little odd to declare var mtime and var atime in both branches of the if/else. Maybe just declare them in one? (I'm not a JS expert but IIRC you just need one var decl for a give variable it it will be hoisted to function level).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know any JS at all. :)

Choose a reason for hiding this comment

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

mtime and atime should be declared on level up (var mtime, atime;).
Otherwise the FS.utime(path, atime, mtime) will not be able to access the variables on the scope.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is that true? I thought var declaration were hoisted to the function level in JS. This seems to work just fine:

function foo() {                                                                 
  if (0) {                                                                          
    var bar = 10;                                                                   
  } else {                                                                       
    bar = 7;                                                                     
  }                                                                                                
  console.error(bar);                                                            
} 

It looks odd but its saves a few bytes in code size.

Choose a reason for hiding this comment

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

You are completely right! I got a bit confused with var and let :P

Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

lgtm % comments

@tiran
Copy link
Contributor Author

tiran commented Mar 9, 2022

Tests are failing.

The noderawfs layer defines the utime function as function() { fs.utimesSync.apply(void 0, arguments); }. According to https://nodejs.org/api/fs.html#fsutimessyncpath-atime-mtime and https://nodejs.org/api/fs.html#fsutimespath-atime-mtime-callback the utimesSync function accepts the time arguments as seconds, not milliseconds:

The atime and mtime arguments follow these rules:
Values can be either numbers representing Unix epoch time in seconds, Dates, or a numeric string like '123456789.0'.

Perhaps the values must be adjusted in the noderawfs layer instead?

@tiran
Copy link
Contributor Author

tiran commented Mar 10, 2022

Tests are no passing. I had to implement the same fix in wasmfs layer.

@tiran tiran requested a review from sbc100 March 10, 2022 14:04
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

lgtm! We can try to figure out why the missing errno = 0 was ok in the past but not any more as a followup.

mSeconds = aSeconds;
} else {
aSeconds = times[0].tv_sec;
mSeconds = times[1].tv_sec;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm curious how / why this was needed? Do we run test_utime under WASMFS? Or did you try running manually with this flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was needed to implement utime(path, NULL) for wasmfs. The PR fixes utime(path, times) on noderawfs and implements utime(path, NULL) for all fs layers.

test_utime was failing on test_core.wasmfs, https://app.circleci.com/pipelines/github/emscripten-core/emscripten/19754/workflows/57871d6d-c5f8-4f0c-83ae-2566038f9724/jobs/513149

Copy link
Collaborator

Choose a reason for hiding this comment

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

At thanks.. i had forgotten that we can run the whole of the core tests suite in wasmfs mode

@sbc100 sbc100 merged commit a7b10da into emscripten-core:main Mar 10, 2022
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.

NODERAWFS: utime, utimensat set wrong atime and mtime (overflow issue?)
3 participants