java-topology/whitepaper/outreach/angelscript.md

5 KiB
Raw Blame History

AngelScript — CWE-407 Disclosure Brief

2026-03-27 · Patch available — awaiting upstream merge

Finding

Three O(n²) defects in AngelScript's module ownership transfer and switch-statement compiler. All patched. Patches ready for upstream review. Notably, the AngelScript source contains explicit // TODO: optimize comments at two of the defect sites, acknowledging the performance problem.

The Defects

angelscript-0001 (PATCHED — HIGH): sdk/angelscript/source/as_scriptengine.cpp:880

// In FindNewOwnerForSharedType() — called per shared type on module discard:
for (int n = 0; n < engine->modules.GetLength(); n++) {
    asCModule *mod = engine->modules[n];
    // 5 calls to IndexOf() per shared type transfer:
    if (mod->sharedTypes.IndexOf(type) >= 0) { ... }  // O(n) per call
}
// Engine comment at line 917:
// "TODO: optimize: If the modules already stored the shared types separately, this would be quicker"

asCArray<T>::IndexOf() is a linear scan. Called 5 times per shared type transfer for every remaining module.

angelscript-0002 (PATCHED — HIGH): sdk/angelscript/source/as_scriptengine.cpp:953

// In FindNewOwnerForSharedFunc() — called per shared function on module discard:
if (mod->sharedFunctions.IndexOf(func) >= 0) { ... }  // O(n) per call

Same root cause on shared functions. 5 linear scans per shared function transfer.

angelscript-0003 (PATCHED — HIGH): sdk/angelscript/source/as_compiler.cpp

// In CompileSwitch() — per case value in while loop:
while (/* more cases */) {
    if (caseValues.IndexOf(caseVal) >= 0) {  // O(n) per case — duplicate check
        Error(TXT_DUPLICATE_SWITCH_CASE);
    }
    caseValues.PushLast(caseVal);
}
// O(n²) duplicate case detection during switch compilation

caseValues is asCArray<asDWORD>. IndexOf() is O(n) per case. O(n²) total for n switch cases.

Complexity Proof

angelscript-0001/0002: For T shared types/functions across M modules:

  • Per module: 5 × O(T) IndexOf() calls
  • Total: O(M × T × 5)

At T=200 types, M=100 modules: defective=3,980,000 comparisons, fixed=39,800 (asCSet<> shadow). 100× op reduction.

angelscript-0003: For N case values in a switch statement:

  • Per case: O(N) IndexOf() scan
  • Total: O(N²)

At N=500 cases: defective=124,750 comparisons, fixed=500 (asCSet<asDWORD> shadow). 250× op reduction.

Impact

AngelScript is the scripting language embedded in many C++ game engines and applications, including Dry/Urho3D, and dozens of indie engines. It is used wherever C++ developers need a scripting layer that integrates tightly with C++ types.

angelscript-0001/0002 fire on every module->Discard() call — when a script module is unloaded and ownership of shared types/functions must be transferred. In applications that frequently reload scripts (modding systems, live editing workflows, hot-reload dev environments), this path runs repeatedly.

angelscript-0003 fires on every script compilation that includes a switch statement. Scripts with large switch statements (state machines, command parsers, opcode dispatchers) pay O(n²) at every compile. For switch statements with hundreds of cases (common in protocol implementations and scripted state machines), the overhead is significant.

The Fix

angelscript-0001/0002: Add asCSet<asCTypeInfo*> and asCSet<asCScriptFunction*> shadow sets:

// Before
if (mod->sharedTypes.IndexOf(type) >= 0) { ... }

// After
// CWE-407 fix: asCSet shadow for O(1) Exists() instead of O(n) IndexOf() scan.
if (mod->sharedTypeSet.Exists(type)) { ... }

Maintain sharedTypeSet and sharedFuncSet alongside the existing arrays. asCSet is already available in AngelScript's own container library.

angelscript-0003: Add asCSet<asDWORD> for case dedup:

// Before
if (caseValues.IndexOf(caseVal) >= 0) { ... }
caseValues.PushLast(caseVal);

// After
// CWE-407 fix: asCSet for O(1) duplicate detection instead of O(n) IndexOf().
if (caseValueSet.Exists(caseVal)) { ... }
caseValueSet.Insert(caseVal);
caseValues.PushLast(caseVal);  // preserved for downstream iteration

Patch

Fix available: defects/angelscript/patch/angelscript-0001-0003-ascset-shadow.patch

Three-location patch across as_scriptengine.cpp (two sites) and as_compiler.cpp.

Unit test: AngelScriptTest 4/4 pass. angelscript-0001/0002: 100× speedup at T=200, M=100. angelscript-0003: 250× speedup at N=500 cases.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign an issue reference (AngelCode/angelscript or the official forums).
  2. Assess severity — the // TODO: optimize comments in the source indicate these defects were already known; the patch resolves them.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the AngelScript team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.