Microsoft KB Archive/219280

= FIX: Class Must Be Touched for Static Initialization to Occur When Loaded by SecurityClassLoader =

Article ID: 219280

Article Last Modified on 6/14/2006

-

APPLIES TO


 * Microsoft Java Virtual Machine
 * Microsoft Visual J++ 1.0 Standard Edition
 * Microsoft Visual J++ 1.1 Standard Edition
 * Microsoft Visual J++ 6.0 Standard Edition
 * Microsoft Software Development Kit for Java 1.0
 * Microsoft Software Development Kit for Java 1.5
 * Microsoft Software Development Kit for Java 1.51
 * Microsoft Software Development Kit for Java 2.02
 * Microsoft Software Development Kit for Java 2.01
 * Microsoft Software Development Kit for Java 2.02
 * Microsoft Software Development Kit for Java 3.0
 * Microsoft Software Development Kit for Java 3.0
 * Microsoft Software Development Kit for Java 3.1

-



This article was previously published under Q219280



SYMPTOMS
When deriving from the SecurityClassLoader class, as described in the SDK for Java documentation, to associate permissions with loaded classes, the loaded classes' static variables are not initialized until the class is touched by either instantiating a new instance or calling a method on the class. This behavior is by default.



CAUSE
An optimization flag is set to on by default.



RESOLUTION
This problem has been fixed in build 3155 of the Microsoft virtual machine. If you are using the Microsoft Raw Native Interface (RNI), you can work around this problem by setting a private member variable of the SecurityClassLoader class. Please see the RNI sample below.



STATUS
Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.



Steps to Reproduce Behavior

 * Compile and run the following code.
 * Follow the instructions in the code comments.
 * If you are running on a Microsoft virtual machine build older than 3155, the values of the static variables have not been set.
 * Otherwise, the values appear in the MessageBox as expected.

Java Code
import java.io.*; import com.ms.security.*; import com.ms.win32.*;

public class SecureLoader extends SecurityClassLoader { private static File f;  private FileInputStream fis;

private byte[] loadClassData(String class_name) throws Exception {   // Change this as needed to reflect the path // to the appropriate .class file TestClass.class. // Note that you will also want to make sure that // the class file does not exist on the system // CLASSPATH, or it will be loaded by the System // ClassLoader and not your custom SecurityClassLoader. f = new File("D:/VJProj/RNIBug/" + class_name + ".class"); synchronized (f) {     try {       byte[] data = new byte[(int)f.length]; fis = new FileInputStream(f); fis.read(data); return data; }     finally {       fis.close; }   }  }

protected Class loadClass(String class_name, boolean resolve_class) throws ClassNotFoundException {   Class cl = null;

try {     cl = findSystemClass(class_name); }   catch (Exception e)    { try {       byte[] class_data = loadClassData(class_name); PermissionDataSet pds = new PermissionDataSet; pds.setFullyTrusted(true); PermissionSet perms = new PermissionSet(pds);

cl = defineClass(class_name,                         class_data,                          0,                          class_data.length,                          perms,                          (java.security.Principal)null); }     catch (Exception e2) {       WinUtil.alert(e2); }   }    if (resolve_class) resolveClass(cl);

return cl; } }

class WinUtil { public static void alert(Object o)  { User32.MessageBox(0,                     o.toString,                      "Alert",                      0); } }

/***************************************************/

import java.lang.reflect.*;

public class TestRun { public static void main(String[] args) {   try {     SecureLoader sl = new SecureLoader; Class cl = sl.loadClass("TestClass", true); // Comment the following two lines to reproduce the problem. Object o = cl.newInstance; WinUtil.alert(o); // Indicates that we have an instance of TestClass. // We are unable to typecast this Object to TestClass, as     // TestClass was loaded by the custom ClassLoader SecureLoader. Field f = cl.getField("staticBlockInt"); int staticBlockInt = f.getInt(cl); f = cl.getField("staticInt"); int staticInt = f.getInt(cl);

String message = "This string is a result "; message += "of the TestClass.testMethod call.\n"; message += "The value of staticInt is "+staticInt+"\n"; message += "The value of staticBlockInt is "+staticBlockInt+"\n"; WinUtil.alert(message); }   catch (Exception e)    { WinUtil.alert(e); } } }

/***********************************************************/

public class TestClass {  public static int staticInt = 10; public static int staticBlockInt; static {     staticBlockInt = 20; }  // We are over-riding toString to indicate // that we do indeed have an instance of the // class that we want. public String toString {    return "TestClass"; } }

RNI CODE
NOTE: Make sure the Java classes used in the following code are on the CLASSPATH.
 * 1) include 
 * 2) include 
 * 3) include 

void checkForError;

void main(int argc, char *argv[]) { static const int LATE_CLINIT = -1; static const int EARLY_CLINIT = 1; static const int NOT_INITIALIZED = 0; static int staticInt = 0; static int staticBlockInt = 0; int initval = 0; ThreadEntryFrame threadEntryFrame; ClassClass* pcMyLoader = NULL; ClassClass* pcLoadedClass = NULL; HObject* phMyLoaderInst = NULL; fieldblock* pFieldBlock = NULL; if (PrepareThreadForJava(&threadEntryFrame)) {   pcMyLoader = FindClass(NULL, "SecureLoader", TRUE); checkForError; if (pcMyLoader) {     phMyLoaderInst = execute_java_constructor(        NULL,        "SecureLoader",        pcMyLoader,        ""); } else { printf("SecureLoader not found."); Sleep(3000); }   if (phMyLoaderInst) {     pFieldBlock = Class_GetField(pcMyLoader,         "initialized"); initval = Field_GetValue(phMyLoaderInst,        pFieldBlock); printf("The value of initialized is %d.\n",        initval); // This switch block is the work-around. // Comment this out to reproduce the problem. switch (initval) {     case LATE_CLINIT: Field_SetValue(phMyLoaderInst,          pFieldBlock,           EARLY_CLINIT); pFieldBlock = Class_GetField(pcMyLoader,          "initialized"); initval = Field_GetValue(phMyLoaderInst,          pFieldBlock); break; case NOT_INITIALIZED: checkForError; break; case EARLY_CLINIT: break; }     printf("The value of initialized is now:  %d\n",         initval); pcLoadedClass = (ClassClass*)execute_java_dynamic_method(       NULL,        phMyLoaderInst,        "loadClass",        "(Ljava/lang/String;Z)Ljava/lang/Class;",        makeJavaString("TestClass", strlen("TestClass")),        TRUE); } else checkForError; if (pcLoadedClass) {     pFieldBlock = Class_GetField(pcLoadedClass,         "staticInt"); staticInt = Field_GetValue(NULL,        pFieldBlock); printf("The value of staticInt is %d.\n",        staticInt); pFieldBlock = Class_GetField(pcLoadedClass,        "staticBlockInt"); staticBlockInt = Field_GetValue(NULL,        pFieldBlock); printf("The value of staticBlockInt is %d.\n",        staticBlockInt); Sleep(3000); } else checkForError; UnprepareThreadForJava(&threadEntryFrame); } }

void checkForError { if (getPendingException(NULL)) {   exceptionDescribe(NULL); Sleep(3000); exceptionClear(NULL); }        }

