Skip to content

CircuitPython 10.3.0's own Flanger overflows int32 where our port does not — a deliberate departure, and an upstream report owed #76

Description

@bdbarnett

Found by the first three-way verify_dsp run, 2026-09-09. 18 of 54 probe lines differ between the patched CircuitPython build and our other two targets, and they are exactly the rails cases — the full-scale alternating material. Every other case agrees to the byte, which is the signature of an overflow that only bites at the extremes.

The cause, at the source

cmods/circuitpython/shared-module/audiodelays/Flanger.c:365:

int32_t wet = s0 + (((s1 - s0) * (int32_t)delay_frac) >> 16);

With the delay line holding adjacent samples at opposite rails, s1 - s0 reaches 65535 and delay_frac reaches 65535 too — a product of 4.29e9, past INT32_MAX. Signed overflow, and reachable on ordinary full-scale material.

Upstream widened the other product and not this one. Eighteen lines above, at :347:

uint32_t delay_q16 = delay_min_q16 + (uint32_t)(((uint64_t)delay_span_q16 * tri) >> 16);

so the (uint64_t) cast is there where it is needed for the span, and absent where it is needed for the interpolation.

Where each target stands

target form correct?
CircuitPython 10.3.0 (upstream's C) int32_t product no
audioif CPython twin (Python) arbitrary precision yes, by accident — Python does not overflow
audioif MicroPython (our C) (int64_t) product yes, fixed in 2a95091

Our port inherited the bug because Cursor ported from that same upstream file; I found it here by cross-interpreter comparison and widened it. The twin was never wrong because Python has no int32 to overflow — which is also why a twin cannot be relied on to surface this class of defect.

What this needs

  1. An upstream-diff.md entry, because under docs/correctness-standard.md a deliberate departure from CircuitPython in a node CircuitPython has must be written there or it is a bug. We are deliberately not reproducing this overflow.
  2. A stated skip in verify_dsp's PROBES for flanger_probe.py on circuitpython, naming this issue — otherwise the three-way stands red on a defect that is not ours to fix.
  3. An upstream report, drafted into docs/upstream-reports/ and not filed yet: Brad's rule of 2026-09-09 is that no upstream report goes out until our own house is clean, in case something related changes the report. The fix upstream is one cast, the same one they already used eighteen lines earlier.

Related: audioif#75 (our CircuitPython bindings lagging), which the same three-way run surfaced.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions