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: 6512111
Votes 1
Synopsis final long stack variable gets corrupted when FileChannel read is interrupted
Category hotspot:compiler1
Reported Against
Release Fixed hs10(b07), 6u1(b03) (Bug ID:2145986) , 7(b07) (Bug ID:2176837)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs
Submit Date 11-JAN-2007
Description
FULL PRODUCT VERSION :
1.6.0-b105

ADDITIONAL OS VERSION INFORMATION :
 customer  Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
final long stack variable gets corrupted when FileChannel read is interrupted

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run the main method in provided source code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
final long variable value remains constant
ACTUAL -
final long variable value gets corrupted during program execution

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Random;

public class CorruptFinalLong {

	private static final Random random = new Random();

	private static void createFileIfNeeded(File file) throws IOException {
		if (!file.exists()) {
			int bufSize = 1000000;
			int rounds = 50;
			System.out.println("writing random file " + file + " of size " + (bufSize * rounds)
					+ " bytes");
			byte[] buf = new byte[bufSize];
			OutputStream out = new BufferedOutputStream(new FileOutputStream(file), 65536);
			for (int i = 0; i < rounds; i++) {
				random.nextBytes(buf);
				out.write(buf);
			}
			out.close();
		}
	}

	public static void main(String[] args) throws Exception {

		System.setErr(System.out);

		String[] props = new String[] { "java.vm.version", "java.vm.name", "sun.os.patch.level",
				"java.runtime.version", "java.vm.version", "os.arch", "os.name",
				"java.specification.version", "java.vm.specification.version",
				"java.specification.vendor", "java.version" };

		for (String p : props) {
			System.out.printf("%30s: %s", p, System.getProperty(p));
			System.out.println();
		}
		System.out.println();

		final File file = new File("random.dat");

		createFileIfNeeded(file);

		final Thread t = Thread.currentThread();

		new Thread(new Runnable() {
			public void run() {
				try {
					Thread.sleep(1000);
					System.out.println("\tabout to interrupt thread '" + t + "' from thread '"
							+ Thread.currentThread() + "'");
					t.interrupt();
				} catch (InterruptedException e) {
					System.out.println("\tinterrupted in thread");
					e.printStackTrace();
				}

			}
		}).start();

		final long start = System.currentTimeMillis();
		System.out.println("started at " + new Date(start) + " (" + start + " ms)");
		System.out.println();

		MessageDigest md = MessageDigest.getInstance("MD5");

		ByteChannel channel = new FileInputStream(file).getChannel();
		try {
			int cap = 10;
			ByteBuffer byteBuffer = ByteBuffer.allocateDirect(cap);
			byte[] local = new byte[cap];
			long lastRead = 0;
			boolean eof = false;
			while (!eof) {
				byteBuffer.rewind();
				int bytesReadThisTime = channel.read(byteBuffer);
				if (bytesReadThisTime == -1) {
					eof = true;
				} else {
					// totalRead += bytesReadThisTime;
					byteBuffer.rewind();
					byteBuffer.get(local, 0, bytesReadThisTime);
					md.update(local, 0, bytesReadThisTime);
					if (System.currentTimeMillis() - lastRead > 1000) {
						lastRead = System.currentTimeMillis();
					}
				}
			}
		} catch (Exception e) {
			if (Thread.interrupted()) {
				System.out.println("\t********* IO was interrupted in thread '"
						+ Thread.currentThread() + "': " + e);
			} else {
				System.out.println("\texception: " + e);
			}
		} finally {
			channel.close();
		}

		System.out.println();
		System.out
				.println("the following line should be identical to the similar one above, since variable 'start' is final:");
		System.out.println("started at " + new Date(start) + " (" + start + " ms)");

	}

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
none --- aside from reverting to java 5.0
Posted Date : 2007-01-11 10:56:02.0
Work Around
Use Server VM (-server option).
Evaluation
Possible compiler1 issue on x86 rather than NIO bug.
Posted Date : 2007-01-11 11:38:40.0

It looks like it's a bug with OSR and longs.
Posted Date : 2007-01-11 17:51:27.0

The problem is actually in the generation of exception adapters.  Exception edges aren't explicitly represented in the control flow graph so adapters are inserted along the exception edges to adjust the register states between the catch and throw points.  Sometimes they have to emit stack to stack moves and the code for doing that wasn't accounting for the fact that the push changes the esp so it was picking up the wrong high word in the move.  The fix is trivial.
Posted Date : 2007-01-11 20:14:10.0

Note that this only effect x86.
Posted Date : 2007-01-17 02:07:50.0
Comments
  
  Include a link with my name & email   

Submitted On 16-JAN-2007
which future released version and build is this scheduled to be fixed in?



PLEASE NOTE: JDK6 is formerly known as Project Mustang