androidc++android-ndkcrashopenal

OpenAL application crashes/hangs when I pass non-nullptr to `alBufferData()` from native code


I'm trying to play some sound on Android using OpenAL and C/C++. I'm using SDL framework.

I keep getting mysterious crashes with alBufferData() even when my code is as simple as:

ALuint buf, src;
alGenBuffers(1, &buf);
alGenSources(1, &src);
uint8_t data[8000]{};
alBufferData(buf, AL_FORMAT_MONO8, data, 8000, 8000);
alSourcei(src, AL_BUFFER, buf);
alSourcePlay(src);

Every time the program reaches alBufferData() it crashes or hangs. I'm not getting any kind of error message.

Surprisingly enough, if I pass 0 instead of actual pointer to alBufferData(), then the program runs fine and plays some random noise.

I have absolutely no idea what's wrong.

MCVE:

#include <cstdlib>
#include <cmath>
#include <string>

#include <SDL2/SDL.h>
#include <AL/al.h>
#include <AL/alc.h>

#if !defined(ANDROID) && !defined(__ANDROID__)
#define GLEW_STATIC
#include <GL/glew.h>
#else
#include <GLES2/gl2.h>
#endif

void Msg(const char *txt)
{
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "test app", txt, 0);
}
void Err(const char *txt)
{
    Msg(txt);
    std::exit(0);
}

int SDL_main(int, char **)
{
    Msg("Running build compiled at " __DATE__ " " __TIME__);

    if (SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO))
        Err("SDL init failed");
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    #if !defined(ANDROID) && !defined(__ANDROID__)
    SDL_Window *win = SDL_CreateWindow("test app", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    #else
    SDL_Window *win = SDL_CreateWindow("test app", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_FULLSCREEN);
    #endif
    if (!win)
        Err("Window creation failed");
    SDL_GLContext con = SDL_GL_CreateContext(win);
    if (!con)
        Err("OpenGL context creation failed");
    #if !defined(ANDROID) && !defined(__ANDROID__)
    glewExperimental = 1;
    if (glewInit() != GLEW_OK)
        Msg("GLEW init failed");
    while (glGetError()) {}
    #endif
    SDL_GL_SetSwapInterval(1);

    ALCdevice *device = alcOpenDevice(0);
    if (!device)
        Err("OpenAL init failed");
    const ALCint config_array[] = {ALC_FREQUENCY, 44100, ALC_MONO_SOURCES, 4, ALC_STEREO_SOURCES, 4, 0};
    ALCcontext *context = alcCreateContext(device, config_array);
    if (!context)
        Err("OpenAL context creation failed");
    if (!alcMakeContextCurrent(context))
        Err("OpenAL context switching failed");


    uint8_t sound_wave[8000];
    for (int i = 0; i < 8000; i++)
    {
        float pi = std::atan(1)*4;
        sound_wave[i] = int(std::pow(std::sin(i * pi / 180 * 4),0.5) * 127) + 127;

        auto smoothstep = [](float x){return 2*x*x*x-3*x*x;};
        if (i < 1000)
            sound_wave[i] *= smoothstep(i / 1000.f);
        else if (i >= 7000)
            sound_wave[i] *= smoothstep((8000 - i) / 1000.f);
    }

    ALuint buf, src;
    int frames = 0;

    while (1)
    {
        SDL_Event event;
        bool click = 0;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
              case SDL_QUIT:
                std::exit(0);
                break;
              case SDL_KEYDOWN:
                click = 1;
                break;
            }
        }

        switch (frames)
        {
          case 3:  Msg("Creating a buffer");   break;
          case 4:  alGenBuffers(1, &buf); if (!buf) Err("No buffer"); break;
          case 5:  Msg("Creating a source");   break;
          case 6:  alGenSources(1, &src); if (!src) Err("No source"); break;
          case 7:  Msg("Setting buffer data"); break;
          case 8:
            alBufferData(buf, AL_FORMAT_MONO8, sound_wave, 8000, 8000);
            if (int err = alGetError()) // This code is not reached
                Msg((std::string("Error code: ") + std::to_string(err)).c_str());
            break;
          case 9:  Msg("Attaching buffer");    break;
          case 10: alSourcei(src, AL_BUFFER, buf);  break;
          case 11: Msg("Done");                break;
        }
        if (frames < 12)
            frames++;

        if (frames == 12 && click)
            alSourcePlay(src);

        SDL_GL_SwapWindow(win);
    }
}

Here is my Application.mk:

APP_ABI := armeabi armeabi-v7a x86 mips

APP_STL := c++_shared

LOCAL_SHARED_LIBRARIES := c++_shared
APP_CFLAGS += -w
APP_CPPFLAGS += -fexceptions -frtti -I../lib/include
APP_CPPFLAGS += -std=c++14 -O3 -s
NDK_TOOLCHAIN_VERSION := clang

I'm using OpenAL which was prebuilt using standalone toolchains. I don't know if it matters, but here is my build command (this one is for armv7-a, for other ABIs there are different commands):

cmake -D CMAKE_SYSTEM_NAME:string=android -D CMAKE_C_COMPILER:filepath="Y:/clang_3.8_android_api12_androideabi/bin/arm-linux-androideabi-clang.cmd" ^
                                          -D CMAKE_CXX_COMPILER:filepath="Y:/clang_3.8_android_api12_androideabi/bin/arm-linux-androideabi-clang++.cmd" ^
                                          -D CMAKE_C_FLAGS:string="-w -O3 -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" ^
                                          -D CMAKE_CXX_FLAGS:string="-w -O3 -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" ^
                                          -D CMAKE_SHARED_LINKER_FLAGS:string="-lc++_shared" ^
                                          -D CMAKE_MODULE_LINKER_FLAGS:string="-lc++_shared" ^
                                          -D CMAKE_BUILD_TYPE:string="Release" ^
                                          -G "MinGW Makefiles" ^
                                          ../../..
mingw32-make.exe

EDIT:

Now it's getting more interesting. I've managed to make it work once, but after a tiny unrelated change to the source code it broke again.

There MUST be some kind undefined behaviour somewhere, but I'm sure it's not on my side.

Is it a bug in OpenAL? The exact version I'm using is openal-soft-1.17.1.

EDIT:

Updated to OpenAL 1.17.2. No luck, same error.

EDIT:

Here is logcat output for the mcve from the emulator.
It's hosted externally because it's 2000+ lines long.

If I understood correctly, the log says that there is a heap corruption and that that application had sigsegv'ed in dlmalloc(). But I have no idea how to fix it.

I've tried to add SDL_INIT_AUDIO flag to SDL_Init() - same error.


Solution

  • It seems like a bug in OpenAL, which also affects MacOS. It should be already fixed.

    Also it crashes only when the library is built in "Release" or "RelWithDebInfo" modes. Switching to any random string or "Debug" fixes the issue.