Verifier: disallow acmp & ifnull on 'uninitialized' types

XMLWordPrintable

    • Type: CSR
    • Resolution: Unresolved
    • Priority: P4
    • 27
    • Component/s: hotspot
    • None
    • binary
    • minimal
    • verifier rejects acmp or ifnull operations applied to uninitialized objects
    • Class file construct
    • SE

      Summary

      Reject class files that perform if_acmpeq, if_acmpne, ifnull, or ifnonnull on an uninitialized type.

      Problem

      An uninitialized type represents an object that has been created with new but not yet initialized with an invokespecial call to an <init> method.

      Historically, in version 50+ class files, it has been allowed to test whether two uninitialized objects are equal. The answer is almost* always obvious: if it's the same uninitialized type, then they are equal; otherwise, they are not. In older class files, the operation is rejected (that is, this behavior is specific to "verification by type checking").

      (*There is one corner case: some complex control flow could end up producing two different objects with the same new instruction, and then make it statically impossible to tell whether two matching unitialized(nn) types are equal. This is very unlikely to come up in practice.)

      It has also been historically possible, in this case for all class file versions, to test whether an uninitialized object is null. Yet, per the typing rules, it cannot be null.

      In general, the intent of the uninitialized types is to protect a freshly-allocated object from general usage until it has had a chance to be initialized. The set of supported operations is meant to be minimal. In that spirit, it is unhelpful to support the acmp and ifnull operations.

      In the future, uninitialized value objects would expose hidden internals if they were required to support acmp operations before they were initialized. This would not be tolerable. (And note that bytecode in old class files may end up operating on uninitialized value objects, so this is not a fix that can be targeted to a specific class file version.)

      Solution

      We propose removing these degrees of freedom to simplify the set of operations that need to be supported by an uninitialized object.

      A verification error will occur if an existing class file attempts to perform if_acmpeq, if_acmpne, ifnull, or ifnonnull on an uninitialized type, regardless of version number. This can almost always be addressed by simply replacing the instruction with a nop or goto.

      (We considered a similar change for monitorenter, but decided against it, because in that case there is a practical application: locking on an object before untrusted code can share it with another thread.)

      Specification

      See JVMS issue JDK-8376519.

      Modified if_acmpeq rule:

      An if_acmpeq instruction is type safe iff one can validly pop types matching ~~reference and reference~~ Object and Object on the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.

      instructionIsTypeSafe(if_acmpeq(Target), Environment, _Offset, StackFrame,
                            NextStackFrame, ExceptionStackFrame) :-
          ~~canPop(StackFrame, [reference, reference], NextStackFrame),~~
          **isBootstrapLoader(BL),**
          **objectType = class('java/lang/Object', BL),**
          **canPop(StackFrame, [objectType, objectType], NextStackFrame),**
          targetIsTypeSafe(Environment, NextStackFrame, Target),
          exceptionStackFrame(StackFrame, ExceptionStackFrame).
      

      Modified ifnonnull rule:

      An ifnonnull instruction is type safe iff one can validly pop a type matching ~~reference~~ Object off the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.

      instructionIsTypeSafe(ifnonnull(Target), Environment, _Offset, StackFrame,
                            NextStackFrame, ExceptionStackFrame) :-
          ~~canPop(StackFrame, [reference], NextStackFrame),~~
          **isBootstrapLoader(BL),**
          **canPop(StackFrame, [class('java/lang/Object', BL)], NextStackFrame),**
          targetIsTypeSafe(Environment, NextStackFrame, Target),
          exceptionStackFrame(StackFrame, ExceptionStackFrame).
      

            Assignee:
            Dan Smith
            Reporter:
            Dan Smith
            Chen Liang, Matias Saavedra Silva
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: