From 49cd3d97a849a2a110bf12754640c277a7b88d2a Mon Sep 17 00:00:00 2001 From: farwayer Date: Sat, 21 Feb 2026 03:43:57 +0100 Subject: [PATCH 1/2] fix uint64_t underflow inside Array::arrayPrototypeSplice --- lib/VM/JSLib/Array.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/VM/JSLib/Array.cpp b/lib/VM/JSLib/Array.cpp index b9c11c33ac3..8b4d3f56bbe 100644 --- a/lib/VM/JSLib/Array.cpp +++ b/lib/VM/JSLib/Array.cpp @@ -2691,19 +2691,18 @@ CallResult arrayPrototypeSplice(void *, Runtime &runtime) { gcScope.flushToMarker(gcMarker); } - // Use i here to refer to (k-1) in the spec, and reindex the loop. - double i = len - 1; + // (len - actualDeleteCount + itemCount) >= 0 so k never underflow + uint64_t k = len; // Delete the remaining elements from the right that we didn't copy into. - while (i > (len - actualDeleteCount + itemCount - 1)) { - lv.i = HermesValue::encodeTrustedNumberValue(i); + while (k-- > len - actualDeleteCount + itemCount) { + lv.i = HermesValue::encodeTrustedNumberValue(k); if (LLVM_UNLIKELY( JSObject::deleteComputed( lv.O, runtime, lv.i, PropOpFlags().plusThrowOnError()) == ExecutionStatus::EXCEPTION)) { return ExecutionStatus::EXCEPTION; } - i -= 1; gcScope.flushToMarker(gcMarker); } } else if (itemCount > actualDeleteCount) { From 372f41a49b3efda3b88208ca3be475332c1fe237 Mon Sep 17 00:00:00 2001 From: farwayer Date: Wed, 4 Mar 2026 14:56:05 +0100 Subject: [PATCH 2/2] add regress test --- test/hermes/regress-array-splice.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/hermes/regress-array-splice.js diff --git a/test/hermes/regress-array-splice.js b/test/hermes/regress-array-splice.js new file mode 100644 index 00000000000..8a2f22fac27 --- /dev/null +++ b/test/hermes/regress-array-splice.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// RUN: %hermes -O %s | %FileCheck --match-full-lines %s + +print("splice"); +// CHECK: splice + +let removed = []; +let arr = new Proxy([], { + deleteProperty(target, p) { + removed.push(p); + return Reflect.deleteProperty(target, p); + }, +}); + +arr.push('a', 'b', 'c'); +arr.splice(0); +print(removed); +// CHECK-NEXT: 2,1,0