Previously, njs_value_to_primitive() retained a pointer to the caller's value
slot while valueOf(), toString(), or property getters executed user code.
Reentrant code could overwrite that slot, after which the conversion treated
the replacement primitive as the original object.
The fix is to snapshot the input value before the first observable property
lookup and use the stable copy throughout conversion.
The issue was introduced in
64dbf104 (0.3.4).
This closes #1094 issue on GitHub.
{
njs_int_t ret;
njs_uint_t tries, force_ordinary;
- njs_value_t method, retval, arguments[2];
+ njs_value_t input, method, retval, arguments[2];
njs_flathsh_query_t fhq;
static const uint32_t atoms[] = {
return NJS_OK;
}
+ input = *value;
+ value = &input;
+
tries = 0;
fhq.proto = &njs_object_hash_proto;
{ njs_str("false.__proto__ === Boolean.prototype"),
njs_str("true") },
+ { njs_str("var o = {valueOf() { o = 0; return {}; },"
+ " toString() { return '7'; }}; +o"),
+ njs_str("7") },
+
+ { njs_str("var original = {toString() { return '7'; }}, o = original;"
+ "Object.defineProperty(original, 'valueOf', {get() {"
+ " o = 0; return () => ({}); }}); +o"),
+ njs_str("7") },
+
{ njs_str("var b = Boolean(1); b.__proto__ === Boolean.prototype"),
njs_str("true") },