https://bugs.winehq.org/show_bug.cgi?id=46918
Bug ID: 46918 Summary: Call of Duty: Black Ops crashes when using FAudio Product: Wine Version: 4.4 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: xaudio2 Assignee: wine-bugs@winehq.org Reporter: andrey.goosev@gmail.com Distribution: ---
Created attachment 64007 --> https://bugs.winehq.org/attachment.cgi?id=64007 log
Game crashes right after clicking LMB to skip intro movie.
err:seh:raise_exception Unhandled exception code c0000005 flags 0 addr 0x509c26
The next scheme helps with entering the main menu: 1. Set xaudio2_7 to 'disabled' 2. Launch game -> Settings -> Audio 3. Change 'Sound Occlusion' option to 'Off' 4. Quit from game 5. Set xaudio2_7 to 'builtin'
but now crash happens when start a campaign.
wine-4.4-232-gc7f323107b
https://bugs.winehq.org/show_bug.cgi?id=46918
pattietreutel katyaberezyaka@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |katyaberezyaka@gmail.com
https://bugs.winehq.org/show_bug.cgi?id=46918
Ethan Lee flibitijibibo@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |flibitijibibo@gmail.com
--- Comment #1 from Ethan Lee flibitijibibo@gmail.com --- More XAPOs...
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #2 from Ethan Lee flibitijibibo@gmail.com --- This one's really strange - there are lots of submix XAPOs that are fine, with the crash happening immediately after the first time a source XAPO's parameters are updated. All the effects are custom implementations made by Treyarch, so no symbols to be found here.
The part that's weird is the Source DSP (which is what it's called), which has a SetParameters implementation that behaves roughly like this:
// ParameterByteSize == 64 void SetParameters(void* pParameters, uint32_t ParameterByteSize) { float* src = (float*) pParameters; float* dst = (float*) this->m_pParameterBlocks + (0 through 2);
for (int i = 0; i < 12; i += 1) { dst[i + 1] = src[i + 4]; } }
This... doesn't make a lot of sense. The typical case is to simply copy pParameters to m_pParameterBlocks with the intended ParameterByteSize, and this just avoids that entirely. I feel like I'm either misinterpreting the assembly or missing some huge detail in how this is meant to work, because these values are what appear to derail the program (IXAPO::Process starts corrupting things). Avoiding the SetParameters for this one XAPO allows everything to function correctly.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #3 from Ethan Lee flibitijibibo@gmail.com --- Cool, so I was actually reading the asm correctly and my debugger was just having a fun day. It actually does
for (int i = 0; i < 16; i += 1) { dst[i] = src[i] }
Which makes more sense than whatever my debugger was doing yesterday, but still doesn't explain why there are 48 bytes just doing nothing in the effect. At least all the values are 0 I guess...? Until we get into Process and then it writes into the parameter buffer some time before crashing on the main thread.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #4 from Ethan Lee flibitijibibo@gmail.com --- I am very smart. 16 floats is 64 bytes. I swear I passed a math class once!
So SetParameters is fine on the surface, but the fact that us calling it causes a crash is still worrying. Interestingly the data that gets dumped into the XAPO's internal parameter buffer is always the same, which means it's either intentional or there's a consistently-reproducible overwrite.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #5 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Ethan Lee from comment #4)
I am very smart. 16 floats is 64 bytes. I swear I passed a math class once!
Are you confusing floats with doubles?
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #6 from Ethan Lee flibitijibibo@gmail.com --- Worse, I had the sense to convert to float when I was reading out the bytes, but still expected 64 values... so I was confusing bytes with floats.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #7 from Ethan Lee flibitijibibo@gmail.com --- More on the "why did I let myself open the disassembly tab" saga:
I stepped through the Source DSP's Process function and it seems the reason for crashing may be an infinite loop. Consider this function...
void Blorp(float4* x, float4* y) { while (x != y) { *x = *y; // Just making something up... x++; } }
For whatever reason it's giving the equivalent of Blorp(0x430, 0x420) when SetParameters is called. This causes infinite overwriting, resulting in corruption in other parts of the engine, which is why the crash doesn't necessarily happen on the audio thread but does always stop when the audio thread is in IXAPO_Process.
When we skip SetParameters it doesn't even go to the routine in question, so unfortunately it's hard to say if there's a corrupted variable without just My First Fuzzing the thing.
https://bugs.winehq.org/show_bug.cgi?id=46918
Paul Gofman gofmanp@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |gofmanp@gmail.com
--- Comment #8 from Paul Gofman gofmanp@gmail.com --- Created attachment 66683 --> https://bugs.winehq.org/attachment.cgi?id=66683 PoC hack for FAudio
I've tested the game.
Unlike somewhat similar looking problem in Bug #46725 where the game's xapos were ignoring buffer sizes provided in _LockForProcess, this game is mindful about these parameters. But unfortunately it gets zero MaxFrameCount for the problematic xapo. Then it overwrites some data in xapos's _Process function and things go weird.
This happens probably because the voice's number of samples is not initialized at voice creation, this is done later. Application sets effect chain before number of samples is initialized for the voice.
The attached proof of concept hack is fixing the issue for me. Please note that the correct value of 480 (for audio frequency present in game) is important, if I set 512 there the game crashes as well, so it is sort of dependent on Bug #46725.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #9 from Ethan Lee flibitijibibo@gmail.com --- This seems like a pretty good indicator that SetOutputVoices and SetEffectChain are even more tightly-coupled together than we already knew. What most likely needs to happen is a merge of the all the code in those functions into a single FAudio_INTERNAL_ValidateVoiceOutput so that all the validation happens together, meaning we always have enough information for all the little details in the voices (in this case, whether or not we can lock the XAPO for processing).
The good news is that the mix thread is already smart enough to not do any processing when there’s no output, we just need to be smart enough to not lock the effects until we have those output voices.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #10 from Paul Gofman gofmanp@gmail.com --- Yes, can’t it be that Windows just calls _LockForProcess only when the voice chain is initialized and about to start? Why would they make a separate function otherwise? If that is the case then there is the room for other problems in apps which get that called at the wrong moment. But this probably can’t be guessed without testing on Windows. IIRC when I was running my test for the previous bug with additional logging Windows did not call _Lock on adding effect, but that is something to be verified.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #11 from Ethan Lee flibitijibibo@gmail.com --- Played around with the official XAPO example projects and discovered some interesting rules from some debug assertion failures. I also discovered that SetOutputVoices was a complete mess and was doing things in just about the worst order possible. I've made a new commit to address all of these things:
https://github.com/FNA-XNA/FAudio/commit/f6df13f507261268debef92846f68b10792...
So now it should have a valid MaxFrameCount when applying an effect chain on a voice with no sends.
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #12 from Paul Gofman gofmanp@gmail.com --- (In reply to Ethan Lee from comment #11)
Played around with the official XAPO example projects and discovered some interesting rules from some debug assertion failures. I also discovered that SetOutputVoices was a complete mess and was doing things in just about the worst order possible. I've made a new commit to address all of these things:
https://github.com/FNA-XNA/FAudio/commit/ f6df13f507261268debef92846f68b107929e7bb
So now it should have a valid MaxFrameCount when applying an effect chain on a voice with no sends.
Will all go right if the application calls SetEffectChain on source or submix voice before setting output voice? And if Windows indeed calls LockForProcess later (not sure if it is the case) should not FAudio do the same?
https://bugs.winehq.org/show_bug.cgi?id=46918
--- Comment #13 from Ethan Lee flibitijibibo@gmail.com --- As long as the output sample rates match when calling SetOutputVoices after SetEffectChain it should be okay, otherwise that’s an error even in XAudio2. I was also able to verify that LockForProcess is called during SetEffectChain (or voice creation, if a chain is passed).
https://bugs.winehq.org/show_bug.cgi?id=46918
Andrey Gusev andrey.goosev@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |NOTOURBUG Status|NEW |RESOLVED
--- Comment #14 from Andrey Gusev andrey.goosev@gmail.com --- Marking fixed.