Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
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
  
  Include a link with my name & email   

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