Career case study · Firmware defects

The bug that only existed after three and a half hours.
Below that, it passed every normal test.

In stimulation firmware at SPR Therapeutics, a burst/gap modulation duration came out wrong, but only when it was set above about 3.5 hours. Peter Sords, then a firmware engineer there, recorded the defect in his 2020 engineering notes. It belongs to a class of bug a compiler can flag before anyone has to debug it.

SPR Therapeutics · 2020int16_t · uint16_t · -Wsign-conversionPrior role, not a Kyros engagement

Correct at every setting anyone tested.

A burst/gap modulation duration came out wrong when it was set above roughly 3.5 hours. Below that threshold the firmware behaved correctly, so the defect passed every normal test anyone thought to run.

On a stimulation device, a timing parameter that is wrong only at the long end of its range is wrong at exactly the settings least likely to be on the bench the day you test.

Nothing in the logic was wrong.

Below the threshold there was nothing to see. The firmware produced the right duration, every normal test passed, and the code on each side of the function call was valid on its own. Implicit signed-to-unsigned conversion is legal, so under default warning settings the compiler says nothing about it.

The defect existed only where the two sides met, and only for values large enough to reach it. A test suite that sticks to typical settings never gets there.

The threshold was the clue.

Three timing parameters were declared as signed types, then passed into the function that computed the phase count, which received them as unsigned types.

Declared as

Received as

int32_t

uint32_t

int16_t

uint16_t

int32_t

uint32_t

That conversion is completely harmless until a value consumes more than half the range of the smaller, signed type. A long duration does exactly that: an int16_t tips negative at 32,768. The rule Peter took from it is to suspect type width or signedness before logic whenever a bug appears only past a magnitude, then compute the threshold and check whether it lands on a power of two.

The fix was to make the types match end to end, each chosen from the physical range the quantity can actually take rather than from whatever compiled. With the types matched and sized to the real range, there is no conversion left to go wrong.

The uncomfortable part is that no clever debugging was required. With -Wconversion and -Wsign-conversion enabled in CI, the compiler would have flagged it before it was ever a mystery.

Compiler warnings beat clever debugging.

Turn the warnings on

-Wconversion and -Wsign-conversion catch this class of defect at build time. Treat what they report as findings, not noise.

Suspect the type before the logic

When a bug appears only past a magnitude, compute the threshold and check whether it lands on a power of two.

Test the ends of every range

A test suite that only exercises typical values is testing the values you already understand. Put the maximum of every settable range on the bench.

Choose each type from the physics

Size every variable from the physical range of the quantity it holds, not from whatever happens to compile.

How Kyros applies it now

Warnings on. Edges tested.

When Kyros runs a firmware code audit on inherited code, the build goes through with -Wconversion and -Wsign-conversion enabled before anyone reads the logic, and settable values are exercised at the ends of their ranges rather than the middle. The compiler finds this class of defect for free, so it is the first thing we let it do.

Firmware that fails only at the edges?

Bring the symptom and the codebase. We will tell you what we would check first.

Schedule an Architecture Call

Frequently Asked Questions

Why would a firmware bug appear only above a certain setting?
Often because a value has outgrown its type. A signed 16-bit integer tips negative at 32,768, so a conversion that is harmless at small values can break past a threshold. When a bug appears only past a magnitude, suspect type width or signedness before logic.
Can compiler warnings catch signed/unsigned conversion bugs?
Yes. -Wconversion and -Wsign-conversion flag implicit conversions that can change a value or its sign, such as a signed argument passed to an unsigned parameter. Enabled in CI, they would have caught this defect before it was ever a mystery.
Is SPR source code shown on this page?
No. This is career work from Peter Sords' prior role at SPR Therapeutics in 2020, not a Kyros engagement. The page describes the types and the threshold only, and no SPR source code is reproduced.