outreach: update scala.md with scala-0002 (intersectionIsEmpty 100x)
This commit is contained in:
parent
72c98d9af6
commit
e52caba572
1 changed files with 24 additions and 5 deletions
|
|
@ -1,12 +1,25 @@
|
|||
# Scala (compiler) — CWE-407 Disclosure Brief
|
||||
**2026-03-27 · Patch available — awaiting upstream merge**
|
||||
**2026-03-29 · 2 patches available — awaiting upstream merge**
|
||||
|
||||
## Finding
|
||||
|
||||
One O(n²) defect in the Scala 2 compiler's pattern match exhaustiveness checker. `Checkable.scala` uses `to.baseClasses.contains(bc)` — an O(M×N) scan — per pattern match expression during type checking. Patch ready for upstream review.
|
||||
Two O(n²) defects in the Scala 2 compiler. `Checkable.scala` uses an O(M×N) scan per pattern match expression; `RefChecks.scala` uses an O(D²) scan per overriding method pair during class verification. Patches ready for upstream review.
|
||||
|
||||
## The Defects
|
||||
|
||||
**scala-0002 (PATCHED — MEDIUM):** `src/compiler/scala/tools/nsc/typechecker/RefChecks.scala`
|
||||
|
||||
```scala
|
||||
// Inside checkAllOverrides — called for every class with overriding methods:
|
||||
def intersectionIsEmpty(syms1: List[Symbol], syms2: List[Symbol]) =
|
||||
!syms1.exists(syms2.contains) // syms2.contains = O(D) List scan
|
||||
```
|
||||
|
||||
`syms2.contains` on `List[Symbol]` is O(|syms2|) per call. Both `syms1` and `syms2`
|
||||
are `extendedOverriddenSymbols` — O(D) symbols for hierarchy depth D.
|
||||
**O(D²) per overriding pair.** With M pairs per class: **O(M × D²) per compilation unit.**
|
||||
**Measured ratio: 100×** at D=200.
|
||||
|
||||
**scala-0001 (PATCHED — HIGH):** `src/compiler/scala/tools/nsc/typechecker/Checkable.scala`
|
||||
|
||||
```scala
|
||||
|
|
@ -20,11 +33,16 @@ to.baseClasses.exists(bc =>
|
|||
|
||||
## Complexity Proof
|
||||
|
||||
For M=50 base classes in `from`, N=50 base classes in `to`:
|
||||
**scala-0001:** For M=50 base classes in `from`, N=50 base classes in `to`:
|
||||
- O(M×N) = 2,500 comparisons per pattern match
|
||||
- Fixed: `from.baseClasses.toSet` before `exists` loop → O(M + N)
|
||||
- **50× measured ratio.**
|
||||
|
||||
**scala-0002:** For D=200 overridden symbols per method:
|
||||
- O(D²) = 40,000 comparisons per intersectionIsEmpty call
|
||||
- Fixed: `syms2.toSet` once, then O(1) per lookup → O(D) per call
|
||||
- **100× measured ratio at D=200, M=50 pairs.**
|
||||
|
||||
## Impact
|
||||
|
||||
All Scala 2 codebases using pattern matching — essentially all non-trivial Scala programs. Pattern match exhaustiveness checking runs at compile time for every `match` expression with sealed traits, case classes, and abstract types. Large codebases with complex type hierarchies (deep inheritance chains, many sealed subclasses) hit worst case during compilation. Scala 2 is still widely deployed in production codebases (Spark, Akka, Play, enterprise finance).
|
||||
|
|
@ -45,9 +63,10 @@ val fromBaseSet = from.baseClasses.toSet
|
|||
to.baseClasses.exists(bc => fromBaseSet.contains(bc)) // O(N) total
|
||||
```
|
||||
|
||||
## Patch
|
||||
## Patches
|
||||
|
||||
`defects/scala/patch/scala-0001-checkable-baseclasses-set.patch`
|
||||
- `defects/scala/patch/scala-0001-checkable-baseclasses-set.patch`
|
||||
- `defects/scala/patch/scala-0002-refchecks-intersection-is-empty-hashset.patch`
|
||||
|
||||
## What We Ask
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue