JDK-4887178 : in with J2se1.3 in multithread situation, socket reads data unexpectly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 1.3.1
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2003-07-08
  • Updated: 2009-06-25
  • Resolved: 2003-11-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
1.3.1_11 11Fixed
escalationID is 547065
My ISV experiences the below problem as below

testcase is in SocketBug.jar
start server from ost.ServerSimulator
start client from ost.ClientSimuator

BUG : in multithreads situation, socket improperly reads data instead of 
blocking read or throw exceptions, although lock is designed properly.
Platform: J2SE1.3
The bug is reproducible only with the setSOtimeout ,without an setSOtimeout 
there is no problem

First ServerSimulator  Threads generate many sockets in server side, pass those 
sockets to SocketReader Threads  and put SocketReaders  to a thread pool for 
also pass those sockets to  SocketCloser threads groups for closing sockets by 
putting socketcloser threads into a same threadpool  and ServerSimuator Threads  
group will also setSoTimeout  for every
passed socket  , SocketReader thread read data from  inputstream completely, it 
will notfiy SocketCloser  thread to close this socket, then it trys to read 4 
bytes data again . at this moment
it should block at  p = in.read(data, 0, 4), because client doesnot send data 
At this moment, socket could be closed or still open, if socket is closed by 
SocketCloser , then IOException should happen at p=in.read(data,0,4). if 
blocking time  expired, then also IOException will 
happen at p=in.read(data,0,4), but SocketReader should never be able to read any 
data at in.read(data,0,0,4), but in multi threads situation, it does read data 

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.3.1_11 1.4.1_07 1.4.2_04 generic tiger-beta FIXED IN: 1.3.1_11 1.4.1_07 1.4.2_04 tiger-beta INTEGRATED IN: 1.3.1_11 1.4.1_07 1.4.2_04 tiger-b28 tiger-beta VERIFIED IN: 1.3.1_11 1.4.1_07 1.4.2_04

SUGGESTED FIX Fix for 1.3.1 code base: ------- PlainSocketImpl.java ------- *** /tmp/sccs.J7aGol Wed Aug 13 12:28:25 2003 --- PlainSocketImpl.java Wed Aug 13 12:28:24 2003 *************** *** 508,513 **** --- 508,516 ---- synchronized(fdLock) { if (fd != null) { if (fdUseCount == 0) { + if (closePending) { + return; + } closePending = true; socketClose(false); fd = null; ###@###.### 2003-08-13 --- SocketInputStream.c Mon Oct 13 01:20:16 2003 *** 50,60 **** char *bufP; char BUF[MAX_BUFFER_LEN]; jobject fdObj = (*env)->GetObjectField(env, this, sis_fdID); ! jint fd, timeout; jobject impl = (*env)->GetObjectField(env, this, sis_implID); jint datalen, nread; --- 50,60 ---- char *bufP; char BUF[MAX_BUFFER_LEN]; jobject fdObj = (*env)->GetObjectField(env, this, sis_fdID); ! jint fd, timeout, newfd; jobject impl = (*env)->GetObjectField(env, this, sis_implID); jint datalen, nread; *** 123,132 **** --- 123,139 ---- if (bufP != BUF) { free(bufP); } return -1; } + + /*check if the socket has been closed while we were in timeout*/ + newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); + if (newfd == -1) { + NET_ThrowSocketException(env, "Socket Closed"); + return -1; + } } nread = JVM_Recv(fd, bufP, len, 0); if (nread > 0) { (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP); } else { ###@###.### 2003-10-28

EVALUATION I modified the testcase to read 3 bytes in the second read() so as to distinguish the two 'read's. I analysed the system level calls made by the testcase using 'truss'. This is what is happening at the system level: 1336/11: read(83, "\0010203", 4) = 4 ... 1336/13: close(83) = 0 ... 1336/6: accept(6, 0xEE58153C, 0xEE58154C, 1) = 83 ... 1336/11: read(83, "\00102", 3) = 3 Thread 11 reads 4 bytes in the first read call on the socket with fd 83 and notifies other thread to close this socket and proceeds to read 3 more bytes. Meanwhile Thread 13 closes that fd and creates another socket with same fd. Now Thread 11 reads 3 bytes on fd 83 as this is the first read after creation of fd 83 again. SocketInputStream class has an instance variable 'impl' of type PlainSocketImpl which contains an instance variable of type FileDescriptor (fd). SocketInputStream has methods to read and close the stream which in turn call the impl's methods to get the fd in read and set the fd to null in close. Now here what could be happening is: While one thread is in the second read blocked at timeout, another thread closes the stream and sets the 'fd' of PlainSocketImpl to NULL and one another thread creates one more socket with the same file descriptor. Now when the first thread comes out from timeout(in the native), it does not know that the stream has been closed an it passes the old fd number to system read(). As this fd is valid (because it got recreated), read succeeds. So the native call SocketRead() in SocketInputStream class and the close() method should be synchronized blocks. While one thread is in native SocketRead(), we should not allow other threads to close the stream and set fd to null. ###@###.### 2003-07-28