最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Calling Play method of DirectSoundBuffer object causes crash under address sanitizer - Stack Overflow

programmeradmin2浏览0评论

I'm getting my app crash when running my code under asan and executing Play method of the sound buffer object.

I have several classes related to sound creating. The first one is the struct that contains main data of the WAV file.

struct WaveData
{
    WAVEFORMATEX wfx;
    BYTE* pData;
    DWORD dwSize;
};

WAV file is added into the Visual Studio solution as a resource. I'm taking a resource ID for creating a sound object ->

class sound
{
public:
    sound(intptr_t resource_id);
    
    bool is_valid() const noexcept;
    bool play();

    bool load_wave();

    bool create_snd_buffer(const Microsoft::WRL::ComPtr<IDirectSound8>& device);

private:
    bool valid;
    BYTE* locked_resource_;
    HRSRC resource_handle_;
    WaveData native_data_;

    Microsoft::WRL::ComPtr<IDirectSoundBuffer> sound_buffer_;
};


sound::sound(intptr_t resource_id) : valid{}, locked_resource_{}, native_data_{}
{
    resource_handle_ = FindResource(GetModuleHandle(nullptr), MAKEINTRESOURCE(resource_id), xor ("WAVE").c_str());
    if (resource_handle_ && (locked_resource_ = static_cast<BYTE*>(LoadResource(GetModuleHandle(nullptr), resource_handle_))))
        valid = true;
}

The sounds create in the sound manager class ->

class sound_manager
{
public:
    sound_manager(HWND window);
    ~sound_manager();

    bool play(sound_type type);

private:
    std::map<sound_type, std::vector<sound>> sounds;

    std::random_device random_device;
    std::mt19937 numbers;

    Microsoft::WRL::ComPtr<IDirectSound8> sound_device_;
};

sound_manager::sound_manager(HWND window)
{
    if (DirectSoundCreate8(nullptr, &sound_device_, nullptr) == DS_OK)
        sound_device_->SetCooperativeLevel(window, DSSCL_PRIORITY);

    sounds =
    {
        { access,           { IDR_WAVE1, IDR_WAVE7, IDR_WAVE8, IDR_WAVE9 }},
        { me,               { IDR_WAVE3, IDR_WAVE4, IDR_WAVE5 }},
        { shop,             { IDR_WAVE2, IDR_WAVE6, IDR_WAVE11 }},
        { access_fail,      { IDR_WAVE12 }},
        { access_click,     { IDR_WAVE13 }},
        { inject_fail,      { IDR_WAVE10 }},
    };
}

We're executing this code when we call Play method of sound manager ->

bool sound_manager::play(sound_type type)
{
    auto& sound = sounds[type];
    std::uniform_int_distribution engine(0, static_cast<int>(sound.size() - 1));
    auto& snd = sound[engine(numbers)];

    if (!snd.is_valid() && (!snd.load_wave() || !snd.create_snd_buffer(sound_device_)))
        return false;

    return snd.play();
}

is_valid, load_wave, create_snd_buffer ->

bool sound::is_valid() const noexcept
{
    return valid && static_cast<bool>(sound_buffer_) && static_cast<bool>(native_data_.dwSize);
}

