Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8336430

Inconsistent NPE behaviour of `Utf8Entry::equalsString`

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • 24
    • 23
    • core-libs

      A DESCRIPTION OF THE PROBLEM :
      Currently, when `Utf8Entry::equalsString` is called with a `null` value, then it only sometimes throws `NullPointerException`.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached Java program.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      ```
      State.STRING: false
      State.RAW: false
      State.BYTE: false
      State.CHAR: false
      ```
      or
      ```
      State.STRING: java.lang.NullPointerException
      State.RAW: java.lang.NullPointerException
      State.BYTE: java.lang.NullPointerException
      State.CHAR: java.lang.NullPointerException
      ```
      ACTUAL -
      ```
      State.STRING: false
      State.RAW: java.lang.NullPointerException
      State.BYTE: java.lang.NullPointerException
      State.CHAR: java.lang.NullPointerException
      ```

      ---------- BEGIN SOURCE ----------
      /*
       * Any copyright is dedicated to the Public Domain.
       * https://creativecommons.org/publicdomain/zero/1.0/
       */

      import java.lang.classfile.*;
      import java.lang.classfile.attribute.*;
      import java.lang.classfile.constantpool.*;
      import java.lang.constant.ClassDesc;
      import java.util.List;
      import java.util.Locale;

      import static java.lang.classfile.ClassFile.*;
      import static java.lang.constant.ConstantDescs.*;
      import static java.util.Objects.requireNonNullElse;

      public final class Utf8EntryEqualsStringTest {
      record TestCase(
      String label,
      Utf8Entry entry
      ) implements Runnable {
      @Override
      public void run() {
      Boolean result = null;
      Exception ex = null;

      try {
      result = entry.equalsString(null);
      } catch (final Exception e) {
      ex = e;
      }

      System.out.printf(
      Locale.ROOT,
      "%-12s\t%s%n",
      label,
      requireNonNullElse(ex, result).toString()
      );
      }
      }

      private static final String State_STRING = "State.STRING";
      private static final String State_RAW = "State.RAW";
      private static final String State_BYTE = "State.BYTE";
      private static final String State_CHAR = "State.CHAR";

      public static final void main(final String... args) {
      final var testCases = prepareUtf8Entries(ClassFile.of());
      for (final var testCase : testCases) {
      testCase.run();
      }
      }

      private static final List<TestCase> prepareUtf8Entries(final ClassFile cf) {
      final var cm = cf.parse(cf.build(ClassDesc.of(DEFAULT_NAME), cb -> {
      withConstant(cb, State_RAW, "raw");
      withConstant(cb, State_BYTE, "byte");
      withConstant(cb, State_CHAR, "π (\u03C0)");
      }));

      Utf8Entry
      stateString,
      stateRaw = null,
      stateByte = null,
      stateChar = null;

      for (final var field : cm.fields()) {
      switch (field.fieldName().stringValue()) {
      case State_RAW -> {
      stateRaw = getStringConstantValue(field);
      }
      case State_BYTE -> {
      stateByte = getStringConstantValue(field);
      stateByte.length();
      }
      case State_CHAR -> {
      stateChar = getStringConstantValue(field);
      stateChar.length();
      }
      }
      }

      stateString = (Utf8Entry) AnnotationValue.ofString("string").constant();

      return List.of(
      new TestCase(State_STRING + ':', stateString),
      new TestCase(State_RAW + ':', stateRaw),
      new TestCase(State_BYTE + ':', stateByte),
      new TestCase(State_CHAR + ':', stateChar)
      );
      }

      private static final void withConstant(final ClassBuilder cb, final String name, final String value) {
      cb.withField(name, CD_String, fb -> {
      fb.withFlags(ACC_STATIC | ACC_FINAL);
      fb.with(ConstantValueAttribute.of(value));
      });
      }

      private static final Utf8Entry getStringConstantValue(final FieldModel field) {
      var constantValueAttr = (ConstantValueAttribute) field.elementStream()
      .filter(e -> e instanceof ConstantValueAttribute)
      .reduce((_, _) -> { throw new IllegalStateException(field.toString()); })
      .orElseThrow(() -> new IllegalArgumentException(field.toString()));

      return ((StringEntry) constantValueAttr.constant()).utf8();
      }
      }
      ---------- END SOURCE ----------

      FREQUENCY : always


            asotona Adam Sotona
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: