BZ #82: clojure doesn't start (subtype constraint violated)

Status fields:

creation_ts:2008-06-14 12:59
component:verifier
version:default branch
rep_platform:All
op_sys:All
bug_status:NEW
reporter:stefan@complang.tuwien.ac.at
From clojure_20080612.zip:

$ cacao -cp clojure.jar clojure.lang.Repl
Exception in thread "main" java.lang.ExceptionInInitializerError
   at clojure.lang.Repl.<clinit>(Repl.java:22)
Caused by: java.lang.RuntimeException: clojure.lang.Compiler$CompilerException:
boot.clj:208: subtype constraint violated (java.lang.Object is not a subclass of
clojure.lang.IObj)
   at clojure.lang.RT.<clinit>(RT.java:255)
   at clojure.lang.Repl.<clinit>(Repl.java:22)
Caused by: clojure.lang.Compiler$CompilerException: boot.clj:208: subtype constraint
violated (java.lang.Object is not a subclass of clojure.lang.IObj)
   at clojure.lang.Compiler.analyzeSeq(Compiler.java:3759)
   at clojure.lang.Compiler.analyze(Compiler.java:3614)
   at clojure.lang.Compiler.analyze(Compiler.java:3589)
   at clojure.lang.Compiler.eval(Compiler.java:3779)
   at clojure.lang.Compiler.load(Compiler.java:4032)
   at clojure.lang.RT.loadResourceScript(RT.java:278)
   at clojure.lang.RT.doInit(RT.java:288)
   at clojure.lang.RT.<clinit>(RT.java:251)
   ...1 more
Caused by: java.lang.LinkageError: subtype constraint violated (java.lang.Object is not
a subclass of clojure.lang.IObj)
   at clojure.fns.clojure.meta__42.invoke(boot.clj:147)
   at clojure.fns.clojure.defn__50.doInvoke(boot.clj:203)
   at clojure.lang.RestFn.invoke(RestFn.java:460)
   at clojure.lang.Var.invoke(Var.java:291)
   at clojure.lang.AFn.applyToHelper(AFn.java:195)
   at clojure.lang.Var.applyTo(Var.java:396)
   at clojure.lang.Compiler.macroexpand1(Compiler.java:3688)
   at clojure.lang.Compiler.analyzeSeq(Compiler.java:3740)
   ...8 more

Comment #1 by stefan@complang.tuwien.ac.at on 2008-06-14 13:14:26

gij doesn't like it too much as well:

$ gij -cp clojure.jar clojure.lang.Repl
Exception in thread "main" java.lang.NoClassDefFoundError: clojure.fns.clojure.meta__42
   at java.lang.Class.initializeClass(libgcj.so.9)
   at java.lang.Class.newInstance(libgcj.so.9)
   at clojure.lang.Compiler$FnExpr.eval(Compiler.java:2949)
   at clojure.lang.Compiler$DefExpr.eval(Compiler.java:267)
   at clojure.lang.Compiler.eval(Compiler.java:3780)
   at clojure.lang.Compiler.load(Compiler.java:4032)
   at clojure.lang.RT.loadResourceScript(RT.java:278)
   at clojure.lang.RT.doInit(RT.java:288)
   at clojure.lang.RT.<clinit>(RT.java:251)
   at java.lang.Class.initializeClass(libgcj.so.9)
   at clojure.lang.Repl.<clinit>(Repl.java:22)
   at java.lang.Class.initializeClass(libgcj.so.9)
Caused by: java.lang.VerifyError: verification failed at PC 31 in
clojure.fns.clojure.meta__42:invoke((Ljava.lang.Object;)Ljava.lang.Object;):
incompatible type on stack
   at java.lang.Class.initializeClass(libgcj.so.9)
   ...11 more
$ gij --version
java version "1.5.0"
gij (GNU libgcj) version 4.3.0 20080428 (Red Hat 4.3.0-8)

Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Comment #2 by twisti@complang.tuwien.ac.at on 2008-06-22 10:14:15

Edwin, could you have a look at this one?

Comment #3 by twisti@complang.tuwien.ac.at on 2008-07-01 09:38:40

OK, I'm assigning that one to me now, but we need to have Edwin to take a look at that
one.

Comment #4 by edwin.steiner@gmx.net on 2008-07-11 09:45:17

The problem is this method in the generated meta__42 class:

