|
Quick Lists
|
|
Bug ID:
|
4647546
|
|
Votes
|
1
|
|
Synopsis
|
Hotspot is using single threaded ("MT-unsafe") Solaris functions
|
|
Category
|
hotspot:runtime_system
|
|
Reported Against
|
1.4
|
|
Release Fixed
|
1.4.1(hopper)
|
|
State
|
10-Fix Delivered,
bug
|
|
Priority:
|
4-Low
|
|
Related Bugs
|
4515367
,
4873538
,
4886930
|
|
Submit Date
|
05-MAR-2002
|
|
Description
|
The Solaris versions of Hotspot are not using the MT-safe versions of certain OS functions in some cases. This may lead to subtle failures in a multithreaded context. I complete survey of Hotspot should be conducted to identify all occurances of this problem and each function's MT-safe counterpart must be substituted while also implementing any special buffering requirements that are exposed.
|
|
Work Around
|
No known workaround for this problem except avoidance of multi-threaded use of the JNI methods that use the MT-unsafe VM calls and it's difficult to know if even this restriction could be guaranteed as the core libraries probably make use of these VM interfaces.
This turned out to be a mistaken assumption, see the evaluation.
xxxxx@xxxxx 2002-04-29
|
|
Evaluation
|
A survey of the nonreentrant Unix routines referenced in the VM source was conducted and it turned up the following uses:
====== ctime ======
./share/vm/runtime/os.cpp: st->print("Local Time = %s", asctime(ltime)); /* ctime() puts a '\n' at the end */
====== localtime ======
./share/vm/runtime/os.cpp: ltime = localtime(&long_time);
====== gethostbyname ======
./os/win32/agent/SwDbgSrv.cpp: struct hostent* myInfo = gethostbyname(myname);
./os/linux/vm/hpi_linux.hpp: return ::gethostbyname(hostname);
./os/solaris/vm/hpi_solaris.hpp: return ::gethostbyname(hostname);
====== gethostbyaddr ======
./os/linux/vm/hpi_linux.hpp: return ::gethostbyaddr(name, len, type);
./os/solaris/vm/hpi_solaris.hpp: return ::gethostbyaddr(name, len, type);
====== getservbyname ======
./os/linux/vm/hpi_linux.hpp: return ::getprotobyname(name);
./os/solaris/vm/hpi_solaris.hpp: return ::getprotobyname(name);
====== readdir ======
./os/win32/vm/os_win32.cpp:os::readdir(DIR *dirp)
== argument handling: no need for reentrant version?
./share/vm/runtime/arguments.cpp: while ((entry = os::readdir(dir)) != NULL) {
./os/linux/vm/os_linux.inline.hpp:inline struct dirent* os::readdir(DIR* dirp)
./os/linux/vm/os_linux.inline.hpp: return ::readdir(dirp);
./os/solaris/vm/os_solaris.inline.hpp:inline struct dirent* os::readdir(DIR* dirp)
./os/solaris/vm/os_solaris.inline.hpp: return ::readdir(dirp);
./share/vm/runtime/os.hpp: static struct dirent* readdir(DIR* dirp);
====== getlogin ======
====== getpwent ======
====== getnetbyname ======
====== getnetbyaddr ======
====== strtok ======
====== gmtime ======
====== getservbyport ======
====== getprotobyname ======
====== getrpcbyname ======
====== getrpcbynumber ======
====== getrpcent ======
====== ctermid ======
====== tmpnam ======
====== getpwnam ======
====== getpwuid ======
====== getspent ======
====== fgetspent ======
====== getspnam ======
====== getgrnam ======
====== getgrgid ======
====== getnetgrent ======
====== getrpcbyname ======
====== tempnam ======
====== fgetpwent ======
====== fgetgrent ======
====== ecvt ======
====== gcvt ======
====== getservent ======
====== gethostent ======
====== getgrent ======
====== fcvt ======
The worrisome routines are those used by exported VM functions that might be called in a multithreaded context:
JVM_GetHostByAddr()
JVM_GetHostByName()
JVM_GetProtoByName()
A search of the JDK sources (thanks Mark Reinhold!) showed that only networking libraries are making use of these functions and the networking code is already platform aware and for Unix platforms the VM functions are avoided and more direct libc calls are used instead.
These exported routines are documented in the following JDK header file:
src/share/javavm/export/jvm.h
This header file needs to be updated with warning comments about the dangerous routines listed above.
The remaining uses of nonrentrant libc functions are either single threaded (e.g. "argument parsing") or in contexts where we aren't too concerned about an additional failure (the VM fatal error path). Provisions can be made to use the corresponding reentrant versions of these routines without too much difficulty.
xxxxx@xxxxx 2002-04-15
As was pointed out by a reviewer, the fact that the VM uses readdir(), for
example, in its argument handling and doesn't present a hazard of corruption
through multithreading within the VM doesn't mean it's safe to use this routine.
That is, if we try not to distinguish between application vs system code in a
a process and assume that anybody embedding a VM may use nonreentrant
system routines, then the rule becomes *never use the nonreentrant version,
period*. So the use of readdir() mentioned above is being modified to use
readdir_r() instead.
Also, I wasn't clear about the list of nonreentrant routines that the VM was
checked for. Here is the complete list used for the survey:
asctime ctermid ctime ecvt fcvt fgetgrent fgetpwent fgetspent gcvt
getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent
getlogin getnetbyaddr getnetbyname getnetgrent getprotobyname
getpwent getpwnam getpwuid getrpcbyname getrpcbyname getrpcbynumber
getrpcent getservbyname getservbyport getservent getspent getspnam
gmtime localtime rand readdir strtok tempnam tmpnam
xxxxx@xxxxx 2002-04-24
|
|
Comments
|
Submitted On 23-APR-2002
p-mcilroy
[ followup to (Review ID: 145352) thread-unsafe methods
detected in Solaris runtime library.]
The above is NOT a complete list of the mt-unsafe functions
referenced in the solaris shared libraries.
In particular, the function localtime() is HIGHLY thread-
unsafe, and frequently leads to catastrophic heap
corruption in (non-java) application code.
The following is a complete list, done as a join on the
solaris man pages (man -k) with the .so files (nm):
jre/lib/sparc/*.so illegal symbols:
asctime
ctime
gethostbyaddr
gethostbyname
gethostbyname
getprotobyname
getpwuid
localtime
rand
readdir
readdir
strtok
jre/lib/sparc/native_threads/libhp.so illegal symbols:
gethostbyaddr
gethostbyname
getprotobyname
This can be reproduced with the commands:
$ nm -AC *.so | grep UNDEF | grep -v :: | sort -t'|' +7 |
sed 's/.*|//' > java.symbols
$ man -k _r | grep "_r[<tab> ]" | sed "s/[<tab> ].*//" |
sed 's/_r$//' | sort > unsafe
(NOTE: here <tab> represents tab character; you may need to
use control-V to get it into your shell line.)
$ join java.symbols unsafe
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |