devkitPro / newlib

fork from sourceware git://sourceware.org / newlib-cygwin.git
https://devkitpro.org
GNU General Public License v2.0
22 stars 16 forks source link

[v/s/n]printf is not thread safe #27

Closed xfangfang closed 1 year ago

xfangfang commented 1 year ago

With the latest version of devkitpro, compiling and running the following code results in an error. However, when using an older version (newlib 4.2.0), it runs fine.

This code continuously calls vsnprnitf from both the main and another thread:

#include <cstdarg>
#include <cstdio>
#include <thread>

#include <switch.h>

static bool running = true;

void print(const char *format, ...) {
    char data;
    va_list args;
    va_start(args, format);
    vsnprintf(&data, 1, format, args);
    va_end(args);
}

static void startPrint() {
    while (running) {
        print("%f\n", 1.0);
    }
}

int main(int argc, char **argv)
{
    consoleInit(NULL);
    padConfigureInput(1, HidNpadStyleSet_NpadStandard);
    PadState pad;
    padInitializeDefault(&pad);
    printf("\x1b[16;20HHello World!");

    // start a new thread to call `print`
    std::thread printThread(startPrint);

    while(appletMainLoop())
    {
        padUpdate(&pad);
        u64 kDown = padGetButtonsDown(&pad);
        if (kDown & HidNpadButton_Plus) break;
        consoleUpdate(NULL);

        // call `print` at main thread
        print("%f\n", 1.0);
    }

    running = false;
    if (printThread.joinable()) printThread.join();
    consoleExit(NULL);
    return 0;
}

Here is the project code that includes the makefile: hello-world.zip

I am trying to find out exactly where the problem is, but unfortunately, due to my limited understanding of newlib, there has been no progress so far.

xfangfang commented 1 year ago

Here are what I have discovered (please don't believe anything I say, as I am not familiar with newlib):

  1. %d will not report an error,%f will.

Based on my search results, newlib may dynamically request memory when using %f in [v\s\n]printf . But when I try to use malloc within the print function, it does not trigger an error.

  1. Using aarch64-none-elf-addr2line to view stack information, the error will randomly appear in two threads, and here is the error content for one of them:

Atmosphere crach code: 2168-0002

$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0xc27c
0x000000000000c27c: _EntryWrap at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x93c8
0x00000000000093c8: __thread_entry at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x1314c
0x000000000001314c: execute_native_thread_routine at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0xc30
0x0000000000000c30: startPrint() at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0xbe8
0x0000000000000be8: print(char const*, ...) at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x1e050
0x000000000001e050: vsnprintf at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x1dfa0
0x000000000001dfa0: _vsnprintf_r at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x2d964
0x000000000002d964: _svfprintf_r at :?
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x2b0e0
0x000000000002b0e0: _dtoa_r at :?

# pc
$ aarch64-none-elf-addr2line -e hello-world.elf -f -p -C -a 0x30738
0x0000000000030738: _Balloc at :?

According to my decompilation results, the location of 0x30738 is in newlib/libc/stdlib/mprec.c#L122:

https://github.com/devkitPro/newlib/blob/c561f356fc324a25951b3c3b1f75edc3811459c4/newlib/libc/stdlib/mprec.c#L101-L138

xfangfang commented 1 year ago

@WinterMute

I'm very sorry to @ you, I'm afraid you missed this issue.

This issue has been bothering me for a long time. I know that add some lock can avoid this, but I'm not sure if it's the best way.

Welcome any suggestions. Thanks for your kind attention and look forward your reply.

xfangfang commented 1 year ago

Fixed with devkitA64 r22.1

WinterMute commented 1 year ago

Again, many thanks for hunting down the issue & providing a fix. Much appreciated.

xfangfang commented 1 year ago

That's just a small fix. I have also learned a lot in the days of finding the problem, and I am very grateful to devkitpro for providing the development environment for the switch.