Recent

Author Topic: SetJmp / LongJmp results in Illegal Instruction: 4  (Read 2155 times)

pleumann

  • Jr. Member
  • **
  • Posts: 94
SetJmp / LongJmp results in Illegal Instruction: 4
« on: May 23, 2022, 08:13:04 pm »
Hi,

I am trying to improve the error handling in my project using SetJump/LongJmp. The simple example

https://www.freepascal.org/docs-html/rtl/system/setjmp.html

from the docs works fine, but if I do exactly the same in my (much more complex) code the resulting binary stops with "Illegal Instruction: 4" when the LongJump is being executed. I have no idea what this means or how to solve it.

I'm using FPC 3.2.2 with MacOS 12.1 running on a Mac with M1 processor. Any pointers are appreciated.

Cheers
Joerg

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #1 on: May 23, 2022, 08:27:27 pm »
I do exactly the same in my (much more complex) code the resulting binary stops with "Illegal Instruction: 4" when the LongJump is being executed. I have no idea what this means or how to solve it.
First thing would be to ensure the SetJmp parameter has the values it's supposed to have.  Be particularly careful if the parameter resides on the stack, it can be corrupted and also, it's only valid during the execution of the function it is local to, not on a subsequent re-entry (unless it is re-set to a new value.)

The illegal instruction is most likely due to the LongJmp parameter not being the way it was when SetJmp was called.

HTH.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #2 on: May 23, 2022, 08:51:34 pm »
Thanks!

My Jmp_Buf is a global variable. How can I check that it's been assigned something useful? Can I find the definition for Arm somewhere? The docs seem to be Intel-specific.

https://www.freepascal.org/docs-html/rtl/system/jmp_buf.html

I did copy the example into my code more or less verbatim, though. The main difference is that my code is several orders of magnitude more complex (compiler with recursive descent parser).

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #3 on: May 23, 2022, 09:11:24 pm »
Damn! You were right. The code was indeed taking a path that left the Jmp_Ptr uninitialized. Stupid me. It's working now, Thanks a lot!

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #4 on: May 23, 2022, 10:15:05 pm »
It's working now, Thanks a lot!
You're welcome.  I'm glad you figured it out.

You mentioned you're writing a compiler using recursive descent, may I ask, for what language ?
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #5 on: May 23, 2022, 10:43:38 pm »
My Jmp_Buf is a global variable. How can I check that it's been assigned something useful? Can I find the definition for Arm somewhere?

I'd advise treating that as opaque.

Several decades ago I wrote a Meta-2 implementation, which subsequently got translated from the original DR Pascal to Topspeed Pascal, Turbo Pascal, Delphi and now FPC etc. It's pretty crappy in places and sometime I need to redo it, but it's good enough to run a large chunk of the business.

In the older language implementations I used SetJmp/LongJmp for error handling, but in Delphi or later it's trivial to replace that with an exception: you might find that better=behaved.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #6 on: May 24, 2022, 12:27:45 am »
You should note that Longjumps do not refresh the exception state correctly, meaning that if you jump across stack boundaries, the unrolling of the exception stack (e.g. when entering or leaving a function that contains a try-finally block, entering a constructor, using try-except, raising exceptions, etc. maybe even such innocent things like a "for ... in ..." loop) will reference a pointer to the previous stack frame, which if you used longjmp to jump across stack frames, will be invalid.

This is broken for both SEH based exceptions (default on windows) and the default exception implementation, but they break in a different way.
« Last Edit: May 24, 2022, 12:29:26 am by Warfley »

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #7 on: May 24, 2022, 08:15:38 am »
It's working now, Thanks a lot!
You're welcome.  I'm glad you figured it out.

You mentioned you're writing a compiler using recursive descent, may I ask, for what language ?

Sure. It's a super-simple Pascal compiler targeting Z80, a pet project I've been working on for a while now. The supported language is that of TP 3.0 initially, I might raise that a bit later. One goal (hope?) is for the compiler to be self-hosting, so I restrict myself to features that were available in 3.0. Hence no exceptions for error handling, which would have been convenient, but LongJmp is something I could see myself supporting on Z80.

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #8 on: May 24, 2022, 08:18:54 am »
You should note that Longjumps do not refresh the exception state correctly, meaning that if you jump across stack boundaries, the unrolling of the exception stack (e.g. when entering or leaving a function that contains a try-finally block, entering a constructor, using try-except, raising exceptions, etc. maybe even such innocent things like a "for ... in ..." loop) will reference a pointer to the previous stack frame, which if you used longjmp to jump across stack frames, will be invalid.

