RFR: 8350869: os::stat doesn't follow symlinks on Windows

David Holmes dholmes at openjdk.org
Thu May 15 08:52:56 UTC 2025


On Wed, 14 May 2025 14:54:48 GMT, Anton Artemov <duke at openjdk.org> wrote:

> This PR addresses an issue on Windows, where a class file could not be loaded by a symbolic link. 
> 
> I added a check if a wide path is a symbolic link (soft one) and a method for dereferencing. Both os::stat() and os::open() on Windows now can handle such links.
> 
> Tested in tiers 1-3. A separate test added.

I've taken a first pass through this - disclaimer I don't know these Windows API's nor in general how to deal with symlinks. I have a lot of style issues that need correcting, but also an issue with error handling.

Thanks.

src/hotspot/os/windows/os_windows.cpp line 4614:

> 4612: 
> 4613: // This method checks if a wide path is actually a symbolic link
> 4614: static bool is_symbolic_link(const wchar_t* wide_path)

This is a `bool` function but you also set `errno` upon errors - how will anyone know that an error occurred?

src/hotspot/os/windows/os_windows.cpp line 4615:

> 4613: // This method checks if a wide path is actually a symbolic link
> 4614: static bool is_symbolic_link(const wchar_t* wide_path)
> 4615: {

Suggestion:

static bool is_symbolic_link(const wchar_t* wide_path) {

Hotspot-style says the { goes on the same line as the function declaration.

src/hotspot/os/windows/os_windows.cpp line 4619:

> 4617:   HANDLE f = ::FindFirstFileW(wide_path, &fd);
> 4618:   const bool result = fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fd.dwReserved0 == IO_REPARSE_TAG_SYMLINK;
> 4619:   if (0 == ::FindClose(f)) {

```style-nit suggestion
  if (::FindClose(f) == 0) {

src/hotspot/os/windows/os_windows.cpp line 4620:

> 4618:   const bool result = fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fd.dwReserved0 == IO_REPARSE_TAG_SYMLINK;
> 4619:   if (0 == ::FindClose(f)) {
> 4620:     errno = ::GetLastError();

I had not noticed this kind of error handling before. It is not obvious that `errno` is able to accept all the values `GetLastError` may report - or perhaps more accurately that anyone checking `errno` would expect to see them.

https://learn.microsoft.com/en-us/cpp/c-runtime-library/errno-constants?view=msvc-170

src/hotspot/os/windows/os_windows.cpp line 4628:

> 4626: // This method dereferences a symbolic link
> 4627: static WCHAR* get_path_to_target(const wchar_t* wide_path)
> 4628: {

Suggestion:

static WCHAR* get_path_to_target(const wchar_t* wide_path) {

src/hotspot/os/windows/os_windows.cpp line 4632:

> 4630: 
> 4631:   hFile = CreateFileW(wide_path, GENERIC_READ, FILE_SHARE_READ, nullptr,
> 4632:     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);

Suggestion:

  HANDLE hFile = CreateFileW(wide_path, GENERIC_READ, FILE_SHARE_READ, nullptr,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);

src/hotspot/os/windows/os_windows.cpp line 4638:

> 4636: 
> 4637:   if (target_path_size == 0)
> 4638:   {

Suggestion:

  if (target_path_size == 0) {

test/hotspot/jtreg/runtime/LoadClass/TestSymlinkLoad.java line 68:

> 66:         OutputAnalyzer output = new OutputAnalyzer(pb.start());
> 67:         output.shouldContain("Hello World")
> 68:                 .shouldHaveExitValue(0);

Suggestion:

        output.shouldContain("Hello World")
              .shouldHaveExitValue(0);

test/hotspot/jtreg/runtime/LoadClass/TestSymlinkLoad.java line 81:

> 79:         output = new OutputAnalyzer(pb.start());
> 80:         output.shouldContain("Hello World")
> 81:                 .shouldHaveExitValue(0);

Suggestion:

        output.shouldContain("Hello World")
              .shouldHaveExitValue(0);

test/hotspot/jtreg/runtime/LoadClass/TestSymlinkLoad.java line 89:

> 87:     public static void createLinkInSeparateFolder( final String pathToFolderForSymlink, final Path target, final String className) throws IOException {
> 88:         File theDir = new File(pathToFolderForSymlink);
> 89:         if (!theDir.exists()){

Suggestion:

        if (!theDir.exists()) {

-------------

Changes requested by dholmes (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/25233#pullrequestreview-2842618311
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090632317
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090522324
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090510941
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090628885
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090523005
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090518969
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090520141
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090527145
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090536089
PR Review Comment: https://git.openjdk.org/jdk/pull/25233#discussion_r2090536587


More information about the hotspot-runtime-dev mailing list