

So I gave the actual code a one minute look (literally).
Picked src/radicle/util.c, since that was the last file touched.
The level of defensive programming doesn’t look that good (and I’m trying to be nice here).
Here is an example, and note that I didn’t do C in a while:
#include <stdio.h>
#include <string.h>
void rad_rstrip_nl(char* str) {
int len_str = strlen(str);
if (str[len_str-1]=='\n') {
str[len_str-1] = 0;
}
}
bool rad_get_input (char* str, size_t bufsiz) {
if (!fgets(str,bufsiz,stdin)) return false;
rad_rstrip_nl(str);
return true;
}
int main() {
char a[] = {0,0,0,0};
bool i = rad_get_input(a, 4);
printf("%lu\n", strlen(a));
rad_rstrip_nl(a);
return i;
}
The two functions above main() are copy-pasted from that file.
Let’s zoom in:
int len_str = strlen(str);
if (str[len_str-1]=='\n') {
Here we’re accessing str[len_str-1] without checking len_str first.
But you might be thinking, maybe len_str can’t be zero!
Let’s compile first with the AddressSanitizer enabled:
# compile
% gcc -Wall -fsanitize=address t.c -o t
Now let’s see how easily we can have fun:
% echo -n '\0' | ./t
=================================================================
==2949689==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ba827af001f at pc 0x56032434d259 bp 0x7fff1d199010 sp 0x7fff1d199000
READ of size 1 at 0x7ba827af001f thread T0
#0 0x56032434d258 in rad_rstrip_nl (/tmp/t+0x1258) (BuildId: 1ee68e4d67960002de80ae290c8811c63f94aa51)
#1 0x56032434d311 in rad_get_input (/tmp/t+0x1311) (BuildId: 1ee68e4d67960002de80ae290c8811c63f94aa51)
#2 0x56032434d3e4 in main (/tmp/t+0x13e4) (BuildId: 1ee68e4d67960002de80ae290c8811c63f94aa51)
#3 0x7fa82a227740 (/usr/lib/libc.so.6+0x27740) (BuildId: 020d6f7c33b2413f4fe10814c4729dce1387f049)
#4 0x7fa82a227878 in __libc_start_main (/usr/lib/libc.so.6+0x27878) (BuildId: 020d6f7c33b2413f4fe10814c4729dce1387f049)
#5 0x56032434d124 in _start (/tmp/t+0x1124) (BuildId: 1ee68e4d67960002de80ae290c8811c63f94aa51)
(The rest of AddressSanitizer output omitted.)
Another function from the same file:
char* rad_strcpy (char* out, const char* inp, int from, int len) {
const char* inp_shifted = inp+from;
int len_inp_shifted = strlen(inp_shifted);
if (len <= len_inp_shifted) {
memcpy(out,inp,len);
out[len] = 0;
}
else {
memcpy(out,inp,len_inp_shifted);
out[len_inp_shifted] = 0;
}
return out;
}
Here, inp is shifted before inp length is checked, which doesn’t look safe. But my one minute is up, so I didn’t dive into the function callers.
Pretending C is a good choice in 2026, then not being extra vigilant with defensive programming, is not a good look. I remember myself being more vigilant in my wrappers even when I was a beginner.
This is made worse by the developer repeating literal memes like:
One issue I have with rust is that it adds another layer of trusting the compiler isn’t backdoored. All UNIX/Linux systems use the gcc toolchain
Maybe such an enlightened developer should know that you can bootstrap rustc from mrustc using GCC.
Did you expect him to just outright admit that you paid for granite and got Swiss cheese 🙂 👋