RFR(S): 8188122: Path length limits on Windows leads to obscure class loading failures

Thomas Stüfe thomas.stuefe at gmail.com
Thu Oct 26 06:54:47 UTC 2017


Hi Calvin,

this is a worthwhile addition, thank you for your work!

=========================

src/hotspot/os/windows/os_windows.cpp

Could you please use wchar_t instead of WCHAR?

---------------
in os::stat():

This cumbersome malloc/strcpy sequence:

!   size_t path_len = strlen(path) + 1;
+   char* pathbuf = (char*)os::malloc(path_len * sizeof(char), mtInternal);
+   if (pathbuf == NULL) {
+     errno = ENOMEM;
      return -1;
    }
    os::native_path(strcpy(pathbuf, path));

 can be reduced to a simple strdup:

char* pathbuf = os::strdup(path, mtInternal);
if (pathbuf == NULL) {
  errno = ENOMEM;
  return -1;
}
os::native_path(pathbuf);

This also would separate strcpy() from os::native_path() which is a bit
unreadable.

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

The single-byte path (strdup, ::stat()), together with its free(), can be
moved inside the (strlen(path) < MAX_PATH) condition. os::native_path will
not change the path length (it better not, as it operates on the input
buffer). That avoids  having two allocations on the doublebyte path.

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

But seeing that translation to UNC paths is something we might want more
often, I would combine allocation and UNC prefix adding to one function
like this, to avoid the memove and increase reusability:

// Creates an unc path from a single byte path. Return buffer is allocated
in C heap and needs to be freed by caller. Returns NULL on error.
static whchar_t* create_unc_path(const char* s) {
  - does s start with \\?\ ?
- yes:
            - os::malloc(strlen(s) + 1) and mbstowcs_s
        - no:
            - os::malloc(strlen(s) + 1 + 4), mbstowcs_s to fourth position
in string, prefix with L"\\?\"
}

We also need error checking to mbstowcs_s.

Just for cleanliness, I would then wrap deallocation into an own function.

static viud destroy_unc_path(whchar_t* s) { os::free(s); }

These two functions could be candidates of putting into os::win32
namespace, as this form of ANSI->UNC path translation is quite common -
whoever wants to use the xxxxW() functions must do this.

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

FindFirstFileW:

I am pretty sure that you can achieve the same result with
GetFileAttributesExW(). It also returns WIN32_FIND_DATAW.

It is way more straightforward to use than FindFirstFileW, as it does not
require you to write a callback hook.

-------

eval_find_data(): This is more of a generic helper function, could you
rename this to something clearer, e.g. make_double_word() ?

Also, setup_stat(), could this be renamed more clearly to something like
WIN32_FIND_DATA_to_stat? or lowercase if this bothers you :)

==================================
src/hotspot/share/classfile/classLoader.cpp

In ClassPathDirEntry::open_stream(), I would feel better if we were
asserting _dir and name to be != NULL before feeding it to strlen.

===================

Thanks!

Thomas






On Wed, Oct 25, 2017 at 9:48 PM, Calvin Cheung <calvin.cheung at oracle.com>
wrote:

> I've reworked this fix by using the Unicode version of open (wopen) to
> handle path name longer than max path with the path prefixed to indicate an
> extended length path as described in [1].
>
> The Unicode version of stat (wstat) doesn't work well with long path [2].
> So FindFirstFileW will be used.The data in WIN32_FIND_DATA returned from
> FindFirstFileW needs to be transferred to the stat structure since the
> caller expects a return stat structure and other platforms return a stat
> structure.
>
> In classLoader.cpp, calculate the size of buffer required instead of
> limiting it to JVM_MAXPATHLEN.
> In os_windows.cpp, dynamically allocate buffers in os::open and os::stat.
>
> updated webrev: http://cr.openjdk.java.net/~ccheung/8188122/webrev.01/
>
> It passed hs-tier2 testing using mach5.
>
> thanks,
> Calvin
>
> [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa3
> 65247(v=vs.85).aspx#MAX_PATH
> [2] https://social.msdn.microsoft.com/Forums/vstudio/en-US/3c093
> ea9-f0aa-446d-b648-2dabe8480430/stat-and-long-names?forum=vcgeneral
>
>
> On 10/16/17, 3:15 PM, Calvin Cheung wrote:
>
>> JBS: https://bugs.openjdk.java.net/browse/JDK-8188122
>>
>> Adding a warning message if the full path or the directory length exceeds
>> MAX_PATH on windows.
>>
>> Example warning messages.
>>
>> 1) The full path exceeds MAX_PATH:
>>
>> Java HotSpot(TM) 64-Bit Server VM warning: construct full path name
>> failed: total length 270 exceeds max length of 260
>>     dir T:\\testoutput\\jtreg\\JTwork\\classes\\2\\runtime\\LoadClas
>> s\\LongPath.d\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> length 259
>>     name Hello.class length 11
>>
>> 2) The directory path exceeds MAX_PATH:
>>
>> Java HotSpot(TM) 64-Bit Server VM warning: os::stat failed: path length
>> 265 exceeds max length 260
>>     path T:\\testoutput\\jtreg\\JTwork\\classes\\2\\runtime\\LoadClas
>> s\\LongPath.d\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> xxxxxxxxxxxxxxxxxxxxxxxxxxxx\\xxxxx
>>
>> webrev:
>>     http://cr.openjdk.java.net/~ccheung/8188122/webrev.00/
>>
>> Testing:
>>     JPRT (including the new test)
>>
>> thanks,
>> Calvin
>>
>


More information about the hotspot-runtime-dev mailing list