Skip to content

Commit 5c3787f

Browse files
committed
[GR-33742] Avoiding ClassCastException when an enumerator does not return an array.
PullRequest: js/2146
2 parents 4a8eceb + b64a14b commit 5c3787f

File tree

3 files changed

+57
-12
lines changed

3 files changed

+57
-12
lines changed

graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/node/ExecuteNativePropertyHandlerNode.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -321,23 +321,25 @@ private Object executeOwnKeys(Object holder, Object[] arguments) {
321321
}
322322
if (indexedHandler != null && indexedHandler.getEnumerator() != 0) {
323323
DynamicObject ownKeys2 = (DynamicObject) NativeAccess.executePropertyHandlerEnumerator(indexedHandler.getEnumerator(), holder, nativeCallArgs, indexedHandlerData);
324-
// indexed handler returns array of numbers but we need an array of property keys
325-
long length = JSAbstractArray.arrayGetLength(ownKeys2);
326-
for (long i = 0; i < length; i++) {
327-
Object key = JSObject.get(ownKeys2, i);
328-
JSObject.set(ownKeys2, i, JSRuntime.toString(key));
324+
if (JSArray.isJSArray(ownKeys2)) {
325+
// indexed handler returns array of numbers but we need an array of property keys
326+
long length = JSAbstractArray.arrayGetLength(ownKeys2);
327+
for (long i = 0; i < length; i++) {
328+
Object key = JSObject.get(ownKeys2, i);
329+
JSObject.set(ownKeys2, i, JSRuntime.toString(key));
330+
}
331+
ownKeys = concatArrays(ownKeys, ownKeys2);
329332
}
330-
ownKeys = concatArrays(ownKeys, ownKeys2);
331333
}
332-
if (ownKeys == null) {
334+
if (!JSArray.isJSArray(ownKeys)) {
333335
ownKeys = JSArray.createEmpty(context, getRealm(), 0);
334336
}
335337
return ownKeys;
336338
}
337339

338340
private DynamicObject concatArrays(DynamicObject array1, DynamicObject array2) {
339-
if (JSRuntime.isArray(array1)) {
340-
if (JSRuntime.isArray(array2)) {
341+
if (JSArray.isJSArray(array1)) {
342+
if (JSArray.isJSArray(array2)) {
341343
List<Object> keys = new ArrayList<>(Arrays.asList(JSArray.toArray(array1)));
342344
for (Object key : JSArray.toArray(array2)) {
343345
if (!keys.contains(key)) {

graal-nodejs/test/graal/unit/object_template.cc

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -45,6 +45,7 @@
4545

4646
void SimpleAccessorGetter(Local<Name> property, const PropertyCallbackInfo<Value>& info);
4747
void SimpleAccessorSetter(Local<Name> property, Local<Value> value, const PropertyCallbackInfo<void>& info);
48+
void EmptyPropertyEnumeratorCallback(const PropertyCallbackInfo<Array>& info) {};
4849

4950
#endif
5051

@@ -128,4 +129,38 @@ EXPORT_TO_JS(CheckNamedHandlerWithInternalFields) {
128129
args.GetReturnValue().Set(expectedCount == actualCount);
129130
}
130131

132+
EXPORT_TO_JS(CreateWithEmptyIndexedEnumerator) {
133+
Isolate* isolate = args.GetIsolate();
134+
Local<ObjectTemplate> objectTemplate = ObjectTemplate::New(isolate);
135+
IndexedPropertyHandlerConfiguration handler(
136+
nullptr, // getter
137+
nullptr, // setter
138+
nullptr, // query
139+
nullptr, // deleter
140+
EmptyPropertyEnumeratorCallback // enumerator
141+
);
142+
objectTemplate->SetHandler(handler);
143+
144+
Local<Context> context = isolate->GetCurrentContext();
145+
Local<Object> instance = objectTemplate->NewInstance(context).ToLocalChecked();
146+
args.GetReturnValue().Set(instance);
147+
}
148+
149+
EXPORT_TO_JS(CreateWithEmptyNamedEnumerator) {
150+
Isolate* isolate = args.GetIsolate();
151+
Local<ObjectTemplate> objectTemplate = ObjectTemplate::New(isolate);
152+
NamedPropertyHandlerConfiguration handler(
153+
nullptr, // getter
154+
nullptr, // setter
155+
nullptr, // query
156+
nullptr, // deleter
157+
EmptyPropertyEnumeratorCallback // enumerator
158+
);
159+
objectTemplate->SetHandler(handler);
160+
161+
Local<Context> context = isolate->GetCurrentContext();
162+
Local<Object> instance = objectTemplate->NewInstance(context).ToLocalChecked();
163+
args.GetReturnValue().Set(instance);
164+
}
165+
131166
#undef SUITE

graal-nodejs/test/graal/unit/object_template.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -83,6 +83,14 @@ describe('ObjectTemplate', function () {
8383
it('should create object with the specified internal field count', function () {
8484
var result = module.ObjectTemplate_CheckNamedHandlerWithInternalFields();
8585
assert.ok(result);
86-
});
86+
});
87+
it('should not crash with an empty named enumerator', function () {
88+
var obj = module.ObjectTemplate_CreateWithEmptyNamedEnumerator();
89+
assert.strictEqual(Object.keys(obj).length, 0);
90+
});
91+
it('should not crash with an empty indexed enumerator', function () {
92+
var obj = module.ObjectTemplate_CreateWithEmptyIndexedEnumerator();
93+
assert.strictEqual(Object.keys(obj).length, 0);
94+
});
8795
});
8896
});

0 commit comments

Comments
 (0)