value = &entry;
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), NJS_STRING_MAX_LENGTH);
for (i = 0; i < len; i++) {
ret = njs_value_property_i64(vm, this, i, value);
size = njs_chb_size(&chain);
if (njs_slow_path(size < 0)) {
- njs_memory_error(vm);
+ if (chain.error == NJS_CHB_ERR_OVERFLOW) {
+ njs_range_error(vm, "invalid string length");
+
+ } else {
+ njs_memory_error(vm);
+ }
+
return NJS_ERROR;
}
goto memory_error;
}
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(stringify->vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(stringify->vm),
+ NJS_STRING_MAX_LENGTH);
for ( ;; ) {
if (state->index == 0) {
size = njs_chb_size(&chain);
if (njs_slow_path(size < 0)) {
+ if (chain.error == NJS_CHB_ERR_OVERFLOW) {
+ njs_range_error(stringify->vm, "invalid string length");
+
+ } else {
+ njs_memory_error(stringify->vm);
+ }
+
njs_chb_destroy(&chain);
- goto memory_error;
+
+ return NJS_ERROR;
}
if (size == 0) {
ret = njs_string_create_chb(stringify->vm, retval, &chain);
if (njs_slow_path(ret != NJS_OK)) {
njs_chb_destroy(&chain);
- goto memory_error;
+ return NJS_ERROR;
}
release:
}
}
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), NJS_STRING_MAX_LENGTH);
results.separate = 0;
results.pointer = 0;
p = rep.start;
end = rep.start + rep.length;
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), NJS_STRING_MAX_LENGTH);
while (p < end) {
r = njs_strlchr(p, end, '$');
return NJS_OK;
}
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), NJS_STRING_MAX_LENGTH);
start = string.start;
src = string.start;
end = string.start + string.size;
+ /*
+ * Percent-decoding never produces more bytes than it consumes and
+ * the input is a string within NJS_STRING_MAX_LENGTH, so the chain
+ * needs no byte cap.
+ */
NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
njs_utf8_decode_init(&ctx);
len = njs_base64_decoded_length(len, pad);
+ /*
+ * The chain holds a single reservation of at most twice the decoded
+ * length, which is bounded by the input string size, so it cannot
+ * grow unbounded and needs no byte cap.
+ */
NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
dst = njs_chb_reserve(&chain, len * 2);
return NJS_ERROR;
}
- NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));
+ NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), NJS_STRING_MAX_LENGTH);
njs_typed_array_to_chain(vm, &chain, array, separator);
"String.prototype.concat.apply(s, a.slice(1))"),
njs_str("RangeError: invalid string length") },
+#if (NJS_64BIT)
+ /*
+ * Adversarial regex replace must throw RangeError instead of
+ * OOM-killing the process. The chain accumulates ~2GiB before the
+ * cap trips, hence 64-bit only.
+ */
+ { njs_str("var s = 'x'.repeat(1 << 18);"
+ "var r = '$1'.repeat(1 << 14);"
+ "s.replace(/(.+)/g, r)"),
+ njs_str("RangeError: invalid string length") },
+#endif
+
{ njs_str("var a = 'abcdefgh'; a.substr(3, 15)"),
njs_str("defgh") },