-
-
Notifications
You must be signed in to change notification settings - Fork 190
Description
Born from: rust3ds/ctru-rs#60
Description
After some testing on our Rust libraries for this system, we've noticed a weird bug with the use of thread-local storage. With some investigation, we have pinpointed the problem to the use of aligned thread-local variables. As our tests show, the offset of the variable pointers are wrong when one or more aligned TLS variables exist, causing memory leaks, access of uninitialized memory etc. This issue appears in both Rust and C programs.
Furthermore, this issue seems to only affect (at least in our examples) programs with a debug optimization level.
E.g. :
debug mode in Rust reproduces the bug.
release mode in Rust doesn't reproduce the bug.
-Og in C reproduces the bug.
-O2 in C doesn't reproduce the bug.
Here is a test program to try the issue. Remember to use -Og to replicate:
#include <3ds.h>
#include <stdio.h>
#include <string.h>
typedef ALIGN(4) struct {
u8 inner[3];
} Align4;
typedef ALIGN(16) struct {
u8 inner[3];
} Align16;
static __thread Align4 BUF_4 = {.inner = {2, 2, 2}};
static __thread Align16 BUF_16 = {.inner = {1, 1, 1}};
int
main(int argc, char** argv)
{
gfxInitDefault();
consoleInit(GFX_TOP, NULL);
BUF_16.inner[0] = 0;
bool reproduced = false;
// Check if at least one byte has been offset improperly
printf("[");
for (int i = 0; i < 3; i++) {
if (BUF_4.inner[i] != 2) {
reproduced = true;
}
printf("%d, ", BUF_4.inner[i]);
}
printf("]\n");
if (reproduced) {
printf("Bug has been reproduced!\n");
}
else {
printf("There has been no issue!");
}
// Main loop
while (aptMainLoop()) {
gspWaitForVBlank();
hidScanInput();
u32 kDown = hidKeysDown();
if (kDown & KEY_START)
break; // break in order to return to hbmenu
// Flush and swap framebuffers
gfxFlushBuffers();
gfxSwapBuffers();
}
gfxExit();
return 0;
}Notes about our Rust toolchain
Our Rust programs mainly use libctru (to substitute missing newlib functions), and the arm-none-eabi-gcc linker. Most of the linking flags are the same (basically those in a normal Makefile but in the Rust target-specification). Either way, it's hard to believe this one to be an issue in either of the compilers (rustc and gcc) as the issue reproduces in both. It's likely an issue with libctru or the linker.