Skip to content

devkitARM r67: std::shared_ptr copy and std::weak_ptr creation abort on GBA #70

@Fralacticus

Description

@Fralacticus

Bug Report

What's the issue you encountered?

After recently updating my devkitARM/GBA environment, I started getting a runtime abort on GBA when copying a std::shared_ptr or when creating a std::weak_ptr from a std::shared_ptr.

I tested the same code with two devkitARM versions:

devkitARM r67: does not work
devkitARM r66: works

With devkitARM r67, the program aborts at runtime when the smart pointer reference counter is incremented. With devkitARM r66, the same code runs correctly.

The issue does not depend on Butano. The examples below are plain C++ GBA tests using only the mGBA debug log registers.

How can the issue be reproduced?

Create a C++ source file, for example main.cpp, and compile it for GBA with devkitARM.

Common mGBA logging helper

// mgba_log.hpp
#pragma once

#include <cstdint>

namespace mgba {

    inline void log(const char* message) {
        volatile uint16_t& debug_enable_register =
            *reinterpret_cast<volatile uint16_t*>(0x04FFF780);

        debug_enable_register = 0xC0DE;

        constexpr int max_characters_per_line = 256;

        const char* message_data = message;

        while(*message_data) {
            int characters_to_write = 0;

            volatile char* debug_string_register =
                reinterpret_cast<volatile char*>(0x04FFF600);

            while(message_data[characters_to_write] &&
                  characters_to_write < max_characters_per_line) {
                debug_string_register[characters_to_write] =
                    message_data[characters_to_write];

                ++characters_to_write;
            }

            debug_string_register[characters_to_write] = '\0';

            volatile uint16_t& debug_flags_register =
                *reinterpret_cast<volatile uint16_t*>(0x04FFF700);

            debug_flags_register = uint16_t(2) | 0x100;

            message_data += characters_to_write;
        }
    }

    inline void log_bool(bool value) {
        log(value ? "1" : "0");
    }
}

Test 1: gthread state

// main.cpp
#include "mgba_log.hpp"
#include <bits/gthr.h>
#include <ext/atomicity.h>

void test_gthread_state() {
#ifdef __GTHREADS
    mgba::log("__GTHREADS defined");
    mgba::log("__gthread_active_p =");
    mgba::log_bool(__gthread_active_p());
#else
    mgba::log("__GTHREADS not defined");
#endif

    mgba::log("__is_single_threaded =");
    mgba::log_bool(__gnu_cxx::__is_single_threaded());
}

int main() {
    mgba::log("program start");

    test_gthread_state();

    mgba::log("program end");

    while(true) {
    }
}

With devkitARM r67, I get:

program start
__GTHREADS defined
__gthread_active_p =
1
__is_single_threaded =
0
program end

With devkitARM r66, I get:

program start
__GTHREADS defined
__gthread_active_p =
0
__is_single_threaded =
1
program end

Test 2: std::shared_ptr copy

// main.cpp
#include "mgba_log.hpp"
#include <memory>

void test_shared_ptr_copy() {
    mgba::log("sp make");

    std::shared_ptr<int> original_ptr = std::make_shared<int>(123);

    mgba::log("sp copy before");

    // Runtime abort happens here with devkitARM r67.
    std::shared_ptr<int> copied_ptr = original_ptr;

    mgba::log("sp copy after");
}

int main() {
    mgba::log("program start");

    test_shared_ptr_copy();

    mgba::log("program end");

    while(true) {
    }
}

With devkitARM r67, the output is:

program start
sp make
sp copy before

So std::make_shared<int>(123) succeeds, but copying the resulting std::shared_ptr aborts.

With devkitARM r66, the same test works:

program start
sp make
sp copy before
sp copy after
program end

Environment?

  • Host OS: Windows

  • Shell: devkitPro MSYS2 shell

  • Official release or unofficial/self-compiled build:

    • devkitARM r67: official package
    • devkitARM r66: official on other pc
  • Current compiler:

arm-none-eabi-g++ (devkitARM) 15.2.0

Additional context?

I do not know the exact cause yet, but my initial tests suggest that the smart pointer reference counter may no longer be using the single-threaded path in the r67 devkitARM/libstdc++ build.

Could this be related to the unified buildscript or the libstdc++/gthreads configuration used to build devkitARM r67?
5124435#diff-e472a28f68a79d6f66e4b0f10d1c63e24de38e6eda838e695101a44967efafa1
This change could be related :
--enable-threads --disable-win32-registry --disable-nls --disable-debug
into
--enable-threads=posix --disable-win32-registry --disable-nls --disable-debug \

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions