Hacker News new | ask | show | jobs
by wuch 3252 days ago
Now that OpenBSD has an optimizing compiler maybe they will notice and fix dataraces in their pthread_mutex_lock implementation. Currently they use broken double-checked locking pattern when mutex is lazy initialized with PTHREAD_MUTEX_INITIALIZER.
4 comments

In case someone is interested, here is relevant code [0]. Notice that mutexp is read without any synchronization, and _spinlock further down uses different lock than one in initialization code (former is specific to this mutex and latter a global one). There is no happens before relationship between mutex initialization and mutex locking. Thus, if different thread reads non-null value of *mutexp, there is no guarantee that writes done to the mutext structure itself will be visible. Given strong memory model of amd64 and i386, compiler would have to reorder pointer publication and structure initialization in pthread_mutex_init, unlikely but certainly a valid change given lack of synchronization.

[0] https://github.com/openbsd/src/blob/0ecb71b5ec9e4b22a484606f...

Correct me if I'm wrong, but I think a compiler that doesn't do link-time-optimization has to assume that the _spinlock() function can write to mutexp (e.g. through a global variable), and therefore it cannot reorder anything around it.
I think you are looking at the side that does the reading. I was actually thinking about the other side that does the writing (inside pthread_mutex_init), where those two things are not separated by any function calls and are more readily reordered. Not to mention that it would be problematic on architectures with relaxed memory model either way.
Have you reported this bug upstream ?
I just committed a potential fix[0]. Thank you for bringing this to our attention and please let us know if that takes care of the defect you were seeing!

Next time, if you want to be sure we read about your problems with OpenBSD, please use sendbug(8) and fill a report[1] or come talk to us on tech@.

[0] -- https://marc.info/?l=openbsd-cvs&m=150131738906455&w=2

[1] -- https://www.openbsd.org/report.html

They used GCC before Clang, so they switched to a less optimizing compiler.
I would argue to the contrary, especially that we are comparing modern Clang/LLVM with a GCC that was released back in 2008. At that point C programming language didn't even have a memory model.
Their GCC version was forked a while back because of quality issues in "stable" releases of GCC. Optimizing compilers have gotten a lot better since then. Upstream Clang still (in aggregate) generates worse code than upstream GCC, but the point is that Clang's stable releases tend to have fewer correctness regressions, and optimize more than OpenBSD's current version of GCC.