java-topology/whitepaper/outreach/dask-project.md
russell@unturf.com 7e7ec2c3d3 feat: add 10 outreach docs (20 defects) for 2-patch projects
amarok, arrow, audacity, cargo, clementine, composer, dask,
deluge, dosbox-x, dragonfly. All CWE-407.
2026-04-14 13:50:33 -04:00

3.7 KiB
Raw Blame History

Dask — CWE-407 Disclosure Brief

2026-04-13 · Patch available — awaiting upstream merge

Finding

Two O(n²) defects in Dask's Parquet partition filter and DataFrame describe aggregation. Both patched. Patches ready for upstream review.

The Defects

dask-project-0001 (PATCHED — MEDIUM-HIGH): dask/dataframe/io/parquet/core.py:558

# In _filter_partitions() — fires during filtered Parquet reads:
for conjunction in disjunction:
    for part, stats in zip(*apply_conjunction(parts, statistics, conjunction)):
        if part not in out_parts:  # list membership — O(O) per partition
            out_parts.append(part)
            out_statistics.append(stats)

out_parts is a growing list. part not in out_parts is O(O) per partition. With P partitions across multiple OR filter clauses, total cost reaches O(P×O). Large Parquet datasets with many row groups (P=10,000+) and multiple disjunction clauses amplify the cost.

dask-project-0002 (PATCHED — LOW-MEDIUM): dask/dataframe/methods.py:180

# In describe_aggregate() — fires during DataFrame.describe():
names = []
for idxnames in values_indexes:
    for name in idxnames:
        if name not in names:  # list membership — O(N) per name
            names.append(name)

names is a growing list. name not in names is O(N) per name. With C total column names across all describe results, total cost reaches O(C²).

Complexity Proof

dask-project-0001: At P=5,000 partitions across disjunctions:

  • Defective: 5,000 × 2,500 (avg) = 12,500,000 comparisons
  • Fixed: 5,000 × O(1) = 5,000 lookups (set of id())
  • ~50× op reduction per filtered Parquet read.

dask-project-0002: At C=500 column names:

  • Defective: 500 × 250 (avg) = 125,000 comparisons
  • Fixed: 500 × O(1) = 500 lookups (set)
  • ~10× op reduction per describe().

Impact

Dask is a parallel computing library for Python analytics — used alongside pandas, scikit-learn, and NumPy for out-of-core and distributed data processing. dask-project-0001 fires on every filtered Parquet read with OR conditions. Data science workflows reading large partitioned Parquet datasets (data lakes, time-series stores, log analytics) with disjunctive filters hit this path.

dask-project-0002 fires during DataFrame.describe() aggregation. Wide DataFrames with many columns amplify the quadratic deduplication.

The Fix

dask-project-0001: Maintain a parallel set of partition identities:

# Before
if part not in out_parts:

# After
# CWE-407 fix: set of id() for O(1) membership instead of O(O) list scan.
out_parts_set = set(id(p) for p in out_parts)
if id(part) not in out_parts_set:
    out_parts.append(part)
    out_parts_set.add(id(part))

dask-project-0002: Maintain a parallel set for name deduplication:

# Before
if name not in names:

# After
# CWE-407 fix: set for O(1) membership instead of O(N) list scan.
names_set = set()
if name not in names_set:
    names.append(name)
    names_set.add(name)

Patch

Fix available: defects/dask-project/patch/dask-project-0001.patch and defects/dask-project/patch/dask-project-0002.patch

Two-file patch across parquet/core.py and methods.py.

dask-project-0001: ~50× speedup at P=5,000. dask-project-0002: ~10× speedup at C=500.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign an issue reference (dask/dask).
  2. Assess severity — dask-project-0001 sits on the Parquet I/O hot path and scales with partition count.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the Dask team in the public disclosure. Preferred acknowledgment format welcome.

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