Method name:"invoke" public Descriptor: (java.lang.Object)java.lang.Object
Attribute "Code", length:106, max_stack:3, max_locals:2, code_length:42
  0: getstatic <Field clojure.fns.clojure.meta__42.const__0 clojure.lang.Var>
  3: invokevirtual <Method clojure.lang.Var.get ()java.lang.Object>
  6: checkcast <Class clojure.lang.IFn>
  9: getstatic <Field clojure.fns.clojure.meta__42.const__1 java.lang.Class>
 12: aload_1
 13: invokeinterface <InterfaceMethod clojure.lang.IFn.invoke
(java.lang.Object,java.lang.Object)java.lang.Object> nargs:3
 18: dup
 19: ifnull 39
 22: getstatic <Field java.lang.Boolean.FALSE java.lang.Boolean>
 25: if_acmpeq 40
 28: aload_1
 29: aconst_null
 30: astore_1
 31: invokeinterface <InterfaceMethod clojure.lang.IObj.meta
()clojure.lang.IPersistentMap> nargs:1
 36: goto 41
 39: pop
 40: aconst_null
 41: areturn

The invokeinterface at 31 calls a method of clojure.lang.IObj
using a java.lang.Object instance (loaded via aload_1).

I wonder why this works with HotSpot. Maybe there is information in
the class file that jcf-dump does not show correctly?

-Edwin

Comment #5 by twisti@complang.tuwien.ac.at on 2008-07-15 09:09:41

Hmm, I'm not sure what I should answer.  Maybe we really should forward this issue to an
OpenJDK mailing list, e.g. hotspot-dev.

Comment #6 by stefan@complang.tuwien.ac.at on 2008-07-30 16:49:38

FYI <http://groups.google.com/group/clojure/browse_thread/thread/a9466e10ff9569f1> –
From Rich Hickey (clojure author): "invokevirtual does not require a verified target
type AFAIK"

He just added a CHECKCAST instruction to the generated code
<http://clojure.svn.sourceforge.net/viewvc/clojure?view=rev&revision=975>. I will soon
verify if this makes it possible to run clojure.

Comment #7 by stefan@complang.tuwien.ac.at on 2008-07-31 17:16:32

The CHECKCAST instruction from the clojure svn makes the verifier happy. Unfortunately,
another error happens shortly thereafter.

clojure.lang.Compiler$CompilerException: boot.clj:1422: More than one matching method
found: append

(the line number reference in boot.clj applies to svn r925)

Comment #8 by stefan@complang.tuwien.ac.at on 2008-07-31 17:37:54

(I could have found out easier by using -noverify).

While I'm definitely surprised that an invokeinterface can be used on a not CHECKCAST'ed
type, I cannot find anything in the vmspec that states otherwise.

In fact, the description of invokeinterface turns out to be interesting reading. It says
that invokeinterface should throw an IncompatibleClassChangeError if the object on the
stack does not implement the resolved interface.

Comment #9 by twisti@complang.tuwien.ac.at on 2008-07-31 17:40:40

A lot of information about invokeinterface is in PR88.

Comment #10 by stefan@complang.tuwien.ac.at on 2008-07-31 18:02:01

It seems that someone will need to come up with a clever idea how to check this at
(invokeinterface) runtime then. It's sounds quite easy actually; we would just need to
check if there is a non-zero pointer at interfaceindex.

Comment #11 by stefan@complang.tuwien.ac.at on 2008-07-31 18:16:46

The "More than one matching method found: append" error happens only with the classpath
runtime, not with OpenJDK. At least we're fine there...

Comment #12 by stefan@complang.tuwien.ac.at on 2008-09-02 20:30:39

*** Bug 90 has been marked as a duplicate of this bug. ***

Comment #13 by stefan@complang.tuwien.ac.at on 2008-09-03 10:05:07

We discussed various potential solutions during yesterday's meeting.

- Probably the best way to handle this would be to make the verifier flag such "bad"
INVOKEINTERFACE instructions and generate runtime checks only for the flagged ones.
However, noone is proficient with the verifier.

- Another idea was to add a pseudo-CHECKCAST before invokeinterface which would behave
like CHECKCAST but throw the correct exception (IncompatibleClassChange).
 This was not met with much enthusiasm.

- Extending the SIGSEGV handler for this case was briefly proposed but I don't think
this is feasible.

- For a quick solution, a runtime flag could be added which would govern the creation of
runtime checks (boundary check and non-null check).

Comment #14 by stefan@complang.tuwien.ac.at on 2009-06-10 11:04:58

*** Bug 90 has been marked as a duplicate of this bug. ***