1

Our Windows application keeps crashing for an access violation. Our system is set up to capture a full dump of the application state when the crash happens. I'm not here to get explanation of the crash... I want to understand an oddness I see with the RAX register in the full dumps.

Here's the snippet of assembly:

000000007B0D306A  mov         rax,qword ptr [rsp+68h]  
000000007B0D306F  movzx       eax,byte ptr [rax+rcx]  
000000007B0D3073  test        eax,eax  
000000007B0D3075  je          000000007B0D3117  
000000007B0D307B  mov         ecx,dword ptr [rsp]  
000000007B0D307E  mov         rax,qword ptr [rsp+58h] <<< CRASH

Notice that we write to RAX in the first and last line of the snippet. The last line of the assembly is the access violation. Because the crash happened, I would expect RAX to still hold the value it got previously from "rsp+68h", but it doesn't. rsp+68h is a valid memory address, but in the crash dump, RAX has a value of 1.

I've ruled out any sort of re-write of memory, and every other register appears to have the values I would expect it to have at this point in the code.

So my question is: when the exception is thrown, is there something that overwrites the RAX register as part of the exception? Or is there some other explanation for why RAX no longer has its previous value?

Inquisitor
  • 49
  • 8
  • 2
    `mov rax,qword ptr [rsp+68h]` loads a **value** from memory, the quadword at `[rsp + 68h]`. So it may hold the value 1 after having loaded from the memory operand. But anyway after that you have `movzx eax,byte ptr [rax+rcx]` which is another load from memory, this time the 8-bit byte value at `[rax + rcx]`, zero-extended to 32-bits. Remember that `eax` is the low 32 bits of `rax` and any write to `eax` also zeroes the remainder upper 32 bits of `rax`. – ecm Oct 10 '22 at 17:57
  • 3
    It's not very plausible that `mov rax,qword ptr [rsp+58h]` would crash if `ecx,dword ptr [rsp]` didn't. Unless there's a jump from somewhere to the instruction that crashed, after trashing the stack pointer RSP? If this ran in a "straight line" like you're talking about in the question, with the `test/je` not being taken, `[rsp+68h]` is a higher address and `[rsp]` is a lower address than `[[rsp+58h]`, so the only way it could fault is if another thread unmapped a page of your stack space, if those previous two loads ran without faulting. – Peter Cordes Oct 10 '22 at 18:04
  • @ecm I forgot about that! Thank you. Good explanation. – Inquisitor Oct 10 '22 at 18:12

1 Answers1

1

This rewrite is explainable. The rewrite of the "eax" register in between rewrites "rax" because one is a subset of the other. Thank you to user @ecm for noticing that.

Inquisitor
  • 49
  • 8