On Jul 19, 2013, at 8:34 AM, Qian Hong wrote:
I was debugging on a popular game [1] [2] (9 GB), it crashes on start.
+relay,+seh,+tid log show that there are some calls to wined3d.wined3d_mutex_lock / wined3d.wined3d_buffer_map / wined3d.wined3d_mutex_unlock before crashing, so I turn on +d3d9 trace to get a new log in details.
To my surprise, the game doesn't crash anymore with +d3d9 trace!
After a serials of bisect, I found d3d9_AddRef is the key function call related to the crashing. If I remove the TRACE statement in line 71, the game will crash with +d3d9 as well; if I upgrade the TRACE in 71 to FIXME, the game will not crash even without +d3d9.
66 static ULONG WINAPI d3d9_AddRef(IDirect3D9Ex *iface) 67 { 68 struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface); 69 ULONG refcount = InterlockedIncrement(&d3d9->refcount); 70 71 TRACE("%p increasing refcount to %u.\n", iface, refcount); 72 73 return refcount; 74 }
Further tests show that the simplest hack to avoid crashing is replacing line 71 to: FIXME("anything %x\n", 0xdeadbeef);
I have no idea what the real fix is, any suggestion what is the next step to debug?
Backtrace on crash: Wine-dbg>c Unhandled exception: page fault on read access to 0x00000001 in 32-bit code (0x0649e6e9).
This reminds me of bugs where programs fail to initialize variables before use. So, the variable contains whatever value happened to be left at that stack location by previous calls. The specific behavior of those previous calls can leave different values, so changing seemingly unrelated code changes the crash (or makes it go away).
Instead of enabling the trace, try replacing it with something like:
char dummy[256]; memset(dummy, 0x55, sizeof(dummy));
I bet the crash will change from a read access to 0x00000001 to 0x55555555.
The question is: is it a bug in the game or a bug in Wine where Wine is returning a garbage pointer to the game and the game is innocently dereferencing it? For that, you'd have to trace the execution from the call to d3d9_AddRef() to the crashing point to see what else is called and whether it uses an uninitialized value.
Of course, another approach would be to run under Valgrind, if you can get it to work.
-Ken