bool sound::load_wave()
{
    DWORD resSize = SizeofResource(nullptr, resource_handle_);
    if (!locked_resource_ || resSize < sizeof(RIFFLIST))
        return false;

    RIFFLIST* pRiff = reinterpret_cast<RIFFLIST*>(locked_resource_);
    if (pRiff->chunk.fcc != FOURCC_RIFF || pRiff->fccListType != mmioFOURCC('W', 'A', 'V', 'E'))
        return false;

    BYTE* pWaveEnd = locked_resource_ + resSize;
    BYTE* pChunk = locked_resource_ + sizeof(RIFFLIST);

    WAVEFORMATEX* pFormat = nullptr;
    BYTE* pWaveStart = nullptr;
    DWORD waveSize = 0;

    while (pChunk < pWaveEnd) 
    {
        if (pChunk + sizeof(RIFFCHUNK) > pWaveEnd)
            return false;
        RIFFCHUNK* pCurrent = reinterpret_cast<RIFFCHUNK*>(pChunk);
        DWORD chunkSize = pCurrent->cb;

        if (pCurrent->fcc == mmioFOURCC('f', 'm', 't', ' ')) {
            pFormat = reinterpret_cast<WAVEFORMATEX*>(pChunk + sizeof(RIFFCHUNK));
            if (pCurrent->cb > sizeof(WAVEFORMATEX)) return false;
            memcpy(&native_data_.wfx, pFormat, sizeof(WAVEFORMATEX));
        }
        else if (pCurrent->fcc == mmioFOURCC('d', 'a', 't', 'a')) {
            pWaveStart = pChunk + sizeof(RIFFCHUNK);
            waveSize = pCurrent->cb;
        }

        DWORD padding = (chunkSize % 2) ? 1 : 0;
        pChunk += sizeof(RIFFCHUNK) + chunkSize + padding;
        if (pChunk > pWaveEnd)
            return false;
    }

    if (!pFormat || !pWaveStart || !waveSize) 
        return false;

    native_data_.pData = pWaveStart;
    native_data_.dwSize = waveSize;
    return true;
}

bool sound::create_snd_buffer(const Microsoft::WRL::ComPtr<IDirectSound8>& device)
{
    DSBUFFERDESC dsbd = {};
    dsbd.dwSize = sizeof(DSBUFFERDESC);
    dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
    dsbd.dwBufferBytes = native_data_.dwSize;
    dsbd.lpwfxFormat = &native_data_.wfx; 

    if (FAILED(device->CreateSoundBuffer(&dsbd, &sound_buffer_, nullptr)))
        return false;

    LPVOID pLocked      = nullptr;
    DWORD dwLockedSize  = 0;
    if (SUCCEEDED(sound_buffer_->Lock(0, 0, &pLocked, &dwLockedSize, nullptr, nullptr, DSBLOCK_ENTIREBUFFER)))
    {
        memcpy(pLocked, native_data_.pData, native_data_.dwSize);
        sound_buffer_->Unlock(pLocked, dwLockedSize, nullptr, 0);
    }

    return true;
}

So, after executing these methods to initialize the sound, I'm executing Play method of a sound object and sound buffer.

bool sound::play()
{
    if (!sound_buffer_)
        return false;

    sound_buffer_->SetCurrentPosition(0);
    sound_buffer_->SetVolume(DSBVOLUME_MAX);
    return sound_buffer_->Play(0, 0, 0) == DS_OK;
}

I got crash when reach this line -> return sound_buffer_->Play(0, 0, 0) == DS_OK; And this problem appears only if I'm running the project under address sanitizer.

The asan shows me this crash place in assembly in dsound.dll ->

00007FFF81D14CCC  je          CCommandManager::ParseRegistrationQueue+98h (07FFF81D14D3Ch)  
00007FFF81D14CCE  mov         rdi,qword ptr [rsp+30h]  
00007FFF81D14CD3  cmp         dword ptr [rdi],0  

rdi is 0, but I can't figure out how is it possible if the objects are initialized correctly, the pointers are correct and everything looks well. Help, pls.

I'm getting my app crash when running my code under asan and executing Play method of the sound buffer object.

I have several classes related to sound creating. The first one is the struct that contains main data of the WAV file.

struct WaveData
{
    WAVEFORMATEX wfx;
    BYTE* pData;
    DWORD dwSize;
};

WAV file is added into the Visual Studio solution as a resource. I'm taking a resource ID for creating a sound object ->

class sound
{
public:
    sound(intptr_t resource_id);
    
    bool is_valid() const noexcept;
    bool play();

