Uploaded image for project: 'Commons BCEL'
  1. Commons BCEL
  2. BCEL-135

BCELifier issue: BCELFactory fails to handle float and long constants

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Blocker
    • Resolution: Fixed
    • 5.2
    • 6.0
    • Main
    • None

    Description

      BCELifier calls BCELFactory. The BCELFactory.createConstant method does not
      handle floats and longs correctly:

      private void createConstant( Object value ) {
      String embed = value.toString();
      if (value instanceof String)

      { embed = '"' + Utility.convertString(embed) + '"'; } else if (value instanceof Character) { embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); }
      _out.println("il.append(new PUSH(_cp, " + embed + "));");
      }

      Note that the types String and char are handled separately. As for the other
      types, it's relying on there being an overloaded constructor of PUSH that takes
      the constant in its correct form once it is converted to a String.

      Let's examine all the other types:

      - boolean: Boolean.toString() produces the values "true" and "false", which
      javac picks up as booleans, e.g. "new PUSH(_cp, false)".

      - byte, short, int: Integer.toString() produces valid values. In the
      bytecode, there is no (significant) distinction between these types (except for
      method signatures, fields, etc.).

      - double: Double.toString() produces valid values, e.g. "new PUSH(_cp, 0.0)".

      - float: Float.toString() produces values that look like doubles, e.g. "new
      PUSH(_cp, 0.0)". These are mishandled.

      - long: Long.toString() produces values that look like ints, e.g. "new
      PUSH(_cp, 0)", or, even worse, "new PUSH(_cp, 4000000000)" (which doesn't
      compile).


      I've attached two simple test cases that illustrate the issues. Do the
      following with BCEL-5.2.jar on your classpath:

      % javac TestIncorrectLiterals.java
      % java TestIncorrectLiterals
      % java org.apache.bcel.util.BCELifier TestIncorrectLiterals
      >TestIncorrectLiteralsCreator.java
      % javac TestIncorrectLiteralsCreator.java
      % java TestIncorrectLiteralsCreator
      % java TestIncorrectLiterals
      Exception in thread "main" java.lang.VerifyError: (class:
      TestIncorrectLiterals, method: main signature: ([Ljava/lang/String;)V)
      Expecting to find float on stack


      % javac TestOutOfRangeLiterals.java
      % java TestOutOfRangeLiterals
      % java org.apache.bcel.util.BCELifier TestOutOfRangeLiterals
      >TestOutOfRangeLiteralsCreator.java
      % javac TestOutOfRangeLiteralsCreator.java
      TestOutOfRangeLiteralsCreator.java:41: integer number too large: 4000000000
      InstructionHandle ih_0 = il.append(new PUSH(_cp, 4000000000));
      ^
      1 error


      Here's my suggested fix:

      private void createConstant( Object value ) {
      String embed = value.toString();
      if (value instanceof String) { embed = '"' + Utility.convertString(embed) + '"'; }

      else if (value instanceof Character)

      { embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); }

      else if (value instanceof Float)

      { embed += "f"; }

      else if (value instanceof Long)

      { embed += "L"; }

      _out.println("il.append(new PUSH(_cp, " + embed + "));");
      }

      I shall test out this fix, and report back.

      This issue seems to exist in the SVN trunk code too.

      Attachments

        1. TestIncorrectLiterals.java
          0.3 kB
          Matthew Wilson
        2. TestOutOfRangeLiterals.java
          0.2 kB
          Matthew Wilson

        Activity

          People

            issues@commons.apache.org Apache Commons Developers
            mj.wilson.uk@googlemail.com Matthew Wilson
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: