kcat / openal-soft

OpenAL Soft is a software implementation of the OpenAL 3D audio API.
Other
2.23k stars 536 forks source link

Array iterator out of bounds when attaching effect to effect slot #969

Closed bshafi closed 9 months ago

bshafi commented 9 months ago

I'm currently trying to add sound effects to my engine. I'm on Windows. I'm loading ogg files using stb_vorbis and everything was working fine. I was able to play, adjust volume, and everything else to a ogg file. Then I tried to add reverb and now I'm getting array out of bounds error. I was able to reproduce the bug in the example alreverb.c. I have created a fork that demonstrates this bug https://github.com/bshafi/openal-soft-windows-bug-fork.

The exact error : Expression: cannot seek array iterator after end

I've traced it in the debug to reverb.cpp line 1198:

void ReverbPipeline::update3DPanning(const al::span<const float,3> ReflectionsPan,
    const al::span<const float,3> LateReverbPan, const float earlyGain, const float lateGain,
    const bool doUpmix, const MixParams *mainMix)
{
    /* Create matrices that transform a B-Format signal according to the
     * panning vectors.
     */
    const auto earlymat = GetTransformFromVector(ReflectionsPan);
    const auto latemat = GetTransformFromVector(LateReverbPan);

    const auto [earlycoeffs, latecoeffs] = [&]{
        if(doUpmix)
        {
            /* When upsampling, combine the early and late transforms with the
             * first-order upsample matrix. This results in panning gains that
             * apply the panning transform to first-order B-Format, which is
             * then upsampled.
             */
            auto mult_matrix = [](const al::span<const std::array<float,4>,4> mtx1)
            {
                auto&& mtx2 = AmbiScale::FirstOrderUp;
                std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> res{};

                for(size_t i{0};i < mtx1[0].size();++i)
                {
                    const al::span dst{res[i]};
                    for(size_t k{0};k < mtx1.size();++k)
                    {
                        const float a{mtx1[k][i]};
                        std::transform(dst.begin(), dst.end(), mtx2[k].begin(), dst.begin(),
                            [a](const float out, const float in) noexcept -> float
                            { return out + a*in; });
                    }
                }

                return res;
            };
            return std::make_pair(mult_matrix(earlymat), mult_matrix(latemat));
        }

        /* When not upsampling, combine the early and late A-to-B-Format
         * conversions with their respective transform. This results panning
         * gains that convert A-Format to B-Format, which is then panned.
         */
        auto mult_matrix = [](const al::span<const std::array<float,NUM_LINES>,4> mtx1,
            const al::span<const std::array<float,4>,4> mtx2)
        {
            std::array<std::array<float,MaxAmbiChannels>,NUM_LINES> res{};

            for(size_t i{0};i < mtx1[0].size();++i)
            {
                const al::span dst{res[i]};
                for(size_t k{0};k < mtx1.size();++k)
                {
                    const float a{mtx1[k][i]};
                    std::transform(dst.begin(), dst.end(), mtx2[k].begin(), dst.begin(),
                        [a](const float out, const float in) noexcept -> float
                        { return out + a*in; }); // <-------------------------------------------------  HERE
                }
            }

            return res;
        };
        return std::make_pair(mult_matrix(EarlyA2B, earlymat), mult_matrix(LateA2B, latemat));
    }();

    auto earlygains = mEarly.Gains.begin();
    for(auto &coeffs : earlycoeffs)
        ComputePanGains(mainMix, coeffs, earlyGain, (earlygains++)->Target);
    auto lategains = mLate.Gains.begin();
    for(auto &coeffs : latecoeffs)
        ComputePanGains(mainMix, coeffs, lateGain, (lategains++)->Target);
}

Here is the callstack:

    OpenAL32.dll!std::_Array_const_iterator<float,4>::_Verify_offset(const __int64 _Off) Line 178
    at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\array(178)
OpenAL32.dll!std::_Get_unwrapped_n<std::_Array_const_iterator<float,4> const &,__int64>(const std::_Array_const_iterator<float,4> & _It, const __int64 _Off) Line 1256
    at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xutility(1256)