    bool load_wave();

    bool create_snd_buffer(const Microsoft::WRL::ComPtr<IDirectSound8>& device);

private:
    bool valid;
    BYTE* locked_resource_;
    HRSRC resource_handle_;
    WaveData native_data_;

    Microsoft::WRL::ComPtr<IDirectSoundBuffer> sound_buffer_;
};


sound::sound(intptr_t resource_id) : valid{}, locked_resource_{}, native_data_{}
{
    resource_handle_ = FindResource(GetModuleHandle(nullptr), MAKEINTRESOURCE(resource_id), xor ("WAVE").c_str());
    if (resource_handle_ && (locked_resource_ = static_cast<BYTE*>(LoadResource(GetModuleHandle(nullptr), resource_handle_))))
        valid = true;
}

The sounds create in the sound manager class ->

class sound_manager
{
public:
    sound_manager(HWND window);
    ~sound_manager();

    bool play(sound_type type);

private:
    std::map<sound_type, std::vector<sound>> sounds;

    std::random_device random_device;
    std::mt19937 numbers;

    Microsoft::WRL::ComPtr<IDirectSound8> sound_device_;
};

sound_manager::sound_manager(HWND window)
{
    if (DirectSoundCreate8(nullptr, &sound_device_, nullptr) == DS_OK)
        sound_device_->SetCooperativeLevel(window, DSSCL_PRIORITY);

    sounds =
    {
        { access,           { IDR_WAVE1, IDR_WAVE7, IDR_WAVE8, IDR_WAVE9 }},
        { me,               { IDR_WAVE3, IDR_WAVE4, IDR_WAVE5 }},
        { shop,             { IDR_WAVE2, IDR_WAVE6, IDR_WAVE11 }},
        { access_fail,      { IDR_WAVE12 }},
        { access_click,     { IDR_WAVE13 }},
        { inject_fail,      { IDR_WAVE10 }},
    };
}

We're executing this code when we call Play method of sound manager ->

bool sound_manager::play(sound_type type)
{
    auto& sound = sounds[type];
    std::uniform_int_distribution engine(0, static_cast<int>(sound.size() - 1));
    auto& snd = sound[engine(numbers)];

    if (!snd.is_valid() && (!snd.load_wave() || !snd.create_snd_buffer(sound_device_)))
        return false;

    return snd.play();
}

is_valid, load_wave, create_snd_buffer ->

bool sound::is_valid() const noexcept
{
    return valid && static_cast<bool>(sound_buffer_) && static_cast<bool>(native_data_.dwSize);
}

bool sound::load_wave()
{
    DWORD resSize = SizeofResource(nullptr, resource_handle_);
    if (!locked_resource_ || resSize < sizeof(RIFFLIST))
        return false;

    RIFFLIST* pRiff = reinterpret_cast<RIFFLIST*>(locked_resource_);
    if (pRiff->chunk.fcc != FOURCC_RIFF || pRiff->fccListType != mmioFOURCC('W', 'A', 'V', 'E'))
        return false;

    BYTE* pWaveEnd = locked_resource_ + resSize;
    BYTE* pChunk = locked_resource_ + sizeof(RIFFLIST);

    WAVEFORMATEX* pFormat = nullptr;
    BYTE* pWaveStart = nullptr;
    DWORD waveSize = 0;

    while (pChunk < pWaveEnd) 
    {
        if (pChunk + sizeof(RIFFCHUNK) > pWaveEnd)
            return false;
        RIFFCHUNK* pCurrent = reinterpret_cast<RIFFCHUNK*>(pChunk);
        DWORD chunkSize = pCurrent->cb;

        if (pCurrent->fcc == mmioFOURCC('f', 'm', 't', ' ')) {
            pFormat = reinterpret_cast<WAVEFORMATEX*>(pChunk + sizeof(RIFFCHUNK));
            if (pCurrent->cb > sizeof(WAVEFORMATEX)) return false;
            memcpy(&native_data_.wfx, pFormat, sizeof(WAVEFORMATEX));
        }
        else if (pCurrent->fcc == mmioFOURCC('d', 'a', 't', 'a')) {
            pWaveStart = pChunk + sizeof(RIFFCHUNK);
            waveSize = pCurrent->cb;
        }

        DWORD padding = (chunkSize % 2) ? 1 : 0;
        pChunk += sizeof(RIFFCHUNK) + chunkSize + padding;
        if (pChunk > pWaveEnd)
            return false;
    }

    if (!pFormat || !pWaveStart || !waveSize) 
        return false;

    native_data_.pData = pWaveStart;
    native_data_.dwSize = waveSize;
    return true;
}

