214 lines
11 KiB
Diff
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);
|