This is broken for both SEH based exceptions (default on windows) and the default exception implementation, but they break in a different way.

Yes, I suppose mixing LongJmp and Exceptions is like mixing Mark/Release with GetMem/FreeMem. I also wondered (thinking about the implementation of LongJmp) if there might be potential problems with nested procedures and the display, but I guess that's doable.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #9 on: May 24, 2022, 08:56:30 am »
I also wondered (thinking about the implementation of LongJmp) if there might be potential problems with nested procedures and the display, but I guess that's doable.

As long as you only go up the call chain there shouldn't be a problem with nested procedures. The only thing you need to take care of yourself is allocated memory (in this case both manually allocated memory and managed types, though as you said you're restricting yourself to TP 3.0, so the later shouldn't be a problem ;) ).

By the way: if it's license compatible for you, FPC's setjmp/longjmp implementation for Z80 is in rtl/z80/setjump.inc.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #10 on: May 24, 2022, 09:27:42 am »
Yes, I suppose mixing LongJmp and Exceptions is like mixing Mark/Release with GetMem/FreeMem. I also wondered (thinking about the implementation of LongJmp) if there might be potential problems with nested procedures and the display, but I guess that's doable.

Good comparison.Certainly in the case I mentioned it's one or the other, but in that sort of situation there's a risk that SetJmp/LongJmp be used at a low level with exceptions elsewhere in the program... which would be problematic.

The only time I've used them comparatively recently was to simulate coroutines... which is now obsolete since Warfley has put a lot of effort into doing the job properly.

Quote
nested procedures and the display,

I don't believe that FPC uses a display as such, instead it chains stackframes. In fact the only times I've seen the term used is in the Hisoft/FTL compilers and before that on Burroughs mainframes (to which the compiler writer might have been exposed, since there were several in the Australia/NZ region in which he was based).

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #11 on: May 24, 2022, 09:41:55 am »
I also wondered (thinking about the implementation of LongJmp) if there might be potential problems with nested procedures and the display, but I guess that's doable.

As long as you only go up the call chain there shouldn't be a problem with nested procedures. The only thing you need to take care of yourself is allocated memory (in this case both manually allocated memory and managed types, though as you said you're restricting yourself to TP 3.0, so the later shouldn't be a problem ;) ).

By the way: if it's license compatible for you, FPC's setjmp/longjmp implementation for Z80 is in rtl/z80/setjump.inc.

Thanks for the hint/offer! I will probably try to run my own implementation first, for the fun of it and since there are some dependencies to the compiler and generated code, such as, which registers need to be preserved. Also, as I mentioned, I use a display, so I might have to save/restore the pointer for the level I am jumping to.

pleumann

  • Jr. Member
  • **
  • Posts: 94
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #12 on: May 24, 2022, 09:46:15 am »

Quote
nested procedures and the display,

I don't believe that FPC uses a display as such, instead it chains stackframes. In fact the only times I've seen the term used is in the Hisoft/FTL compilers and before that on Burroughs mainframes (to which the compiler writer might have been exposed, since there were several in the Australia/NZ region in which he was based).

MarkMLl

Sounds like a perfect match then time/technology-wise. I am doing recursive-descent-single-pass-stack-machine, which probably puts me somewhere deep in the early 80s, late 70s. ;)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #13 on: May 24, 2022, 10:05:48 am »
Sounds like a perfect match then time/technology-wise. I am doing recursive-descent-single-pass-stack-machine, which probably puts me somewhere deep in the early 80s, late 70s. ;)

Recursive descent is entirely adequate IMO. The only reason alternative algorithms gained significant traction is that academics (and unskilled language designers) kept turning up cases which it couldn't handle efficiently.

My position on that, after many years of consideration, is that diplomats use English and French for unambiguous communication rather than Arabic and Navaho. A language which can't be parsed without jumping through complex or difficult-to-maintain hoops isn't fit for purpose.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: SetJmp / LongJmp results in Illegal Instruction: 4
« Reply #14 on: May 24, 2022, 10:36:34 am »
Sure. It's a super-simple Pascal compiler targeting Z80, a pet project I've been working on for a while now. The supported language is that of TP 3.0 initially, I might raise that a bit later. One goal (hope?) is for the compiler to be self-hosting, so I restrict myself to features that were available in 3.0. Hence no exceptions for error handling, which would have been convenient, but LongJmp is something I could see myself supporting on Z80.
That sounds very interesting.  Do you plan on sharing the source ? :) it would be nice to be able to look at how you implemented it.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018