Mercurial > hg > graal-compiler
changeset 20789:6bed0ca7a09a
Merge
author | asaha |
---|---|
date | Wed, 17 Dec 2014 12:48:26 -0800 |
parents | c4f1e23c4139 (diff) c3933f52eeb3 (current diff) |
children | 076f441aa9b7 eff80b90c3ad |
files | .hgtags make/hotspot_version |
diffstat | 33 files changed, 1173 insertions(+), 393 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Wed Dec 17 10:43:38 2014 -0800 +++ b/.hgtags Wed Dec 17 12:48:26 2014 -0800 @@ -501,6 +501,8 @@ 00cf2b6f51b9560b01030e8f4c28c466f0b21fe3 hs25.20-b23 19408d5fd31c25ce60c43dd33e92b96e8df4a4ea jdk8u20-b25 eaa4074a7e3975cd33ec55e6b584586e2ac681bd jdk8u20-b26 +7c9925f21c2529a88eb64b8039cc080f60b85e01 jdk8u20-b31 +7edb04063a423e278fe34a0006d25fee198f495e jdk8u20-b32 4828415ebbf11e205dcc08e97ad5ae7dd03522f9 jdk8u40-b00 d952af8cf67dd1e7ab5fec9a299c6c6dafd1863e hs25.40-b01 f0afba33c928ddaa2d5f003b90d683c143f78ea3 hs25.40-b02 @@ -544,6 +546,20 @@ 6467bdd4d22d8b140844dc847c43b9ba7cb0bbd1 jdk8u25-b16 28b50d07f6f8c5a567b6a25e95a423948114a004 jdk8u25-b17 639abc668bfe995dba811dd35411b9ea8a9041cd jdk8u25-b18 +c3528699fb33fe3eb1d117504184ae7ab2507aa1 jdk8u25-b31 +5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00 +5bb686ae3b89f8aa1c74331b2d24e2a5ebd43448 jdk8u31-b01 +087678da96603c9705b38b6cc4a6569ac7b4420a jdk8u31-b02 +401cbaa475b4efe53153119ab87a82b217980a7f jdk8u31-b03 +060cdf93040c1bfa5fdf580da5e9999042632cc8 jdk8u31-b04 +6e56d7f1634f6c4cd4196e699c06e6ca2e6d6efb jdk8u31-b05 +271a32147391d08b0f338d9353330e2b5584d580 jdk8u31-b06 +e9f815c3f21cf2febd8e3c185917c1519aa52d9a jdk8u31-b07 +cc74ca22516644867be3b8db6c1f8d05ab4f6c27 jdk8u31-b08 +245d29ed5db5ad6914eb0c9fe78b9ba26122c478 jdk8u31-b09 +d7b6bdd51abe68b16411d5b292fb830a43c5bc09 jdk8u31-b10 +9906d432d6dbd2cda242e3f3cfde7cf6c90245bf jdk8u31-b11 +e13839545238d1ecf17f0489bb6fb765de46719a jdk8u31-b12 1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11
--- a/make/hotspot_version Wed Dec 17 10:43:38 2014 -0800 +++ b/make/hotspot_version Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2014 +HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 HS_MINOR_VER=40
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -197,7 +197,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,27 +242,185 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -317,9 +506,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,25 +535,14 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); continue; } - // Since we don't create the backing store files in directories - // pointed to by symbolic links, we also don't follow them when - // looking for the files. We check for a symbolic link after the - // call to opendir in order to eliminate a small window where the - // symlink can be exploited. - // - if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); - os::closedir(subdirp); - continue; - } - struct dirent* udentry; char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); errno = 0; @@ -465,26 +645,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,16 +656,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -519,6 +674,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,7 +685,7 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -552,11 +708,14 @@ if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -613,19 +772,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -683,8 +877,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -716,13 +917,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -837,12 +1046,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/os/linux/vm/perfMemory_linux.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/os/linux/vm/perfMemory_linux.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -197,7 +197,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -211,22 +242,180 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirfd(dirp))) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirfd(dirp); + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } @@ -317,9 +506,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -344,7 +535,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); @@ -465,26 +657,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -496,16 +668,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -519,6 +686,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -527,9 +695,8 @@ if (pid == 0) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -551,12 +718,14 @@ // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -613,19 +782,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -683,8 +887,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -715,6 +926,13 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); @@ -722,7 +940,7 @@ assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -837,12 +1055,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -199,7 +199,38 @@ } -// check if the given path is considered a secure directory for +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +// +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + // + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + // + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + // + return false; + } + return true; +} + + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. @@ -213,27 +244,185 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + + +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +// +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { + return false; + } + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +// +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; +} + + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +// +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +// +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +// +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - // return the user name for the given user id // // the caller is expected to free the allocated memory. @@ -308,9 +497,11 @@ const char* tmpdirname = os::get_temp_directory(); + // open the temp directory DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { + // Cannot open the directory to get the user name, return. return NULL; } @@ -335,7 +526,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // open the user directory + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); @@ -504,26 +696,6 @@ } -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path, mtInternal); -} - - // cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in @@ -535,16 +707,11 @@ // static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // open the directory + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup - return; - } - - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory + // directory doesn't exist or is insecure, so there is nothing to cleanup return; } @@ -558,6 +725,7 @@ // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -568,7 +736,7 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; @@ -591,11 +759,14 @@ if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); + + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } @@ -652,19 +823,54 @@ return -1; } - int result; + int saved_cwd_fd; + // open the directory and set the current working directory to it + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // close the directory and reset the current working directory + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // truncate the file to get rid of any existing data + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -700,8 +906,15 @@ THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } + int fd = result; - return result; + // check to see if the file is secure + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -733,13 +946,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // get the short filename + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name, mtInternal); FREE_C_HEAP_ARRAY(char, dirname, mtInternal); @@ -855,12 +1076,12 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; - file_flags = O_RDONLY; + file_flags = O_RDONLY | O_NOFOLLOW; } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode");
--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -89,8 +89,8 @@ public: ArgumentMap *_vars; ArgumentMap *_stack; - short _stack_height; - short _max_stack; + int _stack_height; + int _max_stack; bool _initialized; ArgumentMap empty_map;
--- a/src/share/vm/classfile/systemDictionary.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -1907,11 +1907,12 @@ InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass)); - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK); InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); + InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER); // JSR 292 classes WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
--- a/src/share/vm/classfile/systemDictionary.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -128,6 +128,7 @@ do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \ do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \ do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \ + do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \ do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \ \ do_klass(Thread_klass, java_lang_Thread, Pre ) \
--- a/src/share/vm/classfile/verifier.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/classfile/verifier.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -1553,14 +1553,14 @@ case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokeinterface : case Bytecodes::_invokedynamic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_new : { @@ -2408,8 +2408,9 @@ void ClassVerifier::verify_invoke_init( RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool *this_uninit, - constantPoolHandle cp, TRAPS) { + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS) { u2 bci = bcs->bci(); VerificationType type = current_frame->pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); @@ -2425,28 +2426,36 @@ return; } - // Check if this call is done from inside of a TRY block. If so, make - // sure that all catch clause paths end in a throw. Otherwise, this - // can result in returning an incomplete object. - ExceptionTable exhandlers(_method()); - int exlength = exhandlers.length(); - for(int i = 0; i < exlength; i++) { - u2 start_pc = exhandlers.start_pc(i); - u2 end_pc = exhandlers.end_pc(i); + // If this invokespecial call is done from inside of a TRY block then make + // sure that all catch clause paths end in a throw. Otherwise, this can + // result in returning an incomplete object. + if (in_try_block) { + ExceptionTable exhandlers(_method()); + int exlength = exhandlers.length(); + for(int i = 0; i < exlength; i++) { + u2 start_pc = exhandlers.start_pc(i); + u2 end_pc = exhandlers.end_pc(i); - if (bci >= start_pc && bci < end_pc) { - if (!ends_in_athrow(exhandlers.handler_pc(i))) { - verify_error(ErrorContext::bad_code(bci), - "Bad <init> method call from after the start of a try block"); - return; - } else if (VerboseVerification) { - ResourceMark rm; - tty->print_cr( - "Survived call to ends_in_athrow(): %s", - current_class()->name()->as_C_string()); + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad <init> method call from after the start of a try block"); + return; + } else if (VerboseVerification) { + ResourceMark rm; + tty->print_cr( + "Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); + } } } - } + + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + verify_exception_handler_targets(bci, true, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } // in_try_block current_frame->initialize_object(type, current_type()); *this_uninit = true; @@ -2500,6 +2509,13 @@ } } } + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + if (in_try_block) { + verify_exception_handler_targets(bci, *this_uninit, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } current_frame->initialize_object(type, new_class_type); } else { verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), @@ -2528,8 +2544,8 @@ void ClassVerifier::verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool *this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS) { + bool in_try_block, bool *this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { // Make sure the constant pool item is the right type u2 index = bcs->get_index_u2(); Bytecodes::Code opcode = bcs->raw_code(); @@ -2699,7 +2715,8 @@ opcode != Bytecodes::_invokedynamic) { if (method_name == vmSymbols::object_initializer_name()) { // <init> method verify_invoke_init(bcs, index, ref_class_type, current_frame, - code_length, this_uninit, cp, CHECK_VERIFY(this)); + code_length, in_try_block, this_uninit, cp, stackmap_table, + CHECK_VERIFY(this)); } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) {
--- a/src/share/vm/classfile/verifier.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/classfile/verifier.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -301,8 +301,9 @@ void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, - constantPoolHandle cp, TRAPS); + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS); // Used by ends_in_athrow() to push all handlers that contain bci onto // the handler_stack, if the handler is not already on the stack. @@ -316,8 +317,8 @@ void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool* this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS); + bool in_try_block, bool* this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,
--- a/src/share/vm/classfile/vmSymbols.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -79,6 +79,7 @@ template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \ template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \ template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \ + template(sun_misc_Cleaner, "sun/misc/Cleaner") \ template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \ template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \ template(java_lang_reflect_Method, "java/lang/reflect/Method") \
--- a/src/share/vm/code/dependencies.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/code/dependencies.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -560,7 +560,7 @@ put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value()); } else if (arg.is_method()) { what = "method "; - put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value()); + put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value(), NULL); } else if (arg.is_klass()) { what = "class "; } else { @@ -845,8 +845,8 @@ // Static methods don't override non-static so punt return true; } - if ( !Dependencies::is_concrete_method(lm) - && !Dependencies::is_concrete_method(m) + if ( !Dependencies::is_concrete_method(lm, k) + && !Dependencies::is_concrete_method(m, ctxk) && lm->method_holder()->is_subtype_of(m->method_holder())) // Method m is overridden by lm, but both are non-concrete. return true; @@ -882,8 +882,17 @@ } else if (!k->oop_is_instance()) { return false; // no methods to find in an array type } else { - Method* m = InstanceKlass::cast(k)->find_method(_name, _signature); - if (m == NULL || !Dependencies::is_concrete_method(m)) return false; + // Search class hierarchy first. + Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature); + if (!Dependencies::is_concrete_method(m, k)) { + // Check interface defaults also, if any exist. + Array<Method*>* default_methods = InstanceKlass::cast(k)->default_methods(); + if (default_methods == NULL) + return false; + m = InstanceKlass::cast(k)->find_method(default_methods, _name, _signature); + if (!Dependencies::is_concrete_method(m, NULL)) + return false; + } _found_methods[_num_participants] = m; // Note: If add_participant(k) is called, // the method m will already be memoized for it. @@ -1176,15 +1185,17 @@ return true; } -bool Dependencies::is_concrete_method(Method* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - // Default methods are considered "concrete" as well. - return !m->is_abstract() && - !m->is_overpass(); // error functions aren't concrete +bool Dependencies::is_concrete_method(Method* m, Klass * k) { + // NULL is not a concrete method, + // statics are irrelevant to virtual call sites, + // abstract methods are not concrete, + // overpass (error) methods are not concrete if k is abstract + // + // note "true" is conservative answer -- + // overpass clause is false if k == NULL, implies return true if + // answer depends on overpass clause. + return ! ( m == NULL || m -> is_static() || m -> is_abstract() || + m->is_overpass() && k != NULL && k -> is_abstract() ); } @@ -1209,16 +1220,6 @@ return true; } -bool Dependencies::is_concrete_method(ciMethod* m) { - // Statics are irrelevant to virtual call sites. - if (m->is_static()) return false; - - // We could also return false if m does not yet appear to be - // executed, if the VM version supports this distinction also. - return !m->is_abstract(); -} - - bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) { return k->has_finalizable_subclass(); } @@ -1432,7 +1433,7 @@ Klass* wit = wf.find_witness_definer(ctxk); if (wit != NULL) return NULL; // Too many witnesses. Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0. - if (Dependencies::is_concrete_method(m)) { + if (Dependencies::is_concrete_method(m, ctxk)) { if (fm == NULL) { // It turns out that m was always the only implementation. fm = m; @@ -1462,61 +1463,6 @@ return wf.find_witness_definer(ctxk, changes); } -// Find the set of all non-abstract methods under ctxk that match m[0]. -// (The method m[0] must be defined or inherited in ctxk.) -// Include m itself in the set, unless it is abstract. -// Fill the given array m[0..(mlen-1)] with this set, and return the length. -// (The length may be zero if no concrete methods are found anywhere.) -// If there are too many concrete methods to fit in marray, return -1. -int Dependencies::find_exclusive_concrete_methods(Klass* ctxk, - int mlen, - Method* marray[]) { - Method* m0 = marray[0]; - ClassHierarchyWalker wf(m0); - assert(wf.check_method_context(ctxk, m0), "proper context"); - wf.record_witnesses(mlen); - bool participants_hide_witnesses = true; - Klass* wit = wf.find_witness_definer(ctxk); - if (wit != NULL) return -1; // Too many witnesses. - int num = wf.num_participants(); - assert(num <= mlen, "oob"); - // Keep track of whether m is also part of the result set. - int mfill = 0; - assert(marray[mfill] == m0, "sanity"); - if (Dependencies::is_concrete_method(m0)) - mfill++; // keep m0 as marray[0], the first result - for (int i = 0; i < num; i++) { - Method* fm = wf.found_method(i); - if (fm == m0) continue; // Already put this guy in the list. - if (mfill == mlen) { - return -1; // Oops. Too many methods after all! - } - marray[mfill++] = fm; - } -#ifndef PRODUCT - // Make sure the dependency mechanism will pass this discovery: - if (VerifyDependencies) { - // Turn off dependency tracing while actually testing deps. - FlagSetting fs(TraceDependencies, false); - switch (mfill) { - case 1: - guarantee(NULL == (void *)check_unique_concrete_method(ctxk, marray[0]), - "verify dep."); - break; - case 2: - guarantee(NULL == (void *) - check_exclusive_concrete_methods(ctxk, marray[0], marray[1]), - "verify dep."); - break; - default: - ShouldNotReachHere(); // mlen > 2 yet supported - } - } -#endif //PRODUCT - return mfill; -} - - Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) { Klass* search_at = ctxk; if (changes != NULL) @@ -1524,7 +1470,6 @@ return find_finalizable_subclass(search_at); } - Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
--- a/src/share/vm/code/dependencies.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/code/dependencies.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,7 +287,7 @@ // In that case, there would be a middle ground between concrete // and abstract (as defined by the Java language and VM). static bool is_concrete_klass(Klass* k); // k is instantiable - static bool is_concrete_method(Method* m); // m is invocable + static bool is_concrete_method(Method* m, Klass* k); // m is invocable static Klass* find_finalizable_subclass(Klass* k); // These versions of the concreteness queries work through the CI. @@ -301,7 +301,6 @@ // not go back into the VM to get their value; they must cache the // bit in the CI, either eagerly or lazily.) static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable - static bool is_concrete_method(ciMethod* m); // m appears invocable static bool has_finalizable_subclass(ciInstanceKlass* k); // As a general rule, it is OK to compile under the assumption that @@ -348,7 +347,6 @@ static Klass* find_unique_concrete_subtype(Klass* ctxk); static Method* find_unique_concrete_method(Klass* ctxk, Method* m); static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]); - static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]); // Create the encoding which will be stored in an nmethod. void encode_content_bytes();
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -738,7 +738,7 @@ // Support for parallelizing survivor space rescan if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) { const size_t max_plab_samples = - ((DefNewGeneration*)_young_gen)->max_survivor_size()/MinTLABSize; + ((DefNewGeneration*)_young_gen)->max_survivor_size() / plab_sample_minimum_size(); _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC); @@ -796,6 +796,12 @@ _inter_sweep_timer.start(); // start of time } +size_t CMSCollector::plab_sample_minimum_size() { + // The default value of MinTLABSize is 2k, but there is + // no way to get the default value if the flag has been overridden. + return MAX2(ThreadLocalAllocBuffer::min_size() * HeapWordSize, 2 * K); +} + const char* ConcurrentMarkSweepGeneration::name() const { return "concurrent mark-sweep generation"; }
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -764,6 +764,10 @@ size_t* _cursor; ChunkArray* _survivor_plab_array; + // A bounded minimum size of PLABs, should not return too small values since + // this will affect the size of the data structures used for parallel young gen rescan + size_t plab_sample_minimum_size(); + // Support for marking stack overflow handling bool take_from_overflow_list(size_t num, CMSMarkStack* to_stack); bool par_take_from_overflow_list(size_t num,
--- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,13 @@ // active field set to true. PtrQueue(qset_, perm, true /* active */) { } + // Flush before destroying; queue may be used to capture pending work while + // doing something else, with auto-flush on completion. + ~DirtyCardQueue() { if (!is_permanent()) flush(); } + + // Process queue entries and release resources. + void flush() { flush_impl(); } + // Apply the closure to all elements, and reset the index to make the // buffer empty. If a closure application returns "false", return // "false" immediately, halting the iteration. If "consume" is true,
--- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,15 @@ #include "runtime/thread.inline.hpp" PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) : - _qset(qset), _buf(NULL), _index(0), _active(active), + _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _perm(perm), _lock(NULL) {} -void PtrQueue::flush() { +PtrQueue::~PtrQueue() { + assert(_perm || (_buf == NULL), "queue must be flushed before delete"); +} + +void PtrQueue::flush_impl() { if (!_perm && _buf != NULL) { if (_index == _sz) { // No work to do.
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,15 +65,18 @@ Mutex* _lock; PtrQueueSet* qset() { return _qset; } + bool is_permanent() const { return _perm; } + + // Process queue entries and release resources, if not permanent. + void flush_impl(); public: // Initialize this queue to contain a null buffer, and be part of the // given PtrQueueSet. PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false); - // Release any contained resources. - virtual void flush(); - // Calls flush() when destroyed. - ~PtrQueue() { flush(); } + + // Requires queue flushed or permanent. + ~PtrQueue(); // Associate a lock with a ptr queue. void set_lock(Mutex* lock) { _lock = lock; }
--- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -39,7 +39,7 @@ // first before we flush it, otherwise we might end up with an // enqueued buffer with refs into the CSet which breaks our invariants. filter(); - PtrQueue::flush(); + flush_impl(); } // This method removes entries from an SATB buffer that will not be
--- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,8 @@ // field to true. This is done in JavaThread::initialize_queues(). PtrQueue(qset, perm, false /* active */) { } - // Overrides PtrQueue::flush() so that it can filter the buffer - // before it is flushed. - virtual void flush(); + // Process queue entries and free resources. + void flush(); // Overrides PtrQueue::should_enqueue_buffer(). See the method's // definition for more information.
--- a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -63,7 +63,8 @@ virtual ~ParGCAllocBuffer() {} static const size_t min_size() { - return ThreadLocalAllocBuffer::min_size(); + // Make sure that we return something that is larger than AlignmentReserve + return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; } static const size_t max_size() {
--- a/src/share/vm/interpreter/linkResolver.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -320,7 +320,7 @@ // First check in default method array if (!resolved_method->is_abstract() && (InstanceKlass::cast(klass())->default_methods() != NULL)) { - int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false); + int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false, false); if (index >= 0 ) { vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index); }
--- a/src/share/vm/memory/referenceProcessor.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/memory/referenceProcessor.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -118,6 +118,7 @@ _discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q]; _discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q]; _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; + _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q]; // Initialize all entries to NULL for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { @@ -246,6 +247,13 @@ phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); + + // Process cleaners, but include them in phantom statistics. We expect + // Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + phantom_count += + process_discovered_reflist(_discoveredCleanerRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to @@ -883,6 +891,7 @@ balance_queues(_discoveredWeakRefs); balance_queues(_discoveredFinalRefs); balance_queues(_discoveredPhantomRefs); + balance_queues(_discoveredCleanerRefs); } size_t @@ -1042,6 +1051,9 @@ case REF_PHANTOM: list = &_discoveredPhantomRefs[id]; break; + case REF_CLEANER: + list = &_discoveredCleanerRefs[id]; + break; case REF_NONE: // we should not reach here if we are an InstanceRefKlass default: @@ -1307,6 +1319,17 @@ preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc, yield); } + + // Cleaner references. Included in timing for phantom references. We + // expect Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + for (uint i = 0; i < _max_num_q; i++) { + if (yield->should_return()) { + return; + } + preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive, + keep_alive, complete_gc, yield); + } } } @@ -1375,6 +1398,7 @@ case 1: return "WeakRef"; case 2: return "FinalRef"; case 3: return "PhantomRef"; + case 4: return "CleanerRef"; } ShouldNotReachHere(); return NULL;
--- a/src/share/vm/memory/referenceProcessor.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/memory/referenceProcessor.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -264,9 +264,10 @@ DiscoveredList* _discoveredWeakRefs; DiscoveredList* _discoveredFinalRefs; DiscoveredList* _discoveredPhantomRefs; + DiscoveredList* _discoveredCleanerRefs; public: - static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); } + static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); } uint num_q() { return _num_q; } uint max_num_q() { return _max_num_q; }
--- a/src/share/vm/memory/referenceType.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/memory/referenceType.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -35,7 +35,8 @@ REF_SOFT, // Subclass of java/lang/ref/SoftReference REF_WEAK, // Subclass of java/lang/ref/WeakReference REF_FINAL, // Subclass of java/lang/ref/FinalReference - REF_PHANTOM // Subclass of java/lang/ref/PhantomReference + REF_PHANTOM, // Subclass of java/lang/ref/PhantomReference + REF_CLEANER // Subclass of sun/misc/Cleaner }; #endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
--- a/src/share/vm/memory/threadLocalAllocBuffer.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/memory/threadLocalAllocBuffer.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -235,22 +235,19 @@ } size_t ThreadLocalAllocBuffer::initial_desired_size() { - size_t init_sz; + size_t init_sz = 0; if (TLABSize > 0) { - init_sz = MIN2(TLABSize / HeapWordSize, max_size()); - } else if (global_stats() == NULL) { - // Startup issue - main thread initialized before heap initialized. - init_sz = min_size(); - } else { + init_sz = TLABSize / HeapWordSize; + } else if (global_stats() != NULL) { // Initial size is a function of the average number of allocating threads. unsigned nof_threads = global_stats()->allocating_threads_avg(); init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) / (nof_threads * target_refills()); init_sz = align_object_size(init_sz); - init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); } + init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); return init_sz; }
--- a/src/share/vm/memory/threadLocalAllocBuffer.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/memory/threadLocalAllocBuffer.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -105,7 +105,7 @@ // do nothing. tlabs must be inited by initialize() calls } - static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); } + static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize) + alignment_reserve(); } static const size_t max_size() { assert(_max_size != 0, "max_size not set up"); return _max_size; } static void set_max_size(size_t max_size) { _max_size = max_size; }
--- a/src/share/vm/oops/instanceKlass.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/oops/instanceKlass.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -1453,32 +1453,41 @@ } Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const { - return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass); + return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass, false); } // find_instance_method looks up the name/signature in the local methods array // and skips over static methods Method* InstanceKlass::find_instance_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - Method* meth = InstanceKlass::find_method(methods, name, signature); - if (meth != NULL && meth->is_static()) { - meth = NULL; - } + Method* meth = InstanceKlass::find_method_impl(methods, name, signature, false, true); return meth; } +// find_instance_method looks up the name/signature in the local methods array +// and skips over static methods +Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) { + return InstanceKlass::find_instance_method(methods(), name, signature); +} + // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - return InstanceKlass::find_method_impl(methods, name, signature, false); + return InstanceKlass::find_method_impl(methods, name, signature, false, false); } Method* InstanceKlass::find_method_impl( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) { - int hit = find_method_index(methods, name, signature, skipping_overpass); + Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { + int hit = find_method_index(methods, name, signature, skipping_overpass, skipping_static); return hit >= 0 ? methods->at(hit): NULL; } +bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) { + return (m->signature() == signature) && + (!skipping_overpass || !m->is_overpass()) && + (!skipping_static || !m->is_static()); +} + // Used directly for default_methods to find the index into the // default_vtable_indices, and indirectly by find_method // find_method_index looks in the local methods array to return the index @@ -1487,13 +1496,14 @@ // is important during method resolution to prefer a static method, for example, // over an overpass method. int InstanceKlass::find_method_index( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) { + Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { int hit = binary_search(methods, name); if (hit != -1) { Method* m = methods->at(hit); + // Do linear search to find matching signature. First, quick check // for common case, ignoring overpasses if requested. - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return hit; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit; // search downwards through overloaded methods int i; @@ -1501,18 +1511,18 @@ Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; } // search upwards for (i = hit + 1; i < methods->length(); ++i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; } // not found #ifdef ASSERT - int index = skipping_overpass ? -1 : linear_search(methods, name, signature); + int index = skipping_overpass || skipping_static ? -1 : linear_search(methods, name, signature); assert(index == -1, err_msg("binary search should have found entry %d", index)); #endif }
--- a/src/share/vm/oops/instanceKlass.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/oops/instanceKlass.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -520,10 +520,16 @@ // find a local method (returns NULL if not found) Method* find_method(Symbol* name, Symbol* signature) const; static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature); + + // find a local method, but skip static methods + Method* find_instance_method(Symbol* name, Symbol* signature); static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature); + // true if method matches signature and conforms to skipping_X conditions. + static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static); + // find a local method index in default_methods (returns -1 if not found) - static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass); + static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); // lookup operation (returns NULL if not found) Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const; @@ -1076,7 +1082,7 @@ // find a local method (returns NULL if not found) Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const; - static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass); + static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); // Free CHeap allocated fields. void release_C_heap_structures();
--- a/src/share/vm/runtime/vmStructs.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -671,6 +671,7 @@ static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \ + static_field(SystemDictionary, WK_KLASS(Cleaner_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \
--- a/src/share/vm/utilities/defaultStream.hpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/utilities/defaultStream.hpp Wed Dec 17 12:48:26 2014 -0800 @@ -41,6 +41,8 @@ void init(); void init_log(); + fileStream* open_file(const char* log_name); + void start_log(); void finish_log(); void finish_log_on_error(char *buf, int buflen); public:
--- a/src/share/vm/utilities/ostream.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/utilities/ostream.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -370,7 +370,6 @@ #define EXTRACHARLEN 32 #define CURRENTAPPX ".current" -#define FILENAMEBUFLEN 1024 // convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS char* get_datetime_string(char *buf, size_t len) { os::local_time_string(buf, len); @@ -404,7 +403,6 @@ buffer_length = strlen(log_name) + 1; } - // const char* star = strchr(basename, '*'); const char* pts = strstr(basename, "%p"); int pid_pos = (pts == NULL) ? -1 : (pts - nametail); @@ -419,6 +417,11 @@ buffer_length += strlen(tms); } + // File name is too long. + if (buffer_length > JVM_MAXPATHLEN) { + return NULL; + } + // Create big enough buffer. char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal); @@ -492,46 +495,88 @@ void test_loggc_filename() { int pid; char tms[32]; - char i_result[FILENAMEBUFLEN]; + char i_result[JVM_MAXPATHLEN]; const char* o_result; get_datetime_string(tms, sizeof(tms)); pid = os::current_process_id(); // test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test.log", tms); o_result = make_log_name_internal("test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t-%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%s-pid%u.log", tms, pid); o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%spid%u.log", tms, pid); o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p%t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u%s.log", pid, tms); o_result = make_log_name_internal("%p%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p-test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u-test.log", pid); o_result = make_log_name_internal("%p-test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "%s.log", tms); o_result = make_log_name_internal("%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + + { + // longest filename + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', sizeof(longest_name)); + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result)); + FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + } + + { + // too long file name + char too_long_name[JVM_MAXPATHLEN + 100]; + int too_long_length = sizeof(too_long_name); + memset(too_long_name, 'a', too_long_length); + too_long_name[too_long_length - 1] = '\0'; + o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result)); + } + + { + // too long with timestamp + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 't'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result)); + } + + { + // too long with pid + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 'p'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); + } } #endif // PRODUCT @@ -640,9 +685,16 @@ _bytes_written = 0L; _file_name = make_log_name(file_name, NULL); + if (_file_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", file_name); + _need_close = false; + UseGCLogFileRotation = false; + return; + } + // gc log file rotation if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) { - char tempbuf[FILENAMEBUFLEN]; + char tempbuf[JVM_MAXPATHLEN]; jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); _file = fopen(tempbuf, "w"); } else { @@ -674,10 +726,10 @@ // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. void gcLogFileStream::rotate_log(bool force, outputStream* out) { - char time_msg[FILENAMEBUFLEN]; + char time_msg[O_BUFLEN]; char time_str[EXTRACHARLEN]; - char current_file_name[FILENAMEBUFLEN]; - char renamed_file_name[FILENAMEBUFLEN]; + char current_file_name[JVM_MAXPATHLEN]; + char renamed_file_name[JVM_MAXPATHLEN]; if (!should_rotate(force)) { return; @@ -716,12 +768,15 @@ // have a form of extended_filename.<i>.current where i is the current rotation // file number. After it reaches max file size, the file will be saved and renamed // with .current removed from its tail. - size_t filename_len = strlen(_file_name); if (_file != NULL) { - jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d", + jio_snprintf(renamed_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, - _file_name, _cur_file_num); + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, + "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } const char* msg = force ? "GC log rotation request has been received." : "GC log file has reached the maximum size."; @@ -760,19 +815,23 @@ _cur_file_num++; if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0; - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } + _file = fopen(current_file_name, "w"); if (_file != NULL) { _bytes_written = 0L; _need_close = true; // reuse current_file_name for time_msg - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, + jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - current_file_name); + os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); write(time_msg, strlen(time_msg)); if (out != NULL) { @@ -820,32 +879,64 @@ return _log_file != NULL; } +fileStream* defaultStream::open_file(const char* log_name) { + const char* try_name = make_log_name(log_name, NULL); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", log_name); + return NULL; + } + + fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + // Try again to open the file in the temp directory. + delete file; + char warnbuf[O_BUFLEN*2]; + jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Cannot open log file: %s\n", log_name); + // Note: This feature is for maintainer use only. No need for L10N. + jio_print(warnbuf); + try_name = make_log_name(log_name, os::get_temp_directory()); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory()); + return NULL; + } + + jio_snprintf(warnbuf, sizeof(warnbuf), + "Warning: Forcing option -XX:LogFile=%s\n", try_name); + jio_print(warnbuf); + + file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + delete file; + return NULL; +} + void defaultStream::init_log() { // %%% Need a MutexLocker? const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log"; - const char* try_name = make_log_name(log_name, NULL); - fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); - if (!file->is_open()) { - // Try again to open the file. - char warnbuf[O_BUFLEN*2]; - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Cannot open log file: %s\n", try_name); - // Note: This feature is for maintainer use only. No need for L10N. - jio_print(warnbuf); - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); - try_name = make_log_name(log_name, os::get_temp_directory()); - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Forcing option -XX:LogFile=%s\n", try_name); - jio_print(warnbuf); - delete file; - file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + fileStream* file = open_file(log_name); + + if (file != NULL) { + _log_file = file; + _outer_xmlStream = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); + start_log(); + } else { + // and leave xtty as NULL + LogVMOutput = false; + DisplayVMOutput = true; + LogCompilation = false; } - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); +} - if (file->is_open()) { - _log_file = file; - xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); - _outer_xmlStream = xs; +void defaultStream::start_log() { + xmlStream*xs = _outer_xmlStream; if (this == tty) xtty = xs; // Write XML header. xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>"); @@ -900,13 +991,6 @@ xs->head("tty"); // All further non-markup text gets copied to the tty: xs->_text = this; // requires friend declaration! - } else { - delete(file); - // and leave xtty as NULL - LogVMOutput = false; - DisplayVMOutput = true; - LogCompilation = false; - } } // finish_log() is called during normal VM shutdown. finish_log_on_error() is
--- a/src/share/vm/utilities/vmError.cpp Wed Dec 17 10:43:38 2014 -0800 +++ b/src/share/vm/utilities/vmError.cpp Wed Dec 17 12:48:26 2014 -0800 @@ -22,6 +22,7 @@ * */ +#include <fcntl.h> #include "precompiled.hpp" #include "compiler/compileBroker.hpp" #include "gc_interface/collectedHeap.hpp" @@ -841,7 +842,8 @@ static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { int fd = -1; if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) { - fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666); + // the O_EXCL flag will cause the open to fail if the file exists + fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666); } return fd; }