Name: jn10789 Date: 11/17/98
There is a race condition in the solaris
native threads implemenation of
sysTimeoutFD() in io_md.c. If one sets
a timeout on a socket, and one thread
reads it while another thread closes
it, io_md.c can possibly SEGV. The
attached program reproduces it within
seconds:
dbx: warning: can't find object file io_md.o
t@9 (l@4) signal SEGV (no mapping at the fault address) in sysTimeoutFD at 0xef77a38c
sysTimeoutFD+0xa4: ld [%l0], %l3
(dbx) where
=>[1] sysTimeoutFD(0xed750268, 0x2710, 0x1, 0x0, 0x0, 0x0), at 0xef77a38c
[2] java_net_SocketInputStream_socketRead(0xed704628, 0xed704620, 0x0, 0x1, 0x0, 0x0), at 0xef266af8
[3] Java_java_net_SocketInputStream_socketRead_stub(0xf3180, 0xef1d3cb4, 0x0, 0x0, 0x0, 0x0), at 0xef269bd0
[4] invokeNativeMethod(0xed704628, 0xec0bc, 0x4, 0xef1d3cb4, 0x200, 0x72756e00), at 0xef6eee6c
[5] ExecuteJava(0xef1d3b90, 0xef1d3cb4, 0xf3144, 0xf3170, 0xf3158, 0xec455), at 0xef76ead4
[6] do_execute_java_method_vararg(0xef1d3cb4, 0xed704140, 0xef79df0c, 0xef79df10, 0x0, 0x0), at 0xef70f8f8
[7] execute_java_dynamic_method(0x0, 0xed704140, 0xef79df0c, 0xef79df10, 0xd80d8, 0x0), at 0xef70e4d4
[8] ThreadRT0(0xed704140, 0xdb8b8, 0xd80d8, 0xd80d8, 0x1, 0x2000), at 0xef748474
[9] _start(0xdb8b8, 0x0, 0xef1d3e46, 0xef1d3e47, 0x0, 0xef1d3e45), at 0xef775b68
The problem is that the file descriptor might
have been set to -1 in the Classjava_io_FileDescriptor
object by the closing thread (in socket.c), and
then moments later the reading thread will get
the -1 fd, and in the implementation of
sysTimeoutFD() try to set the -1 bit of the
fd_set, which will access memory out of range.
Attached is the java program to demonstrate
it on native threads.
----------MTSocket.java------------------
import java.net.*;
import java.io.*;
import java.util.*;
public class MTSocket implements Runnable {
Socket s;
static void p(String s) {
System.out.println(s);
}
static void pe(String s) {
System.err.println(s);
}
static int SRVR_PORT = 0;
static int nthreads = 10;
public static void main(String[] a) throws Exception {
ServerSocket ss = new ServerSocket(0);
SRVR_PORT = ss.getLocalPort();
int i;
for (i = 0; i < nthreads; i++) {
new Thread(new Runner(), "runner:" + i).start();
}
i = 0;
while (true) {
Socket s = ss.accept();
new Thread(new MTSocket(s), "SRVRReader:" + (i++)).start();
}
}
public MTSocket(Socket s) {
this.s = s;
}
public void run() {
try {
run0();
} catch (Exception e) {}
}
void run0() throws Exception {
s.setTcpNoDelay(true);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
while (true) {
int r = is.read();
if (r == -1) {
s.close();
return;
}
os.write(r);
}
}
}
class Runner implements Runnable {
Socket s;
public Runner() throws IOException {
s = new Socket("localhost", MTSocket.SRVR_PORT);
}
static int nt = 0;
public void run() {
try {
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
/* this is crucial to reproducing the bug */
s.setSoTimeout(10000);
new Thread(new Closer(s), "closer:" + (nt++)).start();
while (true) {
try {
os.write('A');
if (is.read() < 0) {
break;
}
} catch (Exception e) {
break;
}
}
s.close();
} catch (Exception e) {
}
try {
/* restart */
new Thread(new Runner(), "runner:" + (nt++)).start();
} catch (Exception e) {
}
}
}
class Closer implements Runnable {
Socket s;
Closer(Socket s) {
this.s = s;
}
static Random rand = new Random(System.currentTimeMillis());
public void run() {
long nap = rand.nextLong() >>> 1;
nap %= 1000;
try {
Thread.sleep(nap);
} catch (Exception e) {}
try {
s.close();
} catch (Exception e) {}
}
}
(Review ID: 35693)
======================================================================