Recent

Author Topic: Work of exeptions, corruptable registers  (Read 258 times)

LemonParty

  • Hero Member
  • *****
  • Posts: 525
Work of exeptions, corruptable registers
« on: May 11, 2026, 04:35:44 pm »
I interesting how exactly exeptions work.

What if we have a function. In the begining of this function we corrupt some incorruptable registers (r12-r15 or xmm6-xmm15 for example) then in the middle of this function occurs an exeption. If everyting OK we should restore the value of incorruptable registers but this will not happen since we got an exeption. How exeption handling manage such situations?
« Last Edit: May 11, 2026, 05:39:48 pm by LemonParty »
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12397
  • Debugger - SynEdit - and more
    • wiki
Re: Work of exeptions, corruptable registers
« Reply #1 on: May 11, 2026, 05:00:09 pm »
I take it this isn't about the "push" and "pop" to store/restore?

But rather how are the "pop" still called?

If you have an exception, it doesn't go straight to the "except" block. It also passes through all "finally" blocks on the way.

And, there are "finally" blocks that the compiler can insert itself. E.g. if you have a local ansistring var. That needs to be freed before the function is left. Then the compiler wraps the entire function into a try finally block.

So then
- if those registers fall into the same category as e.g. temp ansistring vars, then the compiler takes care.
- if they are your own, then you must add the try finally block

How finally blocks are handled (and found) differs by target.

LemonParty

  • Hero Member
  • *****
  • Posts: 525
Re: Work of exeptions, corruptable registers
« Reply #2 on: May 11, 2026, 05:38:37 pm »
Quote
But rather how are the "pop" still called?
Yes, how exactly program manage not to completely fall when data in incorruptable registers was lost?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12397
  • Debugger - SynEdit - and more
    • wiki
Re: Work of exeptions, corruptable registers
« Reply #3 on: May 11, 2026, 05:58:22 pm »
I don't know for sure what happens, when and where...

But I would guess.

You have some proc A that calls proc B. When B returns (normally) then A expects those registers to be what they were before. => If they are not then A would crash.

So if B modifies those regs is pushes them.

Then in case of an exception I see 2 valid cases.

1) B catches and handles the exception. Then B should be able to restore those regs (because flow was restored inside B.

2) B does not handle the exception. Then it does not return to the calling location in A. Therefore A never executes any code that relies on those registers. Instead it "bubbles out" (through finally handlers) until it gets caught and handled.
When it gets caught and handled, registers can be restored to what they should be at that outer level.

---------------------
Though that is the theory. I haven't looked at the practical side.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12397
  • Debugger - SynEdit - and more
    • wiki
Re: Work of exeptions, corruptable registers
« Reply #4 on: May 11, 2026, 06:01:29 pm »
That said. I don't know if exception unwinding has any "restoring" code build in. Or if it relies on stuff being saved by outer callers too.

I.e. if an outer caller didn't save a register, because it didn't modify it, then I don't know where it gets restored.

Thaddy

  • Hero Member
  • *****
  • Posts: 19247
  • Glad to be alive.
Re: Work of exeptions, corruptable registers
« Reply #5 on: May 11, 2026, 06:10:44 pm »
Any program written in any language can not recover from such damage you describe.
Apart from possibly a restart. If register level program errors occur that is likely hardware failure and there is no way to recover from that. Not even with exceptions.

If you would not explicitly have mentioned the register damage, my answer would be different.
objects are fine constructs. You can even initialize them with constructors.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12397
  • Debugger - SynEdit - and more
    • wiki
Re: Work of exeptions, corruptable registers
« Reply #6 on: May 11, 2026, 06:22:09 pm »
I think (but it took me some time to realize) that LemonParty means something like

You have code that is optimized and uses registers.
The ABI says Reg42 must be saved by any callee that wants to use it. (Such rules do exist).

So if A calls B, and B returns, then A can continue to use the content of Reg42.
If B had used it too, then B would have stored and restored it.