bool sound::create_snd_buffer(const Microsoft::WRL::ComPtr<IDirectSound8>& device)
{
    DSBUFFERDESC dsbd = {};
    dsbd.dwSize = sizeof(DSBUFFERDESC);
    dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
    dsbd.dwBufferBytes = native_data_.dwSize;
    dsbd.lpwfxFormat = &native_data_.wfx; 

    if (FAILED(device->CreateSoundBuffer(&dsbd, &sound_buffer_, nullptr)))
        return false;

    LPVOID pLocked      = nullptr;
    DWORD dwLockedSize  = 0;
    if (SUCCEEDED(sound_buffer_->Lock(0, 0, &pLocked, &dwLockedSize, nullptr, nullptr, DSBLOCK_ENTIREBUFFER)))
    {
        memcpy(pLocked, native_data_.pData, native_data_.dwSize);
        sound_buffer_->Unlock(pLocked, dwLockedSize, nullptr, 0);
    }

    return true;
}

So, after executing these methods to initialize the sound, I'm executing Play method of a sound object and sound buffer.

bool sound::play()
{
    if (!sound_buffer_)
        return false;

    sound_buffer_->SetCurrentPosition(0);
    sound_buffer_->SetVolume(DSBVOLUME_MAX);
    return sound_buffer_->Play(0, 0, 0) == DS_OK;
}

I got crash when reach this line -> return sound_buffer_->Play(0, 0, 0) == DS_OK; And this problem appears only if I'm running the project under address sanitizer.

The asan shows me this crash place in assembly in dsound.dll ->

00007FFF81D14CCC  je          CCommandManager::ParseRegistrationQueue+98h (07FFF81D14D3Ch)  
00007FFF81D14CCE  mov         rdi,qword ptr [rsp+30h]  
00007FFF81D14CD3  cmp         dword ptr [rdi],0  

rdi is 0, but I can't figure out how is it possible if the objects are initialized correctly, the pointers are correct and everything looks well. Help, pls.

Share Improve this question asked Mar 31 at 23:16 Sora AoiSora Aoi 513 bronze badges 1
  • 1 Can we have a minimal reproducible example please (emphasis on the word minimal), rather than a jigsaw of code. – catnip Commented Mar 31 at 23:47
Add a comment  | 

1 Answer 1

Reset to default 0
locked_resource_ = static_cast<BYTE*>(LoadResource(GetModuleHandle(nullptr), resource_handle_))

This is wrong. You need to use LockResource() after LoadResource() to get access to the raw bytes of the resource, eg:

sound::sound(intptr_t resource_id) : valid{}, locked_resource_{}, native_data_{}
{
    HMODULE hModule = GetModuleHandle(nullptr);
    resource_handle_ = FindResource(hModule, MAKEINTRESOURCE(resource_id), xor ("WAVE").c_str());
    if (resource_handle_) {
        HGLOBAL hResData = LoadResource(hModule, resource_handle_);
        if (hResData) {
            locked_resource_ = static_cast<BYTE*>(LockResource(hResData));
            valid = (locked_resource_);
        }
    }
}
发布评论

评论列表(0)

  1. 暂无评论