RFR: 8240197: Cannot start JVM when $JAVA_HOME includes CJK characters

Ioi Lam ioi.lam at oracle.com
Wed Mar 4 05:50:08 UTC 2020


Hi Yasumasa,

I think this function is getting too long and it's hard to figure out 
all the error conditions.

(I feel sorry for you because the code wasn't pretty messy to begin 
with, but I think it's at a point that we need to do the cleanup. It 
took me like 30 minutes to understand what is going on)

[0] I noticed you changed the return type to LPWSTR, but all the callers 
are using wchar_t*. Are these two types the same?

     If you want to use LPWSTR within this function for consistency, 
maybe you can return the value as

     return (wchar_t*)result; // LPWSTR and wchat_t* are the same type 
on Windows.

     That way people unfamiliar with Windows (most of us) won't be confused.

[1] I think the memory freeing can be done using a destructor, so you 
can simply return in case of error, without having a lot of "if" checks:

     class State {
        errno_t & err;
         char* buf;
         LPWSTR unicode_path;
LPWSTR result;

         State(errno_t & e) : buf(NULL), unicode_path(NULL), 
result(NULL), err(e) {
             err = SUCCESS;
          }
         ~State() {
           os::free(buf);
           os::free(unicode_path);
           if (err != ERROR_SUCCESS) {
              os::free(result);
           }
         }
         LPWSTR as_error(errno_t e) {
             err = e;
             return NULL;
         }
     } st;


     if ((st.buf = static_cast<char*>(os::malloc(buf_size, mtInternal))) 
== NULL) {
         return st.as_error(ENOMEM);
     }

     ....
     return st.result;

[2] Will it be possible to break the functon down into smaller pieces, 
so it's easier to understand what's going on?

E.g., Maybe the code that  converts the C string into a unicode string 
can be moved into a separate function?

   // Get required buffer size to convert to Unicode
   int unicode_path_len = MultiByteToWideChar(CP_THREAD_ACP,
                                              MB_ERR_INVALID_CHARS,
                                              buf, -1,
                                              NULL, 0);
   if (unicode_path_len == 0) {
     os::free(buf);
     err = EINVAL;
     return NULL;
   }

   ....

   LPWSTR unicode_path = static_cast<LPWSTR>(os::malloc(sizeof(WCHAR) * 
unicode_path_len, mtInternal));
   if (unicode_path == NULL) {
     err = ENOMEM;
   } else {
     // This call would be success because it is checked in above
     err = ERROR_SUCCESS;
     MultiByteToWideChar(CP_THREAD_ACP,
                         MB_ERR_INVALID_CHARS,
                         buf, -1,
                         unicode_path, unicode_path_len);



[3] size_t result_len = prefix_len - prefix_off + additional_space;

The variable name result_len is confusing. It's not the length of the 
result.

[4] The old copying code was already hard to understand, and the new 
version now has 2 versions of the copying code. I think the reason is 
you want to avoid an extra memcpy by calling GetFullPathNameW directly 
on the result.

     if (needs_fullpath) {
       // Get required buffer size to convert to full path
       DWORD full_path_len = GetFullPathNameW(unicode_path, 0, NULL, NULL);
       if (full_path_len == 0) {
         err = EINVAL;
       } else {
         size_t result_size = sizeof(WCHAR) * (result_len + full_path_len);
         result = static_cast<LPWSTR>(os::malloc(result_size, mtInternal));
         if (result == NULL) {
           err = ENOMEM;
         } else {
           // This call would be success because it is checked in above
           GetFullPathNameW(unicode_path, full_path_len, result + 
prefix_len - prefix_off, NULL);
           // Copy prefix
           memcpy(result, prefix, sizeof(WCHAR) * prefix_len);
         }
       }
     } else {
       size_t result_size = sizeof(WCHAR) * (result_len + unicode_path_len);
       result = static_cast<LPWSTR>(os::malloc(result_size, mtInternal));
       if (result == NULL) {
         err = ENOMEM;
       } else {
         // Copy unicode path
         memcpy(result + prefix_len - prefix_off, unicode_path, 
sizeof(WCHAR) * unicode_path_len);
         // Copy prefix
         memcpy(result, prefix, sizeof(WCHAR) * prefix_len);
       }
     }

I think the code can be simplified if you do the fullpath version in a 
separate function:

     if (needs_fullpath) {
        unicode_path = to_full_path(unicode_path, err, &unicode_path_len);
     }

     size_t result_size = ......

This will do one more memcpy, but I think it's not performance critical

Thanks
- Ioi


On 3/3/20 4:19 PM, Yasumasa Suenaga wrote:
> Thanks Ralf!
> I fixed them.
>
> I need a Reviewer to push, so I uploaded new webrev:
>
>   http://cr.openjdk.java.net/~ysuenaga/JDK-8240197/webrev.03/
>
>
> Yasumasa
>
>
> On 2020/03/03 23:25, Schmelter, Ralf wrote:
>> Hi Yasumasa,
>>
>> thanks for your work. The code should now be able to handle any path.
>>
>> Two small changes (no new webrev needed):
>>
>> size_t result_len = prefix_len + prefix_off + additional_space
>> should be
>> size_t result_len = prefix_len - prefix_off + additional_space
>>
>> And you should copy the prefix after you copied the filename, since 
>> sometimes the prefix is required to overwrite the start of the filename:
>>
>> // This call would be success because it is checked in above
>> GetFullPathNameW(unicode_path, full_path_len, result + prefix_len - 
>> prefix_off, NULL);
>> // Copy prefix
>> memcpy(result, prefix, sizeof(WCHAR) * prefix_len);
>>
>> and
>>
>> // Copy unicode path
>> memcpy(result + prefix_len - prefix_off, unicode_path, sizeof(WCHAR) 
>> * unicode_path_len);
>> // Copy prefix
>> memcpy(result, prefix, sizeof(WCHAR) * prefix_len);
>>
>> With these changes the os_windows gtest and the appcds jtreg tests 
>> run without errors.
>>
>> Best regards,
>> Ralf
>>



More information about the hotspot-runtime-dev mailing list