shared × unstructured — bad data written permanently, and it spreads
Lossy Coercion Poisons a Shared Ledger
A value silently narrowed to the wrong type is added to a shared running total; the lock keeps the write safe but cannot restore the meaning the coercion threw away.
01the recipe
In the wild
compound ofType Errors in Dynamic LanguagesCWE-704 Bad CastThreading & MutexescompoundCWE-682 Incorrect Calculation
example.py
# SMELL: cents truncated to int before adding to a shared ledger.
# (type errors x threading & mutexes)
with lock:
ledger["cents"] += int(amount) # amount=10.99 -> 10; 0.99 lost every add
# the lock serializes the write, but the truncation is already baked in;
# the shared total drifts low and can never be reconciled.
# RIGHT: keep an exact integer-cents type end to end; never coerce lossily.
cents = round(Decimal(amount) * 100) # exact, total-preserving
with lock:
ledger["cents"] += centsint(amount) discards the fractional cents before the value ever reaches the shared ledger. The mutex makes the increment thread-safe, but it locks in an already-wrong number; every contributor under-reports and the shared total is permanently, unreconcilably low. Carry an exact type (integer cents / Decimal) so no meaning is lost at the coercion.
// observed
lossy: the shared total drifts low by the truncated remainder, forever right: exact integer cents; the aggregate reconciles to the penny
02weakness catalog
Mapped weaknesses (CWE)
On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.