Skip to content

Commit f6b1c4f

Browse files
committed
Filter it down to own properties.
1 parent c1fbddc commit f6b1c4f

1 file changed

Lines changed: 50 additions & 16 deletions

File tree

crates/neon-runtime/src/napi/object.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,69 @@ pub unsafe extern "C" fn new(out: &mut Local, env: Env) {
1515
/// Mutates the `out` argument to refer to a `napi_value` containing the own property names of the
1616
/// `object` as a JavaScript Array.
1717
pub unsafe extern "C" fn get_own_property_names(out: &mut Local, env: Env, object: Local) -> bool {
18-
let status = napi::napi_get_property_names(env, object, out as *mut _);
19-
20-
if status != napi::napi_status::napi_ok {
18+
// Node.js 13+ have `napi_get_all_property_names`, which does the conversion right and allows
19+
// us to ask for only own properties or prototype properties or anything we like.
20+
// Unfortunately, earlier versions do not support that method, so we have to implement it
21+
// manually.
22+
//
23+
// So we use a temporary array for the raw names:
24+
let mut raw_names = MaybeUninit::uninit();
25+
if napi::napi_get_property_names(env, object, raw_names.as_mut_ptr()) != napi::napi_status::napi_ok {
26+
return false;
27+
}
28+
// And a "fixed" array for the actual return value:
29+
let mut fixed_names = MaybeUninit::uninit();
30+
if napi::napi_create_array(env, fixed_names.as_mut_ptr()) != napi::napi_status::napi_ok {
2131
return false;
2232
}
2333

24-
// Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
25-
// numbers for numeric indices instead of strings.
26-
let len = array::len(env, *out);
27-
for index in 0..len {
28-
let mut element: Local = std::mem::zeroed();
34+
let raw_names = raw_names.assume_init();
35+
let mut fixed_names = fixed_names.assume_init();
36+
37+
*out = fixed_names;
38+
39+
let raw_len = array::len(env, raw_names);
40+
let mut fixed_len = 0;
41+
for index in 0..raw_len {
42+
let mut property_name: Local = std::mem::zeroed();
43+
2944
// In general, getters may cause arbitrary JS code to be run, but this is a newly created
3045
// Array from an official internal API so it doesn't do anything strange.
31-
if !get_index(&mut element, env, *out, index) {
32-
continue;
33-
}
34-
if tag::is_string(env, element) {
46+
if !get_index(&mut property_name, env, raw_names, index) {
3547
continue;
3648
}
37-
let mut stringified: Local = std::mem::zeroed();
38-
// If we can't convert to a string, something went wrong.
39-
if !convert::to_string(&mut stringified, env, element) {
49+
50+
let mut is_own_property = false;
51+
// May return a non-OK status if `key` is not a string or a Symbol, but here it is always
52+
// a string.
53+
if napi::napi_has_own_property(env, object, property_name, &mut is_own_property as *mut _) != napi::napi_status::napi_ok {
4054
return false;
4155
}
56+
57+
if !is_own_property {
58+
continue;
59+
}
60+
61+
// Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
62+
// numbers for numeric indices instead of strings.
63+
// Make sure we always return strings.
64+
let property_name = if !tag::is_string(env, property_name) {
65+
let mut stringified: Local = std::mem::zeroed();
66+
// If we can't convert to a string, something went wrong.
67+
if !convert::to_string(&mut stringified, env, property_name) {
68+
return false;
69+
}
70+
stringified
71+
} else {
72+
property_name
73+
};
74+
4275
let mut dummy = false;
4376
// If we can't convert assign to this array, something went wrong.
44-
if !set_index(&mut dummy, env, *out, index, stringified) {
77+
if !set_index(&mut dummy, env, fixed_names, fixed_len, property_name) {
4578
return false;
4679
}
80+
fixed_len += 1;
4781
}
4882

4983
true

0 commit comments

Comments
 (0)