But If B does not use it, then B may not need to store it (well, maybe, I don't know... Maybe B must do that if it calls any other procs???)
Anyway, lets say B did not store Reg42, and B does not modify it.

But B does call C. And C stores it, as it will use it. Then C raises an exception. => that exception is caught in B.
B catching the exception can not restore Reg42. ...

So when/where/who will restore Reg42 in that case. (there are plenty of options: finally handler in C, or maybe something in the exception unwinding code...)

LemonParty

  • Hero Member
  • *****
  • Posts: 525
Re: Work of exeptions, corruptable registers
« Reply #7 on: May 11, 2026, 07:08:58 pm »
I wrote a simple program that illustrate the situation:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$If Defined(CPU386) OR Defined(CPUX64)}
  5.         {$ASMMODE intel}
  6. {$EndIf}
  7.  
  8. interface
  9.  
  10. uses
  11.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  12.  
  13. type
  14.  
  15.   { TForm1 }
  16.  
  17.   TForm1 = class(TForm)
  18.     Button1: TButton;
  19.     procedure Button1Click(Sender: TObject);
  20.   private
  21.  
  22.   public
  23.  
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. function ProceedBuffer(constref Buf: Byte): Integer;assembler;
  32. asm
  33.   push r12
  34.   push r13
  35.   push r14
  36.   push r15
  37.   mov r12,0
  38.   mov r13,0
  39.   mov r14,0
  40.   mov r15,0 {destoyed data in r12, r13, r14, r15 here}
  41.   movzx eax,byte ptr[Buf]
  42.   pop r15 {we should not get here because of exeption}
  43.   pop r14
  44.   pop r13
  45.   pop r12
  46. end;
  47.  
  48. {$R *.lfm}
  49.  
  50. { TForm1 }
  51.  
  52. procedure TForm1.Button1Click(Sender: TObject);
  53. begin
  54.   ProceedBuffer(PByte(nil)^); {will produce an exeption}
  55. end;
  56.  
  57. end.
When press Button1 we get message about exeption but program don't die. So question is how compiler protects program from death when we corrupted an incorruptable registers?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12397
  • Debugger - SynEdit - and more
    • wiki
Re: Work of exeptions, corruptable registers
« Reply #8 on: May 11, 2026, 07:40:48 pm »
But your example misses a lot....

1) Which of those registers does the ABI demand should be restored?
2) Even if the ABI demands that, that does not mean that the code requires it.

For the code to require this, your LCL must be build with optimization, so it relies on registers. And even then, it must on further more rely on exactly those (or some of them).

If the code never relied on those registers, then it won't crash.

And, in your case, that reliance would have to be in the *caller* of the code that has the "try except" that catches this.
I.e. way up the callstack is a try...except. All the callers down to there, don't get executed on the way back. So for them, its not important what happened to the registers.
Then in one procedure the try...except happens. When the "except" block ends, that is the earliest where any register may be expected back to its original value.



Exception handling depends on the Target. On Windows this would be SEH.

I just googled: does SEH restore cpu registers
And Google's AI says: yes, it does.

However, in your code there may still be luck involved.
If you looked at asm you would have seen mnemonics like sehpush. Those describe to the assemble what info to leave for the exception unwinding code. => your asm does not have that. I don't know if it should (if it was on Windows). But that would only matter if those regs weren't saved in any other method between yours and the try...except.

And other targets? I don't know, exceptions are handled by other means.


LeP

  • Sr. Member
  • ****
  • Posts: 318
Re: Work of exeptions, corruptable registers
« Reply #9 on: May 11, 2026, 08:11:18 pm »
I changed the code little bit to be compiled in Delphi.

In Delphi the app crash, 'cause it cannot recover. Not explicit try / except / finally etc. ... helps.

In Windows the ABI must absolutely be followed and the registers (only some of them) must be restored, no exceptions to that rule.
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

LemonParty

  • Hero Member
  • *****
  • Posts: 525
Re: Work of exeptions, corruptable registers
« Reply #10 on: May 11, 2026, 09:13:35 pm »
Interesting. Delphi uses LLVM. Maybe they utilize this registers under the hood. There really may be luck that program on Lazarus don't die.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

 

TinyPortal © 2005-2018