OpenAL32.dll!std::transform<float *,std::_Array_const_iterator<float,4>,float *,````anonymous namespace'::ReverbPipeline::update3DPanning'::`2'::<lambda_1>::operator()'::`2'::<lambda_2>::operator()'::`8'::<lambda_1>>(float * const _First1, float * const _Last1, const std::_Array_const_iterator<float,4> _First2, float * _Dest, `anonymous-namespace'::ReverbPipeline::update3DPanning::__l2::<lambda_1>::()::__l2::<lambda_2>::()::__l8::<lambda_1> _Func) Line 3476
    at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\algorithm(3476)
OpenAL32.dll!`anonymous-namespace'::ReverbPipeline::update3DPanning::__l2::<lambda_1>::()::__l2::<lambda_2>::operator()(const al::span<std::array<float,4> const ,4> mtx1, const al::span<std::array<float,4> const ,4> mtx2) Line 1225
    at openal-soft-windows-bug-fork\alc\effects\reverb.cpp(1225)
OpenAL32.dll!`anonymous-namespace'::ReverbPipeline::update3DPanning::__l2::<lambda_1>::operator()() Line 1230
    at openal-soft-windows-bug-fork\alc\effects\reverb.cpp(1230)
OpenAL32.dll!`anonymous namespace'::ReverbPipeline::update3DPanning(const al::span<float const ,3> ReflectionsPan, const al::span<float const ,3> LateReverbPan, const float earlyGain, const float lateGain, const bool doUpmix, const MixParams * mainMix) Line 1177
    at openal-soft-windows-bug-fork\alc\effects\reverb.cpp(1177)
OpenAL32.dll!`anonymous namespace'::ReverbState::update(const ContextBase * Context, const EffectSlot * Slot, const std::variant<std::monostate,ReverbProps,AutowahProps,ChorusProps,FlangerProps,CompressorProps,DistortionProps,EchoProps,EqualizerProps,FshifterProps,ModulatorProps,PshifterProps,VmorpherProps,DedicatedDialogProps,DedicatedLfeProps,ConvolutionProps> * props_, const EffectTarget target) Line 1305
    at openal-soft-windows-bug-fork\alc\effects\reverb.cpp(1305)
OpenAL32.dll!`anonymous namespace'::CalcEffectSlotParams(EffectSlot * slot, EffectSlot * * sorted_slots, ContextBase * context) Line 511
    at openal-soft-windows-bug-fork\alc\alu.cpp(511)
OpenAL32.dll!`anonymous namespace'::ProcessParamUpdates(ContextBase * ctx, const al::span<EffectSlot *,-1> slots, const al::span<Voice *,-1> voices) Line 1893
    at openal-soft-windows-bug-fork\alc\alu.cpp(1893)
OpenAL32.dll!`anonymous namespace'::ProcessContexts(DeviceBase * device, const unsigned int SamplesToDo) Line 1922
    at openal-soft-windows-bug-fork\alc\alu.cpp(1922)
OpenAL32.dll!DeviceBase::renderSamples(const unsigned int numSamples) Line 2141
    at openal-soft-windows-bug-fork\alc\alu.cpp(2141)
OpenAL32.dll!DeviceBase::renderSamples(void * outBuffer, const unsigned int numSamples, const unsigned __int64 frameStep) Line 2194
    at openal-soft-windows-bug-fork\alc\alu.cpp(2194)
OpenAL32.dll!`anonymous namespace'::WasapiPlayback::mixerProc() Line 1172
    at openal-soft-windows-bug-fork\alc\backends\wasapi.cpp(1172)
[External Code]

It seems like there is a bug in the mult_matrix lambda expression. The size of the array does not match.

kcat commented 9 months ago

Should be fixed in commit 526bb940b55a864e829c28f1100bd88393672467.

bshafi commented 9 months ago

I created this issue, went to sleep, and woke up to find this issue resolved! Thank you