BlindMindStudios / AngelScript-JIT-Compiler

A Just-In-Time compiler for the AngelScript language on x86 processors.

Home Page:www.blind-mind.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Random crash with variable passed locally

codecat opened this issue · comments

We are using AngelScript version 2.31.1 and the latest asJIT compiler. Everything works fine, but we are facing a rare-ish bug where our game crashes at the same (JIT'd) function, on this line: (Function was fetched by dumping all function signatures and JIT addresses and matching it with the instruction pointer in an mdmp, line is an educated guess based on the byte offset and disassembly around the instructions)

if (di.Melee)

Here, di is of type DamageInfo and is passed to the function by value, and Melee is a bool. The class is defined in scripts with 2 constructors, a regular constructor (DamageInfo()) and one with a bunch of params for its properties. (So we're using the default copy constructor)

This is the disassembly corresponding to the script line above, where the crash occurs on 35745A9F:

35745A9C | 83 C3 1E                 | add ebx,1E                                    |
35745A9F | 8B 03                    | mov eax,dword ptr ds:[ebx]                    |
35745AA1 | 25 FF 00 00 00           | and eax,FF                                    |
35745AA6 | 89 47 EC                 | mov dword ptr ds:[edi-14],eax                 |
35745AA9 | 8B 5F EC                 | mov ebx,dword ptr ds:[edi-14]                 |
35745AAC | 20 DB                    | and bl,bl                                     |
35745AAE | 0F 84 39 00 00 00        | je 35745AED                                   |

So far we've only seen this crash happen on Windows 32 bit (we don't have 64 bit builds though), but we haven't tested on our Linux builds to confirm whether it happens there, too.

Could you provide some additional disassembly prior to 357459C?

Sure: (addresses changed due to me re-starting the process, but what was 35745A9F is now 43825A9F

43825A58 | 89 5F EC                 | mov dword ptr ds:[edi-14],ebx           |
43825A5B | D9 47 CC                 | fld dword ptr ds:[edi-34]               |
43825A5E | D8 4F EC                 | fmul dword ptr ds:[edi-14]              |
43825A61 | D9 5F CC                 | fstp dword ptr ds:[edi-34]              |
43825A64 | 8A 4D 20                 | mov cl,byte ptr ss:[ebp+20]             |
43825A67 | 20 C9                    | and cl,cl                               |
43825A69 | 74 20                    | je 43825A8B                             |
43825A6B | C7 45 00 24 99 01 43     | mov dword ptr ss:[ebp],43019924         |
43825A72 | 89 75 08                 | mov dword ptr ss:[ebp+8],esi            |
43825A75 | 8B 55 24                 | mov edx,dword ptr ss:[ebp+24]           |
43825A78 | 52                       | push edx                                |
43825A79 | E8 22 CF BC BD           | call <game.doSuspend>                   |
43825A7E | BA 24 99 01 43           | mov edx,43019924                        |
43825A83 | 20 C0                    | and al,al                               |
43825A85 | 0F 85 85 F7 FF FF        | jne 43825210                            |
43825A8B | 8B 5F 08                 | mov ebx,dword ptr ds:[edi+8]            |
43825A8E | 21 DB                    | and ebx,ebx                             |
43825A90 | 75 0A                    | jne 43825A9C                            |
43825A92 | BA 30 99 01 43           | mov edx,43019930                        |
43825A97 | E9 74 F7 FF FF           | jmp 43825210                            |
43825A9C | 83 C3 1E                 | add ebx,1E                              |
43825A9F | 8B 03                    | mov eax,dword ptr ds:[ebx]              |
43825AA1 | 25 FF 00 00 00           | and eax,FF                              |
43825AA6 | 89 47 EC                 | mov dword ptr ds:[edi-14],eax           |
43825AA9 | 8B 5F EC                 | mov ebx,dword ptr ds:[edi-14]           |
43825AAC | 20 DB                    | and bl,bl                               |
43825AAE | 0F 84 39 00 00 00        | je 43825AED                             |

It looks like something has overwritten the VM's stack. I couldn't say how or what from what you've provided. Perhaps it has something to do with the suspend callback, could you try disabling JIT suspension via the flag?

We'll have to try that, thanks! It's a semi-rare bug that we've been trying to reproduce for a while, so we'll have to experiment a bit.

Oh, I forgot to note we are already using these flags: JIT_ALLOC_SIMPLE | JIT_NO_SCRIPT_CALLS | JIT_FAST_REFCOUNT

We just encountered this crash again with JIT_ALLOC_SIMPLE | JIT_FAST_REFCOUNT | JIT_NO_SUSPEND, at the same point in the code at 3EC66D82:

3EC66D4A | B9 00 00 00 00           | mov ecx,0                               |
3EC66D4F | 8B 45 24                 | mov eax,dword ptr ss:[ebp+24]           |
3EC66D52 | 3B 48 10                 | cmp ecx,dword ptr ds:[eax+10]           |
3EC66D55 | 75 05                    | jne 3EC66D5C                            |
3EC66D57 | E9 1D FB FF FF           | jmp 3EC66879                            |
3EC66D5C | 8B 75 08                 | mov esi,dword ptr ss:[ebp+8]            |
3EC66D5F | 8B 5D 10                 | mov ebx,dword ptr ss:[ebp+10]           |
3EC66D62 | 89 5F EC                 | mov dword ptr ds:[edi-14],ebx           |
3EC66D65 | D9 47 CC                 | fld dword ptr ds:[edi-34]               |
3EC66D68 | D8 4F EC                 | fmul dword ptr ds:[edi-14]              |
3EC66D6B | D9 5F CC                 | fstp dword ptr ds:[edi-34]              |
3EC66D6E | 8B 5F 08                 | mov ebx,dword ptr ds:[edi+8]            |
3EC66D71 | 21 DB                    | and ebx,ebx                             |
3EC66D73 | 75 0A                    | jne 3EC66D7F                            |
3EC66D75 | BA 68 A2 F8 40           | mov edx,40F8A268                        |
3EC66D7A | E9 6A F9 FF FF           | jmp 3EC666E9                            |
3EC66D7F | 83 C3 1E                 | add ebx,1E                              |
3EC66D82 | 8B 03                    | mov eax,dword ptr ds:[ebx]              |
3EC66D84 | 25 FF 00 00 00           | and eax,FF                              |
3EC66D89 | 89 47 EC                 | mov dword ptr ds:[edi-14],eax           |
3EC66D8C | 8B 5F EC                 | mov ebx,dword ptr ds:[edi-14]           |
3EC66D8F | 20 DB                    | and bl,bl                               |

It just crashed again in a different place, this time earlier in the same backtrace (handling the same DamageInfo structure.)

We have found a way to reproduce this pretty easily on our builds (not sure if I can provide an isolated test case for you), so I decided to take a look at this again today.

Debugged this using x64dbg, it seems like ebx is pointing to a valid memory address with valid values (1 byte for a bool, 2 bytes for the int16 in the structure, etc), and the object in which it is contained (asCScriptObject) has a valid vftable, too. (At ebx - 1E in above disassembly.)

This leads me to believe that somehow the object is freed from memory and that's why we're getting an access violation. After looking through the as_jit code and some of the AS bytecode documentation I can't really figure out why this would happen seemingly at random.

Could it be related to garbage collection? I don't think local variables are garbage collected like that, are they?