Android C++新运算符导致“malloc(4294967295) 失败,errno 12”

Android C++ new operator leads to "malloc(4294967295) failed, errno 12"

提问人:RedStoneMatt 提问时间:6/14/2023 更新时间:6/14/2023 访问量:120

问:

TD公司;博士

我正在将我的一个 C++ 项目移植到 android,但是当使用运算符时,它实际上出于某种原因调用,这会导致内存不足错误,即使调试证明我的类大小正确(并且该项目在为 Windows 构建时有效)。newmalloc(4294967295)

这会导致应用程序在物理 Android 设备上卡在黑屏上,或者只是在模拟器上崩溃

上下文

我目前正在尝试将我的 SDL 项目移植到 android。

为此,我按照官方 SDL 存储库中的教程中的说明进行操作。 此外,我按照本教程将 SDL_image 模块以及 SDL_ttf 添加到我的项目中。

问题

构建应用程序工作正常,但一旦启动,它就会卡在黑屏上:

Screenshot of what the app looks like when booted

弄清楚它发生的原因(调试)

“打印”调试

因此,我将手机插入计算机,并尝试使用打印来调试adb的问题,这是我发现的:

为了初始化 SDL 和其他组件,我的游戏函数如下所示:main

int main(int argc, char* argv[]) {
    __android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Starting");
    srand(time(NULL));

    const int targetFPS = 60;
    const int frameDelay = 1000 / targetFPS;

    // Init
    __android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Constructing Game class of size: %lX", sizeof(Game));
    Game* game = new Game(argc, argv);
    __android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Game constructed");

    __android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Initializing");
    int errInit = game->init("SAE201205", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
    __android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Initialized: %d", errInit);

    if (errInit == 0) {
        while (game->running()) {
            /* Game Logic here */
        }

        game->clean();
    }

    delete game;


    return 0;
}

请注意这些调用,它们在这里帮助调试函数。__android_log_print

在我的手机上启动应用程序并使用 捕获手机日志时,可以看到以下几行:adb logcat

06-14 08:34:35.471  8262  8326 V SDL     : Running main function SDL_main from library /data/app/~~F1pn5U_H13LZFzCic5LLyA==/org.libsdl.app-AHd89RMgz8bystTw8XwclA==/lib/arm/libmain.so
06-14 08:34:35.471  8262  8326 V SDL     : nativeRunMain()
06-14 08:34:35.471  8262  8326 D DEBUG   : Starting
06-14 08:34:35.471  8262  8326 D DEBUG   : Constructing Game class of size: 98
06-14 08:34:35.472  8262  8326 W libc    : malloc(4294967295) failed: returning null pointer, errno: 12

然后应用程序中断。我写的更多印刷品从未被印刷过。

可以看出,当使用 new 运算符时,它会调用 .问题是,它不是用我的 Game 类的大小(0x98,如上所示)调用它,而是用 4294967295 的大小(=0xFFFFFFFF,如果有符号,则为 -1),因此导致 malloc 抛出错误 12(“内存不足”)。malloc

这完全没有意义,因为我显然没有尝试分配 4 GB 的内存,并且由于编译器在打印时正确计算了我的 Game 类的大小,因此它应该尝试分配正确的大小。

拆卸

为了确保确实调用了新的运算符,我在 Ghidra 中打开了包含代码的编译文件。 与我们感兴趣的内容相对应的说明如下:.so

Ghidra screenshot of the relevant instructions可以看出,新运算符确实被调用了。它链接到一个外部函数(因为它是一个共享库构建),但没有错误的 malloc 的痕迹。

但是,传递给新运算符的分配大小似乎代替了打印的 .Ghidra 显示的大小很可能是正确的,因为 android 打印格式似乎存在与此处描述的问题相关的问题(使用 时,编译器会发出警告并要求使用 ,但在使用时会发出警告并要求使用 )。0x1080x98%X%lX%lX%X

我的 Windows 版本给出的大小为 .我关于这种大小差异的理论是,指针大小以及其他原生结构可能不同。0x130

无论哪种方式,无论正确的大小,它都远非 ,因此 malloc 误差不太可能与大小差异有关。0xFFFFFFFF

我的配置

以下是我的项目的配置方式。

首先,它是一个 Gradle 项目,其结构与官方 SDL 存储库中的结构相同

Screenshot of the project's root folder

我的应用文件(这里)如下:Application.mk

    # Uncomment this if you're using STL in your project
    # You can find more information here:
    # https://developer.android.com/ndk/guides/cpp-support
    APP_STL := c++_shared

    APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

    # Min runtime API level
    APP_PLATFORM=android-16

可以看出,我取消了该行的注释,因为我的项目使用了很多 STL 函数。它被设置为默认,但我尝试过并面临相同的结果。此外,并且已弃用,无论如何都不适用于 SDL 项目。APP_STLc++_sharedc++_staticgnustl_sharedgnustl_static

位于同一文件夹(此处)中的文件如下所示:CMakeLists.txt

    cmake_minimum_required(VERSION 3.6)

    project(GAME)

    # armeabi-v7a requires cpufeatures library
    # include(AndroidNdkModules)
    # android_ndk_import_module_cpufeatures()


    # SDL sources are in a subfolder named "SDL"
    add_subdirectory(SDL)

    # Compilation of companion libraries
    add_subdirectory(SDL_image)
    #add_subdirectory(SDL_mixer)
    add_subdirectory(SDL_ttf)

    # Your game and its CMakeLists.txt are in a subfolder named "src"
    add_subdirectory(src)

位于我的项目的 C++ 源文件夹(此处)中的文件如下所示:Android.mk

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := main

    SDL_PATH := ../SDL

    LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include $(LOCAL_PATH)/../SDL_image/include $(LOCAL_PATH)/../SDL_ttf/include $(LOCAL_PATH)/../include

    # Add your application source files here...
    LOCAL_SRC_FILES := main.cpp <all my other cpp files here, irrelevant so not including them>

    LOCAL_SHARED_LIBRARIES := SDL2 SDL2_image SDL2_ttf

    LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid

    include $(BUILD_SHARED_LIBRARY)

据我所知,我没有编辑任何其他配置文件(并检查过)。请随时询问您是否需要我未在此处包含的特定文件的内容。

我现在在哪里

这种问题太具体了,很难找到遇到任何接近这个问题的人,所以我什么也没找到

提醒一下,该项目编译并适用于 Windows,我在这里遇到的问题是 android 独有的。

如果我能推测,我会说 c++ 库只是一个我错过的选项来支持运算符,但我找不到任何东西,而且我对 android 开发非常陌生,所以我不能肯定地说。new

Android C++ Gradle malloc SDL

评论

2赞 Some programmer dude 6/14/2023
类构造函数在做什么?似乎分配正在其中进行。请创建一个最小的可重现示例向我们展示。Game
0赞 RedStoneMatt 6/14/2023
Game 类构造函数初始化其他组件,但考虑到抛出的错误提到了内存分配,它很可能是分配部分,而不是类构造本身。但是,我会研究它,看看它可能不是来自另一个组件,并会在这里讲述。当我有更多时间时,我会做一个最小的可重现示例,完成后会在这里发布。
0赞 G.M. 6/14/2023
即使你没有在类构造函数中显式分配内存,也可能有其他原因导致这些分配发生——例如,容器等被初始化。std::vector
0赞 john 6/14/2023
@RedStoneMatt 你已经证明失败的分配不是游戏的分配,游戏构造函数有错是显而易见的下一个可能性。
1赞 john 6/14/2023
@RedStoneMatt 无论如何,有一个简单的测试可以进行,替换为 .(您需要更改其余部分,因为不再是指针,但这微不足道)。没有明显的需要分配 Game 对象,如果您仍然有崩溃证明它是构造器。Game* game = new Game(argc, argv);Game game(argc, argv);maingame

答:

0赞 RedStoneMatt 6/14/2023 #1

我发现了问题所在。

正如评论者所指出的,Game 类的构造函数有问题,而不是内存分配本身。

我以为我已经删除了所有可能导致崩溃的东西,但那是不知道即使没有明确说明类的成员也会被构造,这导致了崩溃,因为他们中的一些人以 Windows 方式请求文件。

不好意思!