stack overflow interacts poorly with classloaders

Timothy Stack kaffe@rufus.w3.org
Tue, 13 Jun 2000 14:32:47 -0600 (MDT)



hi,

I modified verifyMethod in code-analayse.c to load the exception
classes and it seems to work fine.  I also updated godmars Overflow
test case to use a class loader and tweaked some other ones.  Can
someone look this over and make sure I'm not missing something...

thanks,

tim stack




Index: kaffe/kaffe/kaffevm/baseClasses.c
diff -u kaffe/kaffe/kaffevm/baseClasses.c:1.2 kaffe/kaffe/kaffevm/baseClasses.c:1.3
--- kaffe/kaffe/kaffevm/baseClasses.c:1.2	Thu May  4 17:00:39 2000
+++ kaffe/kaffe/kaffevm/baseClasses.c	Tue Jun 13 14:21:34 2000
@@ -68,6 +68,7 @@
 Hjava_lang_Class* javaLangFloatClass;
 Hjava_lang_Class* javaLangDoubleClass;
 
+Hjava_lang_Class* javaLangThrowable;
 Hjava_lang_Class* javaLangArrayIndexOutOfBoundsException;
 Hjava_lang_Class* javaLangNullPointerException;
 Hjava_lang_Class* javaLangArithmeticException;
@@ -248,6 +249,7 @@
 	loadStaticClass(&PtrClass, PTRCLASS);
 
 	/* Exception handling types */
+	loadStaticClass(&javaLangThrowable, "java/lang/Throwable");
 	loadStaticClass(&javaLangArrayIndexOutOfBoundsException, "java/lang/ArrayIndexOutOfBoundsException");
 	loadStaticClass(&javaLangNullPointerException, "java/lang/NullPointerException");
 	loadStaticClass(&javaLangArithmeticException, "java/lang/ArithmeticException");
Index: kaffe/kaffe/kaffevm/baseClasses.h
diff -u kaffe/kaffe/kaffevm/baseClasses.h:1.1 kaffe/kaffe/kaffevm/baseClasses.h:1.2
--- kaffe/kaffe/kaffevm/baseClasses.h:1.1	Thu May  4 16:13:06 2000
+++ kaffe/kaffe/kaffevm/baseClasses.h	Tue Jun 13 14:21:38 2000
@@ -46,6 +46,7 @@
 extern struct Hjava_lang_Class*	javaLangFloatClass;
 extern struct Hjava_lang_Class*	javaLangDoubleClass;
 
+extern struct Hjava_lang_Class* javaLangThrowable;
 extern struct Hjava_lang_Class*	javaLangNullPointerException;
 extern struct Hjava_lang_Class*	javaLangArithmeticException;
 extern struct Hjava_lang_Class* javaLangArrayIndexOutOfBoundsException;
Index: kaffe/kaffe/kaffevm/code-analyse.c
diff -u kaffe/kaffe/kaffevm/code-analyse.c:1.1 kaffe/kaffe/kaffevm/code-analyse.c:1.2
--- kaffe/kaffe/kaffevm/code-analyse.c:1.1	Thu May  4 16:13:06 2000
+++ kaffe/kaffe/kaffevm/code-analyse.c	Tue Jun 13 14:21:42 2000
@@ -28,6 +28,8 @@
 #include "locks.h"
 #include "thread.h"
 #include "jthread.h"
+#include "baseClasses.h"
+#include "soft.h"
 #include "md.h"
 #include "gc.h"
 
@@ -249,6 +251,51 @@
 	sp = meth->localsz + meth->stacksz - 1;
 	if (meth->exception_table != 0) {
 		for (lcl = 0; lcl < meth->exception_table->length; lcl++) {
+			jexceptionEntry* eptr;
+
+			eptr = &meth->exception_table->entry[lcl];
+			/*
+			 * Verification requires us to resolve the catch type
+			 * and check that its actually a Throwable.  But, we
+			 * also do it to ensure that the classes are ready when
+			 * we need them and have little room to work (e.g. a
+			 * stack overflow).
+			 */
+			if( eptr->catch_idx == 0 ) {
+				/* A finally clause... */
+			} else {
+				eptr->catch_type = getClass(eptr->catch_idx,
+							    meth->class,
+							    einfo);
+				/* 
+				 * If we could not resolve the catch class,
+				 * then we must a) record that fact to guard
+				 * against possible recursive attempts to load
+				 * it and b) throw the error resulting from
+				 * that failure and forget about the current
+				 * exception.
+				 */
+				if (eptr->catch_type == NULL) {
+DBG(ELOOKUP|DBG_RESERROR,
+					dprintf("Couldn't resolve catch class\n");
+)
+					eptr->catch_type =
+						UNRESOLVABLE_CATCHTYPE;
+					throwError(einfo);
+					return (false);
+				}
+				/*
+				 * Make sure the exception is a subclass of
+				 * throwable.
+				 */
+				if( !instanceof(javaLangThrowable,
+						eptr->catch_type) )
+				{
+					postException(einfo,
+						JAVA_LANG(ClassFormatError));
+					throwError(einfo);
+				}
+			}
 			pc = meth->exception_table->entry[lcl].handler_pc;
 			ATTACH_NEW_BASICBLOCK(pc);
 			SET_STARTOFEXCEPTION(pc);
Index: kaffe/test/regression/ExceptionTestClassLoader.java
diff -u kaffe/test/regression/ExceptionTestClassLoader.java:1.1 kaffe/test/regression/ExceptionTestClassLoader.java:1.2
--- kaffe/test/regression/ExceptionTestClassLoader.java:1.1	Thu May  4 16:13:48 2000
+++ kaffe/test/regression/ExceptionTestClassLoader.java	Tue Jun 13 14:22:09 2000
@@ -68,7 +68,7 @@
 
 
 
-
+// Sort output
 /* Expected Output:
 Success 1.
 Success 2.
Index: kaffe/test/regression/ExceptionTestClassLoader2.java
diff -u kaffe/test/regression/ExceptionTestClassLoader2.java:1.1 kaffe/test/regression/ExceptionTestClassLoader2.java:1.2
--- kaffe/test/regression/ExceptionTestClassLoader2.java:1.1	Thu May  4 16:13:48 2000
+++ kaffe/test/regression/ExceptionTestClassLoader2.java	Tue Jun 13 14:22:17 2000
@@ -89,9 +89,8 @@
 
 
 
 
 /* Expected Output:
-Success 1.
 Success 2.
 Success 3.
 Success 4.
Index: kaffe/test/regression/Overflow.java
diff -u kaffe/test/regression/Overflow.java:1.1 kaffe/test/regression/Overflow.java:1.2
--- kaffe/test/regression/Overflow.java:1.1	Thu May  4 16:13:49 2000
+++ kaffe/test/regression/Overflow.java	Tue Jun 13 14:23:14 2000
@@ -4,7 +4,9 @@
  *
  * @author Godmar Back <gback@cs.utah.edu>
  */
-public class Overflow extends Thread
+import java.io.*;
+
+class OverflowTester extends Thread
 {
     public void run() {
 	try {
@@ -18,17 +20,61 @@
 	recurse();
     }
 
-    public static void main(String av[]) throws Exception
+    public OverflowTester() throws Exception
     {
-	Overflow o = new Overflow();
-	o.run();	// check for main thread
-
-	o.start();	// check for other thread
-	o.join();
+	    run();	// check for main thread
+		    
+	    start();	// check for other thread
+	    join();
     }
 }
 
+class Overflow extends ClassLoader {
+	
+	/*
+	 * read a .class file
+	 */
+	static byte [] readin(String name) throws Exception
+	{
+		File cf = new File(name);
+		FileInputStream cfi = new FileInputStream(cf);
+
+		int len = (int)cf.length();
+		byte [] cb = new byte[len];
+		if (cfi.read(cb) != len)
+			throw new Exception("short read for " + name);
+		return cb;
+	}
+
+	public Class loadClass(String name, boolean resolve) 
+		throws ClassNotFoundException 
+	{
+		Class c = null;
+	
+		try {
+			byte []b = readin(name + ".class");
+			return defineClass(name, b, 0, b.length);
+		} catch (Exception e) {
+			return findSystemClass(name);
+		}
+	}
+	
+	public static void main(String av[]) throws Exception
+	{
+		OverflowTester oft;
+		Overflow l = new Overflow();
+		Class c;
+		
+		c = l.loadClass("OverflowTester");
+		c.newInstance();
+		oft = new OverflowTester();
+	}
+	
+}
+
 /* Expected Output:
+Success.
+Success.
 Success.
 Success.
 */