aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blog/2023-05-05-debug-smartphone/debugging-smartphone.md139
-rw-r--r--src/blog/2023-05-05-debug-smartphone/termux.jpgbin0 -> 98200 bytes
-rw-r--r--src/blog/blog.md1
-rw-r--r--src/blog/feed.xml7
4 files changed, 147 insertions, 0 deletions
diff --git a/src/blog/2023-05-05-debug-smartphone/debugging-smartphone.md b/src/blog/2023-05-05-debug-smartphone/debugging-smartphone.md
new file mode 100644
index 0000000..e346860
--- /dev/null
+++ b/src/blog/2023-05-05-debug-smartphone/debugging-smartphone.md
@@ -0,0 +1,139 @@
1# I had to debug C code on a smartphone
2
3A few days ago someone contacted me about an issue they had with
4[nissy](https://nissy.tronto.net) - a project of mine that I have talked
5about in [my last blog post](../2023-04-10-the-big-rewrite).
6
7I was happy to look into it, but I could not reproduce the error in any
8way, while this person ran into it consistently every time they tried
9to use a certain functionality.
10
11They were using a [Mac M1](https://en.wikipedia.org/wiki/Apple_M1),
12which has an
13[ARM-based CPU](https://en.wikipedia.org/wiki/ARM_architecture_family).
14So I guessed the error was caused by me relying on some undefined
15behavior of C that resulted in different compiled code on
16[x86](https://en.wikipedia.org/wiki/X86)
17and on ARM. But I had no ARM-based machine to debug this.
18
19Except...
20
21## Everyone has an ARM computer
22
23Most (if not all) smartphones have and ARM-based CPU. This means, at
24least in theory, that if this bug was really related to this different
25CPU architecture, I could reproduce it on my phone.
26
27Nissy is a command line application. To compile it you just need a C
28compiler + standard library and a terminal emulator. On Android there is
29[termux](https://termux.dev), that I already use to ssh into my personal
30server in case I need to check something on the go and to play around.
31So I installed git, [clang](https://clang.llvm.org) and gdb on it, and
32I was ready to go!
33
34![A screenshot of my phone running termux, debugging nissy](termux.jpg)
35
36This was not the most pleasant experience. Yes, I could have installed
37vim or some other text editor instead of using ed, but I don't think this
38would have improved things all that much. I mostly edited the code on
39my laptop and transferred my changes to my phone with quick git push &
40pulls, keeping text editing on the phone to a minimum.
41
42And it worked! I was able to reproduce the bug on the first try in
43this environment. In hindsight, I should have tried building nissy
44with a different compiler first, which would have saved me the hassle
45of working on a 5-inch screen. I tried afterwards, but I could not
46reproduce the error this way.
47
48## The actual bug
49
50The bug itself was just a classic out-of-bounds error. Simplifying a
51bit, at the beginning of a file I had a bunch static arrays that looked
52pretty much like this:
53
54```
55#define N 10000
56static int a[N];
57static int b[N];
58```
59
60The values in these arrays where written only once, in their respective
61`initialize_a()` and `initialize_b()` functions, both called at startup.
62
63The second array `b[]` was initialized correctly, but the value `b[0]`
64changed after calling `initialize_a()`, which in theory did not touch
65`b[]` in any way. But, due to some wrong logic, in this function I ended
66up writing some value into `a[N]`, which is out of the bounds of array
67`a[]`. Apparently, when targeting ARM the compiler decided to allocate
68the space for `a[]` and `b[]` in contiguous areas of memory, something
69that did non happen on other architectures - perhaps some padding was
70added between the two?
71
72Once spotted, fixing the bug was easy: if a certain index `i` reached
73the value `N`, the correct thing to do was to skip that value. I had
74simply forgotten to check this. Adding an `if (i != N)` solved it.
75
76## Retrospective
77
78Debugging on a smartphone is obviously not ideal, especially since nissy
79(at least in its current form) is not meant to run on one. This motivated
80me to think back and look for ways to prevent this kind of problem.
81
82### Testing
83
84The error in the code had nothing to do with CPU architectures, it
85was a logic error. The algorithm I had in mind was correct, but I
86forgot one case and typed it out wrong. This is something that is
87bound to happen to everyone, so how could I have avoided it?
88
89A good way to spot errors in your logic is to write [unit
90tests](https://en.wikipedia.org/wiki/Unit_testing). In this particular
91case, though, I cannot think off the top of my head how to write a
92unit test that would spot this error, at least when running on a x86
93machine. In the end, the function `initialize_a()` achieved its goal -
94albeit with an undesired side effect.
95
96### Better tools
97
98In C, the size of an array is just an indication of how much memory
99has to be allocated for it. There is no runtime check when accesing an
100element. Most compilers can check for *static* out-of-bound accesses, i.e.
101`int a[10]; a[11] = 0` will result in a warning (not even an error!)
102at compile time. But even this would have not spotted my bug.
103
104Tools like [Valgrind](https://valgrind.org) can help you analyze this
105kind of memory-related issues, such as accessing unallocated memory
106areas and memory leaks. However, to my surprise, valgrind did not help
107here. I guess this is because the memory I ended up accessing was still
108reserved for my code, just for a different array - or for some padding
109between the two. Or perhaps I should have used more thorough settings.
110
111There are modern languages that try prevent you from shooting yourself
112on the foot, like [Rust](https://www.rust-lang.org). But for me C has a
113huge advantage over any of these better-on-paper alternatives: I know it
114decently well. Another good reason is ubiquity - I don't want to force
115my few potential users to install a whole Rust environment just for nissy!
116
117### Real world checks
118
119Running your software on more platforms and making sure everything
120works as expected is a good way to spot errors that are architecture-
121or compiler-dependent. I am definitely not going to buy a Mac M1 just to
122test out this toy project, but I could at least test it on all the devices
123I have - including my phone. Since it is a command-line application,
124setting up a test suite that runs a bunch of commands and then checks
125that the outpus is as expected would be relatively easy.
126
127## Conclusion
128
129Typing on a phone is painful. Nonetheless, debugging this was actually
130kind of fun.
131
132Knowing some low-level stuff always helps. In this case, I was able to
133reproduce the issue only because I knew that different CPU architectures
134exists, and that a Mac M1 is similar to an Android phone in this regard.
135
136But I also want to stress that this bug was not related to the CPU
137architecture: there was a logic error in my code. The fact that it was
138only visible on ARM is a coincidence. In the end, correct logic is the
139most important thing in coding.
diff --git a/src/blog/2023-05-05-debug-smartphone/termux.jpg b/src/blog/2023-05-05-debug-smartphone/termux.jpg
new file mode 100644
index 0000000..b5318fd
--- /dev/null
+++ b/src/blog/2023-05-05-debug-smartphone/termux.jpg
Binary files differ
diff --git a/src/blog/blog.md b/src/blog/blog.md
index 88c8e8b..be9015d 100644
--- a/src/blog/blog.md
+++ b/src/blog/blog.md
@@ -5,6 +5,7 @@
5 5
6## 2023 6## 2023
7 7
8* 2023-05-05 [I had to debug C code on a smartphone](2023-05-05-debug-smartphone)
8* 2023-04-10 [The big rewrite](2023-04-10-the-big-rewrite) 9* 2023-04-10 [The big rewrite](2023-04-10-the-big-rewrite)
9* 2023-03-30 [The man page reading club: dc(1)](2023-03-30-dc) 10* 2023-03-30 [The man page reading club: dc(1)](2023-03-30-dc)
10* 2023-03-06 [Resizing my website's pictures with ImageMagick and find(1)](2023-03-06-resize-pictures) 11* 2023-03-06 [Resizing my website's pictures with ImageMagick and find(1)](2023-03-06-resize-pictures)
diff --git a/src/blog/feed.xml b/src/blog/feed.xml
index c4fb4d9..58df461 100644
--- a/src/blog/feed.xml
+++ b/src/blog/feed.xml
@@ -9,6 +9,13 @@ Thoughts about software, computers and whatever I feel like sharing
9</description> 9</description>
10 10
11<item> 11<item>
12<title>I had to debug C code on a smartphone</title>
13<link>https://sebastiano.tronto.net/blog/2023-05-05-debug-smartphone</link>
14<description>I had to debug C code on a smartphone</description>
15<pubDate>2023-05-05</pubDate>
16</item>
17
18<item>
12<title>The big rewrite</title> 19<title>The big rewrite</title>
13<link>https://sebastiano.tronto.net/blog/2023-04-10-the-big-rewrite</link> 20<link>https://sebastiano.tronto.net/blog/2023-04-10-the-big-rewrite</link>
14<description>The big rewrite</description> 21<description>The big rewrite</description>

Generated with cgit - Back to sebastiano.tronto.net