Skip to content

Commit ed45bde

Browse files
author
Adam Farley
committed
8227021: VM fails if any sun.boot.library.path paths are longer than JVM_MAXPATHLEN
The size of each path in sun.boot.library.path property should not exceed JVM_MAXPATHLEN Reviewed-by: dholmes, coleenp, sspitsyn
1 parent 6e3a246 commit ed45bde

File tree

3 files changed

+105
-30
lines changed

3 files changed

+105
-30
lines changed

src/hotspot/share/runtime/os.cpp

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,19 @@ static bool conc_path_file_and_check(char *buffer, char *printbuffer, size_t pri
279279
return false;
280280
}
281281

282+
// Frees all memory allocated on the heap for the
283+
// supplied array of arrays of chars (a), where n
284+
// is the number of elements in the array.
285+
static void free_array_of_char_arrays(char** a, size_t n) {
286+
while (n > 0) {
287+
n--;
288+
if (a[n] != NULL) {
289+
FREE_C_HEAP_ARRAY(char, a[n]);
290+
}
291+
}
292+
FREE_C_HEAP_ARRAY(char*, a);
293+
}
294+
282295
bool os::dll_locate_lib(char *buffer, size_t buflen,
283296
const char* pname, const char* fname) {
284297
bool retval = false;
@@ -299,10 +312,10 @@ bool os::dll_locate_lib(char *buffer, size_t buflen,
299312
}
300313
} else if (strchr(pname, *os::path_separator()) != NULL) {
301314
// A list of paths. Search for the path that contains the library.
302-
int n;
303-
char** pelements = split_path(pname, &n);
315+
size_t n;
316+
char** pelements = split_path(pname, &n, fullfnamelen);
304317
if (pelements != NULL) {
305-
for (int i = 0; i < n; i++) {
318+
for (size_t i = 0; i < n; i++) {
306319
char* path = pelements[i];
307320
// Really shouldn't be NULL, but check can't hurt.
308321
size_t plen = (path == NULL) ? 0 : strlen(path);
@@ -314,12 +327,7 @@ bool os::dll_locate_lib(char *buffer, size_t buflen,
314327
if (retval) break;
315328
}
316329
// Release the storage allocated by split_path.
317-
for (int i = 0; i < n; i++) {
318-
if (pelements[i] != NULL) {
319-
FREE_C_HEAP_ARRAY(char, pelements[i]);
320-
}
321-
}
322-
FREE_C_HEAP_ARRAY(char*, pelements);
330+
free_array_of_char_arrays(pelements, n);
323331
}
324332
} else {
325333
// A definite path.
@@ -1335,17 +1343,22 @@ bool os::set_boot_path(char fileSep, char pathSep) {
13351343
return false;
13361344
}
13371345

1338-
/*
1339-
* Splits a path, based on its separator, the number of
1340-
* elements is returned back in n.
1341-
* It is the callers responsibility to:
1342-
* a> check the value of n, and n may be 0.
1343-
* b> ignore any empty path elements
1344-
* c> free up the data.
1345-
*/
1346-
char** os::split_path(const char* path, int* n) {
1347-
*n = 0;
1348-
if (path == NULL || strlen(path) == 0) {
1346+
// Splits a path, based on its separator, the number of
1347+
// elements is returned back in "elements".
1348+
// file_name_length is used as a modifier for each path's
1349+
// length when compared to JVM_MAXPATHLEN. So if you know
1350+
// each returned path will have something appended when
1351+
// in use, you can pass the length of that in
1352+
// file_name_length, to ensure we detect if any path
1353+
// exceeds the maximum path length once prepended onto
1354+
// the sub-path/file name.
1355+
// It is the callers responsibility to:
1356+
// a> check the value of "elements", which may be 0.
1357+
// b> ignore any empty path elements
1358+
// c> free up the data.
1359+
char** os::split_path(const char* path, size_t* elements, size_t file_name_length) {
1360+
*elements = (size_t)0;
1361+
if (path == NULL || strlen(path) == 0 || file_name_length == (size_t)NULL) {
13491362
return NULL;
13501363
}
13511364
const char psepchar = *os::path_separator();
@@ -1354,7 +1367,7 @@ char** os::split_path(const char* path, int* n) {
13541367
return NULL;
13551368
}
13561369
strcpy(inpath, path);
1357-
int count = 1;
1370+
size_t count = 1;
13581371
char* p = strchr(inpath, psepchar);
13591372
// Get a count of elements to allocate memory
13601373
while (p != NULL) {
@@ -1363,20 +1376,23 @@ char** os::split_path(const char* path, int* n) {
13631376
p = strchr(p, psepchar);
13641377
}
13651378
char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count, mtInternal);
1366-
if (opath == NULL) {
1367-
return NULL;
1368-
}
13691379

13701380
// do the actual splitting
13711381
p = inpath;
1372-
for (int i = 0 ; i < count ; i++) {
1382+
for (size_t i = 0 ; i < count ; i++) {
13731383
size_t len = strcspn(p, os::path_separator());
1374-
if (len > JVM_MAXPATHLEN) {
1375-
return NULL;
1384+
if (len + file_name_length > JVM_MAXPATHLEN) {
1385+
// release allocated storage before exiting the vm
1386+
free_array_of_char_arrays(opath, i++);
1387+
vm_exit_during_initialization("The VM tried to use a path that exceeds the maximum path length for "
1388+
"this system. Review path-containing parameters and properties, such as "
1389+
"sun.boot.library.path, to identify potential sources for this path.");
13761390
}
13771391
// allocate the string and add terminator storage
1378-
char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
1392+
char* s = (char*)NEW_C_HEAP_ARRAY_RETURN_NULL(char, len + 1, mtInternal);
13791393
if (s == NULL) {
1394+
// release allocated storage before returning null
1395+
free_array_of_char_arrays(opath, i++);
13801396
return NULL;
13811397
}
13821398
strncpy(s, p, len);
@@ -1385,7 +1401,7 @@ char** os::split_path(const char* path, int* n) {
13851401
p += len + 1;
13861402
}
13871403
FREE_C_HEAP_ARRAY(char, inpath);
1388-
*n = count;
1404+
*elements = count;
13891405
return opath;
13901406
}
13911407

src/hotspot/share/runtime/os.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ class os: AllStatic {
821821
// Amount beyond the callee frame size that we bang the stack.
822822
static int extra_bang_size_in_bytes();
823823

824-
static char** split_path(const char* path, int* n);
824+
static char** split_path(const char* path, size_t* elements, size_t file_name_length);
825825

826826
// support for mapping non-volatile memory using MAP_SYNC
827827
static bool supports_map_sync();
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test TestSunBootLibraryPath.java
26+
* @bug 8227021
27+
* @summary Confirm using too-long paths in sun.boot.library.path causes failure and useful error message.
28+
* @author afarley
29+
* @library /test/lib
30+
* @build jdk.test.lib.process.ProcessTools
31+
* @run driver TestSunBootLibraryPath
32+
*/
33+
34+
import jdk.test.lib.process.ProcessTools;
35+
36+
public class TestSunBootLibraryPath {
37+
static String expectedErrorMessage = "The VM tried to use a path that exceeds the maximum path length for this system.";
38+
39+
public static void main(String[] args) throws Exception {
40+
// Allows us to re-use this class as a do-nothing test class simply by passing a "Do-Nothing" argument.
41+
if (args.length == 0) {
42+
// Grab any path.
43+
String tooLongPath = System.getProperty("sun.boot.library.path");
44+
// Add enough characters to make it "too long".
45+
tooLongPath += "a".repeat(5000);
46+
// Start a java process with this property set, and check that:
47+
// 1) The process failed and
48+
// 2) The error message was correct.
49+
ProcessTools.executeTestJvm("-Dsun.boot.library.path=" + tooLongPath,
50+
"TestSunBootLibraryPath",
51+
"'Do-Nothing'")
52+
.shouldNotHaveExitValue(0)
53+
.stdoutShouldContain(expectedErrorMessage);
54+
} else if (!args[0].equals("Do-Nothing")) {
55+
// Fail, to prevent accidental args from causing accidental test passing.
56+
throw new IllegalArgumentException("Test was launched with an invalid argument.");
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)