Bug: ClassCastException for arguments variable (plain JavaScript)
Esben Andreasen
esben at esbena.dk
Thu Sep 15 13:02:02 UTC 2016
Nashorn can produce a ClassCastException when executing a plain
JavaScript program.
The exception happens in a situation where the arguments variable is
used in conjunction with call and apply.
## Observed behavior
Code:
```
function F(SOME_PARAMETER) {
Function.prototype.call.apply(G, arguments);
}
function G(){
this;
F("SOME_ARGUMENT");
}
G();
```
Execution:
```
$ jjs -version test.js
nashorn 1.8.0_101
Exception in thread "main" java.lang.ClassCastException: Cannot cast
jdk.nashorn.internal.objects.NativeArguments to [Ljava.lang.Object;
at
java.lang.invoke.MethodHandleImpl.newClassCastException(MethodHandleImpl.java:361)
at
java.lang.invoke.MethodHandleImpl.castReference(MethodHandleImpl.java:356)
...
```
## Expected behavior
Something else than a ClassCastException. Especially since the program
is plain JavaScript.
The minimal example will produce a 'RangeError: Maximum call stack
size exceeded' and 'InternalError: too much recursion' on Chrome/Node
and Firefox respectively.
## Thoughts
The stack trace reveal that the arguments object is being cast to an
array of objects, that seems wrong.
According to ECMA262-5.1 for Function.prototype.apply, the numeric
entries of the second argument should be iterated, if that argument is
array-like. It looks like Nashorn just assumes it is an array already,
and does the corresponding cast.
The minimal example requires several surprising elements that should
have no effect on the behavior of the program. But the
ClassCastException disappear if one of them is removed.
- the `this` variable in G
- the unused `"SOME_ARGUMENT"` argument in G
- the unused `SOME_PARAMETER` parameter name in F
- the use use of `call.apply` in F, it should be rewritable to just `apply`
## Regression test
The minimal example has been extended with a counter to avoid the
stack overflow in other engines.
```
var i = 0;
function F(SOME_PARAMETER) {
if(i++ > 3){
return;
}
Function.prototype.call.apply(G, arguments);
}
function G(){
this;
F("SOME_ARGUMENT");
}
G();
```
-
Esben
More information about the nashorn-dev
mailing list