Skip to content

fix: handle primitive arrays in 'in' operator and .length field access - #461

Open
chenjunwenhao wants to merge 1 commit into
alibaba:mainfrom
chenjunwenhao:fix/primitive-array-classcastexception
Open

fix: handle primitive arrays in 'in' operator and .length field access#461
chenjunwenhao wants to merge 1 commit into
alibaba:mainfrom
chenjunwenhao:fix/primitive-array-classcastexception

Conversation

@chenjunwenhao

Copy link
Copy Markdown
Contributor

Summary

Fix ClassCastException when the in operator or .length field access encounters primitive arrays (byte[], int[], char[], double[], etc.) returned by Java methods or passed via execution context.

Problem

Two locations in the codebase cast arrays directly to Object[], which crashes for primitive arrays:

  1. BaseBinaryOperator.inOperator() (line 316):

    Object[] rightArray = (Object[])rightOperand;  // crashes for byte[], int[], etc.
  2. ReflectLoader.loadField() (line 85):

    return new DataValue(((Object[])bean).length);  // crashes for byte[], int[], etc.

While QLExpress's new int[]{} syntax creates Integer[] internally (via BuiltInTypesSet), primitive arrays from Java method returns (e.g., String.getBytes()byte[], String.toCharArray()char[]) or context variables trigger this crash.

Reproduction:

Express4Runner runner = new Express4Runner();
// Crashes with: ClassCastException: class [B cannot be cast to class [Ljava.lang.Object;
runner.execute("65 in \"ABC\".getBytes()", Collections.emptyMap(), QLOptions.DEFAULT_OPTIONS);
runner.execute("bytes = \"hello\".getBytes(); return bytes.length;", Collections.emptyMap(), QLOptions.DEFAULT_OPTIONS);

Fix

Use java.lang.reflect.Array.getLength() and Array.get() instead of Object[] cast. This is consistent with other array-handling code in the codebase (ForEachInstruction, IndexInstruction, SliceInstruction, SpreadGetFieldInstruction, etc.), all of which correctly use java.lang.reflect.Array for array operations.

Tests

Added two test suite files:

  • testsuite/java/operator/in_primitive_array.ql — tests in and not_in with byte[] from String.getBytes()
  • testsuite/java/property/primitive_array_length.ql — tests .length with byte[] from String.getBytes() and char[] from String.toCharArray()

Verified that:

  • Tests fail with ClassCastException before the fix
  • Tests pass after the fix

The `in` operator (BaseBinaryOperator.inOperator) and array `.length`
field access (ReflectLoader.loadField) both cast arrays to Object[],
which throws ClassCastException for primitive arrays (int[], byte[],
char[], double[], etc.).

While QLExpress's `new int[]{}` syntax creates Integer[] internally
(via BuiltInTypesSet), primitive arrays from Java method returns
(e.g. String.getBytes() → byte[], String.toCharArray() → char[])
or context variables trigger this crash.

Fix: use java.lang.reflect.Array.getLength() and Array.get() instead
of Object[] cast, consistent with other array-handling code in the
codebase (ForEachInstruction, IndexInstruction, SliceInstruction, etc.).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant