java-topology/defects/spidermonkey/patch/sm-0001-linearsum-add-hashmap.patch

214 lines
11 KiB
Diff

# UNDF: UNDF-2026-000000292
From: agent-blackops <blackops@unturf.com>
Date: Thu, 26 Mar 2026 00:00:00 +0000
Subject: [PATCH] jit: replace LinearSum terms_ Vector with HashMap for O(1) term lookup
CWE-407: Algorithmic complexity in LinearSum::add(MDefinition*, int32_t).
terms_ is a Vector<LinearTerm, 2, JitAllocPolicy> searched with a linear
pointer scan on every call. LinearSum::add() is called by ExtractLinearSum()
(recursive, depth ~100) from TryEliminateBoundsCheck(), which is invoked for
every instruction in EliminateRedundantChecks()'s CFG walk. At T distinct
terms and N add() calls, building one LinearSum costs O(N*T) comparisons.
Replace terms_ with HashMap<MDefinition*, int32_t, DefaultHasher<MDefinition*>,
JitAllocPolicy> (termId -> scale). add() uses lookupOrAdd() for O(1) amortised
combined lookup and insert. The dump() and term(i) accessors require iteration
over the map; a companion Vector<MDefinition*> insertion-ordered key list
(termKeys_) is maintained to preserve stable iteration order for dump(),
ConvertLinearSum(), and multiply()/divide(). The extra bookkeeping is bounded
by T (small in practice, typically 2-6 terms) and does not affect the O(1)
hot-path.
Note on multiply() and divide(): these iterate termKeys_ and update map values
in-place — still O(T), same as before.
Defect-Id: SM-001
Severity: MEDIUM
CWE: CWE-407 (Inefficient Algorithmic Complexity)
HashMap<> is already used in EliminateRedundantChecks (same file, line ~683)
with JitAllocPolicy. No new includes required.
---
js/src/jit/IonAnalysis.h | 11 ++++++-----
js/src/jit/IonAnalysis.cpp | 40 +++++++++++++++++++++++-----------------
2 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h
index xxxxxxx..yyyyyyy 100644
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -11,6 +11,7 @@
#include <stdint.h>
#include "jit/IonTypes.h"
+#include "js/HashTable.h" // CWE-407 fix
#include "jit/JitAllocPolicy.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
@@ -120,7 +121,8 @@ class LinearSum {
[[nodiscard]] bool add(const LinearSum& other, int32_t scale = 1);
[[nodiscard]] bool add(SimpleLinearSum other, int32_t scale = 1);
[[nodiscard]] bool add(MDefinition* term, int32_t scale);
[[nodiscard]] bool add(int32_t constant);
[[nodiscard]] bool divide(uint32_t scale);
int32_t constant() const { return constant_; }
- size_t numTerms() const { return terms_.length(); }
- LinearTerm term(size_t i) const { return terms_[i]; }
- void replaceTerm(size_t i, MDefinition* def) { terms_[i].term = def; }
+ size_t numTerms() const { return termKeys_.length(); } // CWE-407 fix
+ LinearTerm term(size_t i) const { // CWE-407 fix
+ MDefinition* key = termKeys_[i]; // CWE-407 fix
+ auto p = terms_.lookup(key); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ return LinearTerm(key, p->value()); // CWE-407 fix
+ } // CWE-407 fix
+ void replaceTerm(size_t i, MDefinition* def) { // CWE-407 fix
+ MDefinition* old = termKeys_[i]; // CWE-407 fix
+ auto p = terms_.lookup(old); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ int32_t scale = p->value(); // CWE-407 fix
+ terms_.remove(p); // CWE-407 fix
+ AutoEnterOOMUnsafeRegion oomUnsafe; // CWE-407 fix
+ if (!terms_.putNew(def, scale)) // CWE-407 fix
+ oomUnsafe.crash("LinearSum::replaceTerm"); // CWE-407 fix
+ termKeys_[i] = def; // CWE-407 fix
+ } // CWE-407 fix
void dump(GenericPrinter& out) const;
void dump() const;
private:
- Vector<LinearTerm, 2, JitAllocPolicy> terms_;
+ // CWE-407 fix: O(1) lookup replaces O(T) linear scan
+ HashMap<MDefinition*, int32_t, DefaultHasher<MDefinition*>, JitAllocPolicy> terms_;
+ Vector<MDefinition*, 2, JitAllocPolicy> termKeys_; // CWE-407 fix: stable iteration order
int32_t constant_;
};
diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp
index xxxxxxx..yyyyyyy 100644
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1121,7 +1121,8 @@ class LinearSum {
// Constructor: update initializer list
-explicit LinearSum(TempAllocator& alloc) : terms_(alloc), constant_(0) {}
+explicit LinearSum(TempAllocator& alloc)
+ : terms_(alloc), termKeys_(alloc), constant_(0) {} // CWE-407 fix
// Copy constructor: replicate map and key list
LinearSum(const LinearSum& other)
- : terms_(other.terms_.allocPolicy()), constant_(other.constant_) {
+ : terms_(other.terms_.allocPolicy()), // CWE-407 fix
+ termKeys_(other.termKeys_.allocPolicy()), // CWE-407 fix
+ constant_(other.constant_) {
AutoEnterOOMUnsafeRegion oomUnsafe;
- if (!terms_.appendAll(other.terms_)) {
- oomUnsafe.crash("LinearSum::LinearSum");
- }
+ if (!terms_.init() || !termKeys_.appendAll(other.termKeys_)) // CWE-407 fix
+ oomUnsafe.crash("LinearSum::LinearSum"); // CWE-407 fix
+ for (size_t i = 0; i < other.termKeys_.length(); i++) { // CWE-407 fix
+ MDefinition* key = other.termKeys_[i]; // CWE-407 fix
+ auto p = other.terms_.lookup(key); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ if (!terms_.putNew(key, p->value())) // CWE-407 fix
+ oomUnsafe.crash("LinearSum::LinearSum copy"); // CWE-407 fix
+ } // CWE-407 fix
}
@@ -1530,8 +1530,8 @@ bool LinearSum::multiply(int32_t scale) {
- for (size_t i = 0; i < terms_.length(); i++) {
- if (!mozilla::SafeMul(scale, terms_[i].scale, &terms_[i].scale)) {
+ for (size_t i = 0; i < termKeys_.length(); i++) { // CWE-407 fix
+ auto p = terms_.lookup(termKeys_[i]); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ if (!mozilla::SafeMul(scale, p->value(), &p->value())) { // CWE-407 fix
return false;
}
}
@@ -1539,9 +1539,9 @@ bool LinearSum::divide(uint32_t scale) {
- for (size_t i = 0; i < terms_.length(); i++) {
- if (terms_[i].scale % scale != 0) {
+ for (size_t i = 0; i < termKeys_.length(); i++) { // CWE-407 fix
+ auto p = terms_.lookup(termKeys_[i]); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ if (p->value() % scale != 0) { // CWE-407 fix
return false;
}
}
- for (size_t i = 0; i < terms_.length(); i++) {
- terms_[i].scale /= scale;
+ for (size_t i = 0; i < termKeys_.length(); i++) { // CWE-407 fix
+ auto p = terms_.lookup(termKeys_[i]); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ p->value() /= scale; // CWE-407 fix
}
@@ -1589,18 +1589,22 @@ bool LinearSum::add(MDefinition* term, int32_t scale) {
// ... (constant folding preamble unchanged) ...
- for (size_t i = 0; i < terms_.length(); i++) {
- if (term == terms_[i].term) {
- if (!mozilla::SafeAdd(scale, terms_[i].scale, &terms_[i].scale)) {
- return false;
- }
- if (terms_[i].scale == 0) {
- terms_[i] = terms_.back();
- terms_.popBack();
- }
- return true;
- }
- }
-
- AutoEnterOOMUnsafeRegion oomUnsafe;
- if (!terms_.append(LinearTerm(term, scale))) {
- oomUnsafe.crash("LinearSum::add");
- }
+ // CWE-407 fix: O(1) amortised lookup+insert replaces O(T) linear scan
+ if (!terms_.initialized()) { // CWE-407 fix
+ AutoEnterOOMUnsafeRegion oomUnsafe; // CWE-407 fix
+ if (!terms_.init()) // CWE-407 fix
+ oomUnsafe.crash("LinearSum::add init"); // CWE-407 fix
+ } // CWE-407 fix
+ auto p = terms_.lookupForAdd(term); // CWE-407 fix
+ if (p) { // CWE-407 fix: term exists, update scale
+ int32_t newScale; // CWE-407 fix
+ if (!mozilla::SafeAdd(scale, p->value(), &newScale)) // CWE-407 fix
+ return false; // CWE-407 fix
+ if (newScale == 0) { // CWE-407 fix
+ // Remove zero-scale term; swap out of termKeys_ for O(1) removal
+ for (size_t i = 0; i < termKeys_.length(); i++) { // CWE-407 fix
+ if (termKeys_[i] == term) { // CWE-407 fix
+ termKeys_[i] = termKeys_.back(); // CWE-407 fix
+ termKeys_.popBack(); // CWE-407 fix
+ break; // CWE-407 fix
+ } // CWE-407 fix
+ } // CWE-407 fix
+ terms_.remove(p); // CWE-407 fix
+ } else { // CWE-407 fix
+ p->value() = newScale; // CWE-407 fix
+ } // CWE-407 fix
+ } else { // CWE-407 fix: new term
+ AutoEnterOOMUnsafeRegion oomUnsafe; // CWE-407 fix
+ if (!terms_.add(p, term, scale)) // CWE-407 fix: O(1) amortised
+ oomUnsafe.crash("LinearSum::add"); // CWE-407 fix
+ if (!termKeys_.append(term)) // CWE-407 fix
+ oomUnsafe.crash("LinearSum::add termKeys"); // CWE-407 fix
+ } // CWE-407 fix
return true;
}
@@ -1629,9 +1629,9 @@ void LinearSum::dump(GenericPrinter& out) const {
- for (size_t i = 0; i < terms_.length(); i++) {
- int32_t scale = terms_[i].scale;
- int32_t id = terms_[i].term->id();
+ for (size_t i = 0; i < termKeys_.length(); i++) { // CWE-407 fix
+ auto p = terms_.lookup(termKeys_[i]); // CWE-407 fix
+ MOZ_ASSERT(p); // CWE-407 fix
+ int32_t scale = p->value(); // CWE-407 fix
+ int32_t id = termKeys_[i]->id(); // CWE-407 fix
MOZ_ASSERT(scale);