Skip to content

Make powl() thread-safe (#222)#355

Merged
ViralBShah merged 1 commit into
masterfrom
fix-222-powl-mt
Jun 23, 2026
Merged

Make powl() thread-safe (#222)#355
ViralBShah merged 1 commit into
masterfrom
fix-222-powl-mt

Conversation

@ViralBShah

Copy link
Copy Markdown
Member

Fixes #222.

powl returned garbage under concurrent calls — e.g. two threads computing powl(0x8.779021e7c2f81b2p+14982L, -0x8.0021b03e1f821c9p-15097L) (exactly 1) got different huge/Inf values.

Root cause

ld80/e_powl.c kept powl()'s working scratch in file-scope static mutable variables:

static volatile long double z;
static long double w, W, Wa, Wb, ya, yb, u;

Concurrent calls race on this shared state. (reducl()/powil() already used locals; the read-only coefficient tables are fine.)

Fix

Move that scratch to local automatic variables inside powl() (preserving the load-bearing volatile on z as a local). No math changes.

Verification

  • 8-thread stress (each thread computing a distinct exactly-representable power, including the issue value): fails every run before, rock solid after.
  • Single-threaded parity vs glibc on a 21-value battery (normal/overflow/underflow/negative base/non-integer exponent) — unchanged.
  • Full make test passes.
  • New test/regression/test-222.c (pthreads; ld80-only via #if LDBL_MANT_DIG == 64, so it builds/runs natively and compile-skips elsewhere). Proven to fail before / pass after.

Note: touches ld80/e_powl.c in a different region than #351 (#334's overflow guard); no conflict.

powl() in ld80/e_powl.c kept its working scratch values (z, w, W, Wa,
Wb, ya, yb, u) in file-scope `static` variables.  Two threads calling
powl() concurrently clobbered each other's scratch, so a call could
return arbitrary garbage -- e.g. the reproducer from the issue,
powl(0x8.779021e7c2f81b2p+14982L, -0x8.0021b03e1f821c9p-15097L), which
is exactly 1, would instead come back as huge values or inf.

Move that scratch to local automatic variables inside powl().  The
`volatile` on z is preserved (as a local volatile) because it is
load-bearing for the rounding/underflow behaviour, exactly like the
twom10000 constant.  The math is unchanged.  reducl() and powil()
already used local automatics and were unaffected.

Add test/regression/test-222.c: it spawns 8 threads, each repeatedly
computing a different power with a known-exact result, and fails if any
call ever deviates.  Before the fix this fails essentially every run;
after it, it is solid.  It skips (77) when long double is not the 80-bit
type or when threads cannot be started.  The regression Makefile rule
gains -pthread (harmless for the single-threaded tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.12%. Comparing base (aeef4da) to head (70e491c).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #355   +/-   ##
=======================================
  Coverage   72.12%   72.12%           
=======================================
  Files         233      233           
  Lines        6135     6135           
  Branches     1607     1607           
=======================================
  Hits         4425     4425           
  Misses       1417     1417           
  Partials      293      293           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ViralBShah ViralBShah merged commit 43f291e into master Jun 23, 2026
24 checks passed
@ViralBShah ViralBShah deleted the fix-222-powl-mt branch June 23, 2026 01:26
@zimmermann6

Copy link
Copy Markdown

good work! I'll check that with the next release

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

powl returns non-sense results in multi-thread mode

2 participants