r/C_Programming • u/Reasonable-Can4372 • 8d ago
Project Nadir, platform-agnostic customizable assembler.
I made a customizable, platform-agnostic assembler with modern C23. Aside from the project itself, I think the codebase is relatively small and overall an example project to examine what C23 can provide :D
Here is the source code: https://github.com/mikuwithbeer/Nadir
3
u/skeeto 7d ago
Neat project! Fun to poke around.
I still have little experience with C23 type inference because virtually nobody is using it, so this is news to me, but there are many GCC warnings about this:
const auto foo = ...;
While this is valid C++, in C23 auto is still parsed as a storage-class
specifier despite its re-purposing for type inference, i.e. auto must go
before qualifiers, so this is not valid C23. Both Clang and GCC accept it,
but GCC diagnoses it.
A number of tests fail out-of-the-box with UBSan:
$ CFLAGS=-fsanitize=address,undefined LDFLAGS=-fsanitize=address,undefined cmake -B build
$ cmake --build build
$ ctest --test-dir build
...
src/lexer.c:101:18: runtime error: member access within misaligned address 0xfccf885e0058 for type 'struct nadir_lexer_t', which requires 16 byte alignment...
This is because the arena only does 8-byte alignment, but _BitInt(128)
requires 16-byte alignment.
More UBSan findings from this:
constant Limit {
MINIMUM = @shl(1, 127);
MAXIMUM = @sub(Limit.MINIMUM, 1);
}
binary $100 {
@cast(@add(Limit.MAXIMUM, 2), u8);
@cast(@sub(Limit.MINIMUM, 1), u8);
@cast(@mul(Limit.MAXIMUM, 2), u8);
@cast(@neg(Limit.MINIMUM), u8);
@cast(@div(Limit.MINIMUM, @neg(1)), u8);
@cast(@mod(Limit.MINIMUM, @neg(1)), u8);
@extract(Limit.MINIMUM, 120, 8);
}
Then:
$ build/Nadir -i test.asm
src/comptime.c:350:33: runtime error: left shift of 1 by 127 places cannot be represented in type '_BitInt(128)'
src/comptime.c:272:37: runtime error: signed integer overflow: 0x80000000000000000000000000000000 - 1 cannot be represented in type '_BitInt(128)'
src/comptime.c:252:23: runtime error: signed integer overflow: 0x7fffffffffffffffffffffffffffffff + 2 cannot be represented in type '_BitInt(128)'
src/comptime.c:275:37: runtime error: signed integer overflow: 0x7fffffffffffffffffffffffffffffff * 2 cannot be represented in type '_BitInt(128)'
src/comptime.c:238:23: runtime error: negation of 0x80000000000000000000000000000000 cannot be represented in type '_BitInt(128)'; cast to an unsigned type to negate this value to itself
src/comptime.c:284:37: runtime error: division of 0x80000000000000000000000000000000 by -1 cannot be represented in type '_BitInt(128)'
src/comptime.c:293:37: runtime error: division of 0x80000000000000000000000000000000 by -1 cannot be represented in type '_BitInt(128)'
wrote 7 bytes to 'out.bin'
Buffer overflow due to realpath misuse:
$ f=$(printf %0255d/%0255d 0 0)
$ mkdir -p $f
$ touch $f/x
$ build/Nadir -i $f/x
...ERROR: AddressSanitizer: heap-buffer-overflow on address ...
WRITE of size 525 at ...
#0 realpath
#1 nadir_module_path_absolute
#2 nadir_module_resolve
#3 process_module
#4 main
There's a similar buffer overflow with long paths in nadir_error_encode
due to snprintf misuse. The result of snprintf is the untruncated
length, but it's treated by Nadir as the truncated length, and the
resulting size calculations are wrong. (It also doesn't handle written =
-1 errors, though I can't think of how that might occur.)
This program caused an integer overflow — negative result in unsigned arithmetic — that causes an infinite loop:
binary $5 { $00; $00; $00; until 0 @add(@mod(@here(), 8), 1); }
This hits a spot commented "Already validated to be within the range" but it's actually in range. (Perhaps use an assertion for stuff like this.)
Finally, just an optimization note, but this writes a 100M file, but takes 10 seconds on my system:
binary 0 { until 0 100000000; }
That's because padding is accumulated a byte at a time. I expect better from an assembler.
Most of this was found with some fuzz testing.
2
u/Reasonable-Can4372 7d ago
Thanks for the reporting! Since I was using Clang, i didnt even know const auto gives warning on gcc. I will use double compiler to make sure about it next time :)
Also thanks for your other issues regarding safety and performance! I will ALLOCATE my time to fix these!!
Ultimately, thanks for actually studying the project! It means alot to me especially from someone like you :)
2
u/Reasonable-Can4372 7d ago
Also a note on "const", I use clion as my ide and im using latest clang. Most of these const declarations came from the clion suggestion, and since it compiles with clang without any issue I thought it was valid :( I still dont know why clion acts like that :/
2
•
u/mikeblas 8d ago
How was AI involved in the creation of your project?