a simple case of a helgrind false negative?
David Yonge-Mallo <[email protected]> Mon, 4 Aug 2025 16:24:38 +0200
| Newsgroups | gmane.comp.debugging.valgrind |
|---|---|
| Message-ID | <CAJjVr9Few5=VHn-hAh_nZO3GZWYdD-RsU3xd81ZDQ3Et03w4EA@mail.gmail.com> |
--===============0166084763645450059==
Content-Type: multipart/alternative; boundary="000000000000d1a0aa063b8ade56"
--000000000000d1a0aa063b8ade56
Content-Type: text/plain; charset="UTF-8"
Hi, everyone,
I would like some help from helgrind experts to settle a disagreement with
a colleague.
We have the following code (very simplified):
--- begin example.cpp ---
#include <pthread.h>
#include <iostream>
#include <atomic>
bool flag = false; // std::atomic<bool> flag{false};
void* callbackEvent(void* whatever) {
flag = true;
return whatever;
}
int main(void) {
pthread_t callback_thread;
pthread_create(&callback_thread, NULL, callbackEvent, NULL);
bool copyOfFlag = flag;
if (!copyOfFlag) {
std::cout << "value of flag: " << copyOfFlag << std::endl; // do
stuff assuming flag is false
}
pthread_join(callback_thread, NULL);
}
--- end example.cpp ---
> g++ -lpthread example.cpp -o example && valgrind --tool=helgrind
./example
Running helgrind naturally produces the output that there is a data race in
"flag" between the two threads.
If the flag is replaced by an atomic, helgrind produces a clean report.
According to my understanding, this is a false negative. There is still no
"happens-before" relationship between the read in thread #1 and the write
in thread #2. The program can terminate with copyOfFlag being either true
or false, which means the race condition still exists.
According to my colleague, helgrind by design only cares that a read and a
write on the same memory does not happen at the same time, and making the
bool atomic fixes this. The indeterminacy of the value of copyOfFlag is a
separate issue, which helgrind cannot detect as it is not within the scope
of its design.
I claimed that helgrind does not understand atomic variables. My colleague
disbelieved this and made the counterargument that if a mutex is used to
guard access to flag (instead of making it atomic), it also produces a
clean report, and since helgrind undoubtedly understands mutexes, it must
mean that the data race is fixed.
What is the correct view here?
Thank you for your time.
p.s. I am aware of bug 339330, but technically it only mentions false
positives and this is a case of (what I believe to be) a false negative.
--
David Yonge-Mallo
--000000000000d1a0aa063b8ade56
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr"><br><div>Hi, everyone,</div><div><br></di=
v><div>I would like some help from helgrind experts to settle a disagreemen=
t with a colleague.<br><br>We have the following code (very simplified):</d=
iv><div><br>--- begin example.cpp ---</div><div>#include <pthread.h><=
br>#include <iostream><br>#include <atomic><br><br>bool flag =
=3D false; =C2=A0// std::atomic<bool> flag{false};<br><br>void* callb=
ackEvent(void* whatever) {<br>=C2=A0 =C2=A0 flag =3D true;<br>=C2=A0 =C2=A0=
return whatever;<br>}<br><br>int main(void) {<br>=C2=A0 =C2=A0 pthread_t c=
allback_thread;<br><br>=C2=A0 =C2=A0 pthread_create(&callback_thread, N=
ULL, callbackEvent, NULL);<br><br>=C2=A0 =C2=A0 bool copyOfFlag =3D flag;<b=
r>=C2=A0 =C2=A0 if (!copyOfFlag) {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 std::cout=
<< "value of flag: " << copyOfFlag << std::end=
l;=C2=A0 // do stuff assuming flag is false<br>=C2=A0 =C2=A0 }<br><br>=C2=
=A0 =C2=A0 pthread_join(callback_thread, NULL);<br>}<br></div><div>--- end =
example.cpp ---<br><br>> g++ -lpthread example.cpp -o example &&=
valgrind --tool=3Dhelgrind ./example=C2=A0</div><div><br>Running helgrind =
naturally produces the output that there is a data race in "flag"=
between the two threads.=C2=A0<br><br></div><div>If the flag is replaced b=
y an atomic, helgrind produces a clean report.</div><div><br></div><div>Acc=
ording to my understanding, this is a false negative. There is still no &qu=
ot;happens-before" relationship between the read in thread #1 and the =
write in thread #2. The program can terminate with copyOfFlag being either =
true or false, which means the race condition still exists.</div><div><br><=
/div><div>According to my colleague, helgrind by design only cares that a r=
ead and a write on the same memory does not happen at the same time, and ma=
king the bool atomic fixes this. The indeterminacy of the value of copyOfFl=
ag is a separate issue, which helgrind cannot detect as it is not within th=
e scope of its design.</div><div><br></div><div>I claimed that helgrind doe=
s not understand atomic variables. My colleague disbelieved this and made t=
he counterargument that if a mutex is used to guard access to flag (instead=
of making it atomic), it also produces a clean report, and since helgrind =
undoubtedly understands mutexes, it must mean that the data race is fixed.<=
/div><div><br></div><div>What is the correct view here?=C2=A0<br><br>Thank =
you for your time.<br><br>p.s. I am aware of bug=C2=A0339330, but technical=
ly it only mentions false positives and this is a case of (what I believe t=
o be) a false negative.<br><br>--=C2=A0<br>David Yonge-Mallo</div></div>
</div>
--000000000000d1a0aa063b8ade56--
--===============0166084763645450059==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
--===============0166084763645450059==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Valgrind-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-users
--===============0166084763645450059==--