Might you or anyone else have some resources you could recommend for learning TLA+?
Has glibc since fixed the issue?
I unfortunately didn't have time to go through:
- compiling glibc from source
- converting my code to C
- trying to reduce multithreaded synchronization code to a minimal example given how non-deterministic any of those bugs are
- do a write-up
That said, it seems like people went through the motions 4 months after me in this bug:
- https://sourceware.org/bugzilla/show_bug.cgi?id=25847 which affects C#, OCaml, Python
Someone also fully reimplemented Glibc condition variable in TLA+ to prove that the glibc code was buggy:
- https://probablydance.com/2020/10/31/using-tla-in-the-real-w... (at the bottom)
I'd normally respond with (when looking at the very complex relevant glibc code), "complexity is a code smell", but I don't understand the problem space enough to legitimately suggest that here, other than to say that in my experience programming thus far, if you require this much complexity for any part of your system, it is in all likelihood reflective of a design flaw (possibly elsewhere).
It's really only douchy or elitist if it's strictly used in an insulting or disparaging way. Most of the time when people talk about code smells it's meant to indicate, just like with real-world odd, bad, or unexpected smells: Something doesn't seem right. I could be wrong, but it warrants investigation.
Using the examples above, deep nesting and large numbers of parameters are indications of a potential problem, but are not necessarily problems. It could be that a refactoring is in order, but it may also be that everything is fine (just not pretty).
Most code "smells" are in the former category, they are not describing the code as "repulsive" but "off". If you're making that leap then you're going to need to supply (or find) another term for what is described, for now over 20 years, as a code smell. Since most people don't have the same visceral reaction you do, they won't care.
For example, it is quite possible that code that is nested 30 levels deep is provably correct. Since we are humans, is that likely? No, it is not. Or at least, it is certainly less likely than 3-level-deep code. So you look at some code and without doing any deep analysis you can make some "probably valid" assumptions which come from your experience.
If you're so bent on accurate engineering, answer me this: Why are technology choices often "fashion-driven", without any significant empirical data to support their choice over other alternatives? (My latest pet peeve in this space is widespread use of Docker.) And where data DOES exist (such as to support the statement "Functional languages produce far fewer bugs per LOC written"), why don't more programmers/engineers heed that?
I thought I had bugs in my code for sure, I couldn't believe glibc and musl had a bug.
Then I decided to spend a couple days to learn formal verification, solved all the bugs it found.
It worked on my Mac, it worked on Windows, it was still deadlocking on Linux. I replaced my code with raw futexes, no deadlock anymore. And I added logs that showed signaling happened but the thread signaled wasn't unblocked.
The futex<->condvar swap is pretty simple. - https://github.com/mratsim/weave/blob/f41a562/weave/cross_th...
Any use of condition variables where the lock is "never used" screams fundamentally broken to me. No amount of atomics and memory orderings or manually inserted fences/memory barriers can help you if you leave a race window open between checking your predicate and starting to wait on a signal. Condvar signals are not sticky. If nobody is waiting for a signal when you signal, that signal is lost. There is nothing between your atomics and lock & wait to prevent such loss.
Also your TLA+ (or rather PlusCal) does not model a condition variable correctly, so it would obviously not detect this issue. You have a sticky boolean variable and await, which blocks the procedure until the condition becomes true. This detects lockups of the class where the condition is never signalled at all, but it does not model the possibility of losing a signal because nobody was waiting for it.
I don't believe you discovered a bug in glibc and musl.
I also proved that one of the nasty deadlock bugs I was fighting on Linux (but not on Windows or Mac) was actually glibc missing condition variables wakeup signals from time to time.
100% convinced it's worth learning to debug or verify any kind of distributed or multithreaded synchronization primitive. I was bug hunting for a couple weeks before deciding to learn formal verification / model checking via TLA+.
Writeup: https://github.com/mratsim/weave/issues/56