fix(tfile): declare ecode volatile in validate_tfile_pow_fp()#151
Merged
adequatelimited merged 1 commit intoaudit-fixesfrom Apr 13, 2026
Merged
fix(tfile): declare ecode volatile in validate_tfile_pow_fp()#151adequatelimited merged 1 commit intoaudit-fixesfrom
adequatelimited merged 1 commit intoaudit-fixesfrom
Conversation
In validate_tfile_pow_fp(), ecode is shared across OMP threads: writes happen inside OMP_CRITICAL_ blocks (correctly serialized) but reads are outside any critical section (the while-loop condition at line 853 and the early-continue at line 866). Under the C11 memory model this is a data race and undefined behavior. On x86 it works by accident due to Total Store Order — stores become visible quickly and the compiler is unlikely to cache the value in a register across an OMP_CRITICAL_ boundary. On weakly- ordered architectures (ARM64, RISC-V, MIPS) the write may not be visible to a reader for an unbounded time. ThreadSanitizer also flags this as a data race. Declaring ecode volatile prevents the compiler from caching it in a register and forces each read to go to memory. Combined with the memory barriers implicit in OMP critical-section entry/exit, this gives correct shared-flag semantics on all real hardware. errnum is written inside critical sections and read only AFTER the OMP_PARALLEL_ block ends. The implicit barrier at parallel- region exit provides the necessary synchronization, so errnum does not need volatile. Closes #101
Collaborator
Author
|
Not an issue now for x86 with current compilers, but patching in case a future compiler optimization makes it an issue. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ecodeasvolatile intinvalidate_tfile_pow_fp()so that the unsynchronized read of the loop-exit flag is well-defined on all hardware.Problem
In
src/tfile.c:821(validate_tfile_pow_fp),ecodeis a plainintshared across OMP threads. Writes happen insideOMP_CRITICAL_()blocks (correctly serialized) but reads are outside any critical section:while (ecode == VEOK)— loop-exit conditionif (ecode != VEOK) continue;— early continueUnder the C11 memory model, an unsynchronized read of a variable that another thread may concurrently write (even inside a critical section) is a data race and undefined behavior. ThreadSanitizer flags this as a race.
On x86 it works by accident due to Total Store Order — stores become visible to other cores quickly and the compiler is unlikely to cache the value in a register across an
OMP_CRITICAL_boundary. On weakly-ordered architectures (ARM64, RISC-V, MIPS) the write may not be visible to a reader for an unbounded time.Fix
Declaring
ecodeasvolatile int:errnumis not affected — it is written inside critical sections and only read AFTER the parallel region ends, where the implicit barrier at parallel-region exit provides the necessary synchronization.Alternatives considered
_Atomic intvia<stdatomic.h>is the C11-purist answer. Not adopted because (a) it requires a new header dependency, (b) thevolatileapproach is sufficient for correctness on all real hardware given the existing OMP critical sections, and (c) the existing codebase style is plain-C + OpenMP, not stdatomic.Test plan
make testpassesmake test CCARGS="-fsanitize=thread"should no longer flag thewhile (ecode == VEOK)read as a race (or the warning should be substantially reduced)Closes #101