Skip to content

Commit

Permalink
chakrashim: Fix GetOwnPropertyNames and GetPropertyNames
Browse files Browse the repository at this point in the history
As per spec `Object.getOwnPropertyNames()` and
`Object.getPropertyNames()` should return an array of strings.
However there is no standardization of what should happen if
these methods are called natively (through NaN for example).

For these 2 APIs, v8 returns an array containing mix of numbers
for numeric properties and strings for normal string properties.
This breaks [grpc](https://github.com/grpc/grpc) module because it
[expects](https://github.com/grpc/grpc/blob/master/src/node/ext/call.cc#L673-L683) returned values to be numeric.

Fix: Once we get the result from, iterate over the result and call
`parseInt` to save numeric value of the key.

PR-URL: nodejs/node#169
Reviewed-By: Jianchun Xu <[email protected]>
  • Loading branch information
kunalspathak committed Jan 23, 2017
1 parent 8e66382 commit 9716837
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 10 deletions.
29 changes: 25 additions & 4 deletions deps/chakrashim/lib/chakra_shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
Set_entries = Set.prototype.entries,
Set_values = Set.prototype.values,
Symbol_keyFor = Symbol.keyFor,
Symbol_for = Symbol.for;
Symbol_for = Symbol.for,
Global_ParseInt = parseInt;
var BuiltInError = Error;
var global = this;

Expand Down Expand Up @@ -276,7 +277,7 @@
Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError,
URIError
].forEach(function(type) {
var newType = function __newType() {
var newType = function newType() {
var e = withStackTraceLimitOffset(
3, () => Reflect_construct(type, arguments, new.target || newType));
// skip 3 frames: lambda, withStackTraceLimitOffset, this frame
Expand Down Expand Up @@ -428,7 +429,7 @@
var microTasks = [];

function patchUtils(utils) {
var isUintRegex = /^(0|[1-9]\\d*)$/;
var isUintRegex = /^(0|[1-9]\d*)$/;

var isUint = function(value) {
var result = isUintRegex.test(value);
Expand All @@ -449,7 +450,11 @@
utils.getPropertyNames = function(a) {
var names = [];
for (var propertyName in a) {
names.push(propertyName);
if (isUint(propertyName)) {
names.push(Global_ParseInt(propertyName));
} else {
names.push(propertyName);
}
}
return names;
};
Expand Down Expand Up @@ -588,6 +593,22 @@
}
return attributes;
};
utils.getOwnPropertyNames = function(obj) {
var ownPropertyNames = Object_getOwnPropertyNames(obj);
var i = 0;
while (i < ownPropertyNames.length) {
var item = ownPropertyNames[i];
if (isUint(item)) {
ownPropertyNames[i] = Global_ParseInt(item);
i++;
continue;
}
// As per spec, getOwnPropertyNames() first include
// numeric properties followed by non-numeric
break;
}
return ownPropertyNames;
};
}

patchErrorTypes();
Expand Down
1 change: 1 addition & 0 deletions deps/chakrashim/src/jsrtcachedpropertyidref.inc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ DEF(enqueueMicrotask)
DEF(dequeueMicrotask)
DEF(saveInHandleScope)
DEF(getPropertyAttributes)
DEF(getOwnPropertyNames)
DEF(getFunctionName)
DEF(getFileName)
DEF(getColumnNumber)
Expand Down
4 changes: 3 additions & 1 deletion deps/chakrashim/src/jsrtcontextshim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ ContextShim::ContextShim(IsolateShim * isolateShim,
ensureDebugFunction(JS_INVALID_REFERENCE),
enqueueMicrotaskFunction(JS_INVALID_REFERENCE),
dequeueMicrotaskFunction(JS_INVALID_REFERENCE),
getPropertyAttributesFunction(JS_INVALID_REFERENCE) {
getPropertyAttributesFunction(JS_INVALID_REFERENCE),
getOwnPropertyNamesFunction(JS_INVALID_REFERENCE) {
memset(globalConstructor, 0, sizeof(globalConstructor));
memset(globalPrototypeFunction, 0, sizeof(globalPrototypeFunction));
}
Expand Down Expand Up @@ -613,6 +614,7 @@ CHAKRASHIM_FUNCTION_GETTER(ensureDebug)
CHAKRASHIM_FUNCTION_GETTER(enqueueMicrotask);
CHAKRASHIM_FUNCTION_GETTER(dequeueMicrotask);
CHAKRASHIM_FUNCTION_GETTER(getPropertyAttributes);
CHAKRASHIM_FUNCTION_GETTER(getOwnPropertyNames);

#define DEF_IS_TYPE(F) CHAKRASHIM_FUNCTION_GETTER(F)
#include "jsrtcachedpropertyidref.inc"
Expand Down
3 changes: 2 additions & 1 deletion deps/chakrashim/src/jsrtcontextshim.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ContextShim {
};

static ContextShim * New(IsolateShim * isolateShim, bool exposeGC,
bool useGlobalTTState,
bool useGlobalTTState,
JsValueRef globalObjectTemplateInstance);
~ContextShim();
void EnsureInitialized();
Expand Down Expand Up @@ -156,6 +156,7 @@ private: \
DECLARE_CHAKRASHIM_FUNCTION_GETTER(enqueueMicrotask);
DECLARE_CHAKRASHIM_FUNCTION_GETTER(dequeueMicrotask);
DECLARE_CHAKRASHIM_FUNCTION_GETTER(getPropertyAttributes);
DECLARE_CHAKRASHIM_FUNCTION_GETTER(getOwnPropertyNames);
};

} // namespace jsrt
12 changes: 8 additions & 4 deletions deps/chakrashim/src/v8object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,17 @@ Local<Array> Object::GetPropertyNames() {
}

MaybeLocal<Array> Object::GetOwnPropertyNames(Local<Context> context) {
JsValueRef arrayRef;
ContextShim* contextShim = ContextShim::GetCurrent();
JsValueRef getOwnPropertyNamesFunction =
contextShim->GetgetOwnPropertyNamesFunction();

JsValueRef result;

if (JsGetOwnPropertyNames((JsValueRef)this, &arrayRef) != JsNoError) {
if (jsrt::CallFunction(getOwnPropertyNamesFunction, (JsValueRef)this,
&result) != JsNoError) {
return Local<Array>();
}

return Local<Array>::New(arrayRef);
return Local<Array>::New(result);
}

Local<Array> Object::GetOwnPropertyNames() {
Expand Down

0 comments on commit 9716837

Please sign in to comment.