aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blog/2024-09-29-fail/fail.jpgbin0 -> 95223 bytes
-rw-r--r--src/blog/2024-09-29-fail/fail.md89
2 files changed, 89 insertions, 0 deletions
diff --git a/src/blog/2024-09-29-fail/fail.jpg b/src/blog/2024-09-29-fail/fail.jpg
new file mode 100644
index 0000000..e9790d8
--- /dev/null
+++ b/src/blog/2024-09-29-fail/fail.jpg
Binary files differ
diff --git a/src/blog/2024-09-29-fail/fail.md b/src/blog/2024-09-29-fail/fail.md
new file mode 100644
index 0000000..41bea13
--- /dev/null
+++ b/src/blog/2024-09-29-fail/fail.md
@@ -0,0 +1,89 @@
1# Sometimes it's the hardware
2
3In the last few weeks, I was debugging a nasty bug on a hobby project.
4I needed to work with ~58GB of data generated by the program itself,
5which made everything quite slow and cumbersome to work with. But this
6specific piece of code was quite simple and I was able to rule out
7every possible cause of the bug, so where could the problem be?
8
9(Ok I think you can guess it from the title, but I want to tell you the
10whole story anyway.)
11
12## The bug
13
14Long story short, my program is a
15[Rubik's cube solver](https://nissy.tronto.net/) and I need
16to generate some lookup tables to speed up the solution search.
17Pretty much a standard
18[IDA*](https://en.wikipedia.org/wiki/Iterative_deepening_A*) method:
19the larger the table, the faster the solver.
20
21I am implementing a new kind of tables, and I know how to reliably
22generate one of around 30MB and one of around 58GB. I can also compute
23tables of different sizes between those two, but the method I use is
24experimental and I am not 100% sure the results are correct. But I can
25also generate the intermediate tables by deriving them from the 58GB one.
26This method is quite slow and can only work if the user has enough RAM,
27but it gives me a way to test the correctness of the other method.
28
29The algorithm to derive the smaller tables from the huge one is quite
30simple, but to my surprise I was getting different results at every
31run. I thought it must be some kind of
32[undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior),
33as it often the case with C.
34
35Time to take out my debugging weapons!
36
37## The whole arsenal
38
39To have a reasonable chance at uncovering nasty bugs related to undefined
40behavior, bad memory access, concurrency and other C programming
41nightmares, I used all of the following:
42
43* All compile-time warnings GCC offers, enabled with `-Wall -Wextra -pedantic`.
44* [Sanitizers](https://github.com/google/sanitizers), in particular the
45 *address* and *undefined* sanitizers. The *thread* sanitizer could not be
46 used with the large 58GB table because it requires much more memory, but in
47 any case this specific computation is not parallelized (yet).
48* `printf()` debugging. Not always effective when dealing with undefined
49 behavior, but it never hurts.
50* [GDB](https://en.wikipedia.org/wiki/GNU_Debugger).
51* [Valgrind](https://valgrind.org/).
52
53But nothing, my code did not trigger any error with these tools.
54Of course it could be an error in my logic, but why would I get a
55different results every time? This just did not make sense.
56
57## Sometimes you are not stupid, sometimes the computer is broken
58
59I started thinking that the OS could be doing something wrong. In fact,
60I noticed that KDE and Firefox occasionally crashed when I used ~60GB of
61RAM. Maybe the Kernel messed up [swapping](https://wiki.debian.org/Swap)?
62And a KDE or Firefox bug related to unusual memory sizes and usage would
63not be surprising.
64
65So I tried giving a `swapoff -a` to disable swap, and then run the
66program again. And I got inconsistent results and crashes once again.
67
68At this point I started doubting my hardware, so I ran
69[memtest86](https://www.memtest86.com/). Sure enough, something was wrong:
70
71![memtest FAIL message](fail.jpg)
72
73By the way, isn't this screen beautiful? It looks like it comes straight
74out of an 1980's hacker movie.
75
76## Conclusion
77
78With some more testing I was able to determine that one of the two RAM
79sticks works fine, and the other one is definitely broken. In case you
80are curious, memtest86 gives a similar screen with a green PASS message
81when all tests pass.
82
83Everything is still covered by warranty, so I asked for a replacement.
84Hopefully I'll have a working PC with 64GB of RAM again soon, but in
85the meantime I think I'll survive with 32GB.
86
87I have been programming for almost 20 years, and this is the first time
88an error in my program was due to a faulty piece of hardware rather than
89a bug in my code. Cool :)

Generated with cgit - Back to sebastiano.tronto.net