Skip to content
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

MinGW/MSVC Sys.rename cornercase regression #13166

Merged
merged 2 commits into from
May 17, 2024

Conversation

jmid
Copy link
Contributor

@jmid jmid commented May 14, 2024

Last year, #12184 and #12320 fixed two MinGW Sys.rename cornercases.
I found a third one which sadly flew under the radar:

# Sys.mkdir "sandbox\\eee" 0o755;;
- : unit = ()
# Sys.rename "sandbox" "sandbox\\eee";;
Exception: Sys_error "Invalid argument".
# Sys.file_exists "sandbox\\eee";;
- : bool = false

This happens only when the target is an empty child directory of the source, in which case

  • it fails as expected
  • but has the side effect of removing the target.

This is a consequence of the try-then-retry strategy of #12320.
Using PathIsPrefix to avoid retrying on a less-common error path does not seem too invasive IMHO.

@MisterDA
Copy link
Contributor

You should squash the last two commits (for bisecting it's better to have changes made to configure.ac reflected in configure in the same commit). You need to regenerate configure with Autoconf 2.71. If you have a later version installed, you may use this Docker invocation (courtesy of David):

docker run --rm -it -v $PWD:/home/opam/ocaml ocaml/opam:ubuntu-22.04-opam sh -c 'sudo apt install -y autoconf ; make -C ocaml configure'

@jmid jmid force-pushed the sys-rename-regfix branch 3 times, most recently from cb26ad1 to 32c188b Compare May 15, 2024 07:03
@jmid
Copy link
Contributor Author

jmid commented May 15, 2024

I've rerun tools/autogen with the proper autoconf version and squashed the commits as requested.
I also fixed an 80-column overflow and added a Changes entry, which required another rebasing.

@MisterDA
Copy link
Contributor

MisterDA commented May 15, 2024

  1. Do you know if PathIsPrefix does something smarter than a strcmp? or does it actually check the filesystem? The documentation doesn't tell much.
  2. The problem is not specific to mingw (by opposition to msvc), but rather to Windows, right?

@jmid
Copy link
Contributor Author

jmid commented May 15, 2024

  1. Do you know if PathIsPrefix does something smarter than a strcmp? or does it actually check the filesystem? The documentation doesn't tell much.

No, sorry, I don't know more than what's available in the above link.
I went with a Windows API call to keep things as simple as possible.

  1. The problem is not specific to mingw (by opposition to msvc), but rather to Windows, right?

Yep, this should also affect the restored MSVC port coming in 5.3.
Technically it is a regression against 5.1 and 5.2 with MinGW support.

@gasche gasche added portabilty Hardware and operating system support bug labels May 15, 2024
@gasche
Copy link
Member

gasche commented May 15, 2024

I'm prepared to approve on behalf of @MisterDA if/when that day comes.

@MisterDA
Copy link
Contributor

I also know that @shindere dislikes when we add failing tests in a commit, and then the fix for the commit: when we bisect and run the testsuite, the new failing test can be annoying to ignore for the person who's looking for another error. I either suggest you squash the patches, or the core-dev merging this PR squashes them.

I'm going to try this PR and convince myself, and report back.

@shindere
Copy link
Contributor

shindere commented May 15, 2024 via email

@shindere
Copy link
Contributor

shindere commented May 15, 2024 via email

@gasche
Copy link
Member

gasche commented May 15, 2024

when we bisect and run the testsuite, the new failing test can be annoying to ignore for the person who's looking for another error

My solution to this problem is to commit the erroneous reference output in the first version that exhibits the bug, with a comment in the test that explains that we observe/expect/record an incorrect output. Then the testsuite passes both before the fix and after the fix, and/but it is clear what the status is, and we can see the change in testsuite behavior in the commit that introduces the fix.

@shindere
Copy link
Contributor

shindere commented May 15, 2024 via email

@jmid jmid changed the title MinGW Sys.rename cornercase regression MinGW/MSVC Sys.rename cornercase regression May 15, 2024
@jmid
Copy link
Contributor Author

jmid commented May 15, 2024

I've updated the PR title.

I'm fine with squashing the commits at the end.

My editor initially added a final newline to testsuite/tests/lib-sys/rename.reference which caused the reference diff test to fail,
hence I removed it again to make the test pass.

Finally, the PR is only adding one library: shlwapi to configure.ac.
I however needed to add a newline to fit within the 80 column limit, so it may appear as a bigger change.

@shindere
Copy link
Contributor

shindere commented May 15, 2024 via email

@MisterDA
Copy link
Contributor

I looked at this and could reproduce the issue and the fix.
I'm however pretty sure that we never fixed any of the reported problems in Unix.rename! It's also never mentioned in the previous PRs. Unfortunately Unix.rename wasn't calling internaly rename_os but MoveFileEx still (unlike Unix.mkdir, for instance, which delegates its work to mkdir_os). I suggest we apply the following patch:

diff --git a/otherlibs/unix/rename_win32.c b/otherlibs/unix/rename_win32.c
index 453ecc1151..ff6421421f 100644
--- a/otherlibs/unix/rename_win32.c
+++ b/otherlibs/unix/rename_win32.c
@@ -30,9 +30,7 @@ CAMLprim value caml_unix_rename(value path1, value path2)
   caml_unix_check_path(path2, "rename");
   wpath1 = caml_stat_strdup_to_utf16(String_val(path1));
   wpath2 = caml_stat_strdup_to_utf16(String_val(path2));
-  ok = MoveFileEx(wpath1, wpath2,
-                  MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH |
-                  MOVEFILE_COPY_ALLOWED);
+  ok = rename_os(wpath1, wpath2);
   caml_stat_free(wpath1);
   caml_stat_free(wpath2);
   if (! ok) {   

If we're considering backporting the previous patches, I think this one could join the basket. I'll audit win32 code from libunix to see whether more functions can delegate their implementation to C code from the runtime.

@MisterDA
Copy link
Contributor

It's also interesting to fix libunix, considering that libraries such as Lwt often wrap libunix functions.

@jmid
Copy link
Contributor Author

jmid commented May 16, 2024

I completely agree about fixing the Unix library too to ensure better portability!
However, I think this is drifting from the PR's original purpose and better handled in a separate one.

(In fact I have a draft model test of some of the corresponding Unix functions that I intend to get back to, which did reveal similar rename differences 🙂 )

Fix a regression under MinGW+MSVC where Sys.rename of a parent directory
to an empty child directory fails as expected, but removes the target
as a side-effect. The fix introduces a dependency on 'shlwapi'.
Finally this adds a Sys.rename regression test.
@jmid
Copy link
Contributor Author

jmid commented May 16, 2024

I've squashed the commits as requested.

I can see the CI failing on MSVC due to #13174 - this failure is however unrelated (the separate commits were passing yesterday before the squash).

@jmid
Copy link
Contributor Author

jmid commented May 17, 2024

I added @dra27 as reviewer as he provided off-line feedback.
This was also an opportunity to kick off another CI run now that #13174 has been merged.
I expect the MSVC workflow to pass again.

@shindere
Copy link
Contributor

shindere commented May 17, 2024 via email

@jmid
Copy link
Contributor Author

jmid commented May 17, 2024

Wish: Squash the two commits into one.

Sure

Question: in the test, is there a reason to first do a print_string "Rename parent directory to empty child directory: "; then some work, and then the print_newline, rather that just using priint_endline?

That won't work, as the expected output is

Rename parent directory to empty child directory: fails as expected

Note the fails as expected part. We need the newline afterwards.
The PR is just doing what the previous testsuite/tests/lib-sys/rename.ml tests are already doing

@shindere
Copy link
Contributor

shindere commented May 17, 2024 via email

@shindere shindere merged commit f9a32a4 into ocaml:trunk May 17, 2024
15 checks passed
@jmid jmid deleted the sys-rename-regfix branch May 17, 2024 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug portabilty Hardware and operating system support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants