Recent

Author Topic: How to Debug and Step into Assert() Function in Lazarus?  (Read 3241 times)

Aruna

  • Hero Member
  • *****
  • Posts: 568
How to Debug and Step into Assert() Function in Lazarus?
« on: October 25, 2024, 04:04:47 am »
Hi everyone,

I'm working on a simple Lazarus project, and I'm using Assert() statements to catch unexpected conditions in my code. However, when an assertion fails, the program terminates, and I'm unable to step into the Assert() function to examine the context around the failure directly. I want to understand better what’s causing the assertion to trigger by being able to step through it in the debugger.

Does anyone know if it’s possible to configure Lazarus or use a specific debugging technique to step into Assert()? Or is there a way to see more context about the failed assertion beyond the termination message? What would be ideal is to be able to single-step through Assert() and any related code.

A simple code example is below that demonstrates the problem.


Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$ASSERTIONS ON} // or equivalently {$C+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     procedure Button1Click(Sender: TObject);
  18.   private
  19.  
  20.   public
  21.  
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. implementation
  28.  
  29. {$R *.lfm}
  30.  
  31. { TForm1 }
  32.  
  33.  
  34. procedure TestDivision(a, b: Integer);
  35. var
  36.   result: Integer;
  37. begin
  38.   // Assert that the denominator is not zero before dividing
  39.   Assert(b <> 0, 'Error: Division by zero!');
  40.  
  41.   result := a div b;
  42.   WriteLn(a, ' divided by ', b, ' equals ', result);
  43. end;
  44.  
  45.  
  46. procedure TForm1.Button1Click(Sender: TObject);
  47. begin
  48. try
  49.    WriteLn('Testing division:');
  50.    TestDivision(10, 2);   // Works fine
  51.    TestDivision(10, 0);   // Will trigger assertion failure
  52.  except
  53.    on E: Exception do
  54.      WriteLn('Exception: ', E.Message);
  55.  end;
  56. end;
  57.  
  58. end.

Thaddy

  • Hero Member
  • *****
  • Posts: 16408
  • Censorship about opinions does not belong here.
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #1 on: October 25, 2024, 06:20:14 am »
I would first get rid of using a plain exception if what you want is a specific EAssertionFailed exception.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3. try
  4.    WriteLn('Testing division:');
  5.    TestDivision(10, 2);   // Works fine
  6.    TestDivision(10, 0);   // Will trigger assertion failure
  7.  except
  8.    on E: EAssertionFailed do
  9.      WriteLn('Exception: ', E.Message)
  10. else
  11.   raise;// it is not an assertion.
  12.  end;
  13. end;
or something along that line;
There is nothing wrong with being blunt. At a minimum it is also honest.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1291
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #2 on: October 25, 2024, 06:38:26 am »
Aruna and I were discussing assert () in chat.
Neither of us could step into it. I don’t know if it’s the fault of the gdb or assert is intentionally off limits?
Hovering over assert () doesn’t allow me to click on link to the source code like other things do.

When I tried to use assert in my project it does indeed stop the program with a dialog giving the line number of error and a gump to choose break or continue. Break takes me to spot where error occurred which Is good.

If I continue there is another gump for abort or risk data corruption.

So for debugging I guess it works ok but why am I not allowed to trace into it to see what it’s doing? I want to see how it gets the line number of error and such.

I have opted to use my own version of error checking that shows message and halts because assert requires too much gump clicking  %)
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10686
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #3 on: October 25, 2024, 09:19:28 am »
What do you mean "step into assert"?

If you indeed want to see what assert itself does, then you need to build an fpc (an rtl) with debug info. (e.g. using fpcupdeluxe).
It is in system.inc
Code: Pascal  [Select][+][-]
  1. Procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;
  2.    ErrorAddr:Pointer); [Public,Alias : 'FPC_ASSERT']; compilerproc;
  3. begin
  4.   if codepointer(AssertErrorProc)<>nil then
  5.     AssertErrorProc(Msg,FName,LineNo,ErrorAddr)
  6.   else
  7.     HandleErrorAddrFrameInd(227,get_pc_addr,get_frame);
  8. end;
  9.  

Mind that this is an intrinsic. As you can see the boolean result of the condition is not in the parameters => that code is inlined into your calling procedure. So the above is only called, if the condition fails.

Afaik it then depends. If any unit in your app (including recursively any unit you used) uses "SysUtils then it throws an exception.

And if you want you can catch that exception.



Most of the time the assert is simply used to alert of the error, and then meant to stop the exe.

Otherwise use "if ... then raise exception.create();"

MarkMLl

  • Hero Member
  • *****
  • Posts: 8129
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #4 on: October 25, 2024, 09:24:41 am »
I checked earlier (since that was my first thought), and even if FPC is built with full debugging the IDE doesn't step into Assert().

Presumably this is because- as you say- Assert() is a compiler/RTL intrinsic. I didn't check whether setting a breakpoint inside the RTL would do it.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10686
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #5 on: October 25, 2024, 09:37:14 am »
It does step in. But only if the condition is true. The condition itself is inlined into the caller..

MarkMLl

  • Hero Member
  • *****
  • Posts: 8129
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #6 on: October 25, 2024, 10:27:49 am »
Ah :-)

So presumably if somebody wants to explore what's actually happening they insert a dummy Assert() with the condition negated.

Would this do anything at all if the condition was entirely evaluated at compilation time, e.g.

Code: Pascal  [Select][+][-]
  1. Assert( { not } SizeOf(Longword) = 2), ... )
  2.  

I've actually got quite a lot of size-checking assertions, particularly when checking that a data structure defined in e.g. an I2C or SPI interface unit is what's known in the C original.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1291
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #7 on: October 25, 2024, 12:24:31 pm »
What I did was placed a breakpoint in Lazarus on same line as assert and then tried to step into it using the ide.
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10686
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #8 on: October 25, 2024, 12:29:46 pm »
What I did was placed a breakpoint in Lazarus on same line as assert and then tried to step into it using the ide.

Same as I did.

But I also did:
- make sure the condition was false
- my RTL had full debug info (that needs to be done outside the IDE)

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1291
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #9 on: October 25, 2024, 12:51:10 pm »
I used assert (false = true,’false = true);
 Which definitely ended the program after two different dialogs were clicked.
What was behavior of yours?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Aruna

  • Hero Member
  • *****
  • Posts: 568
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #10 on: October 25, 2024, 12:54:37 pm »
- my RTL had full debug info (that needs to be done outside the IDE)
Hi @Martin_fr and 'how' does one do this please?

EDIT: make all OPT="-g -gl ?
« Last Edit: October 25, 2024, 01:02:36 pm by Aruna »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10686
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #11 on: October 25, 2024, 01:02:42 pm »
- my RTL had full debug info (that needs to be done outside the IDE)
Hi @Martin_fr and 'how' does one do this please?

FpcUpDeluxe.

Well that or download the sources, and play with Makefiles. (I don't have a link to any instructions)


Either way, you get a 2nd independent install of FPC => once you got that in the IDE you need to change the compiler (Tools > options // or if you prefer in the project settings, something like compile commands)

TRon

  • Hero Member
  • *****
  • Posts: 3810
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #12 on: October 25, 2024, 01:07:31 pm »
EDIT: make all OPT="-g -gl ?
afaik it is make all DEBUG=1
I do not have to remember anything anymore thanks to total-recall.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10686
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #13 on: October 25, 2024, 01:12:07 pm »
EDIT: make all OPT="-g -gl ?
afaik it is make all DEBUG=1

If you use FpDebug in your IDE I would suggest   OPT="-gl -gw3 -O-1"

-gl is not strictly needed. The info is added with -gw3
And the unit will be added if you compile the project with -gl

Of course if you want nice dumps when the compiler itself crashes => then yes: -gl

MarkMLl

  • Hero Member
  • *****
  • Posts: 8129
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #14 on: October 25, 2024, 01:57:05 pm »
If you use FpDebug in your IDE I would suggest   OPT="-gl -gw3 -O-1"

-gl is not strictly needed. The info is added with -gw3
And the unit will be added if you compile the project with -gl

Of course if you want nice dumps when the compiler itself crashes => then yes: -gl

I routinely build FPC with -O- -gl and- as I said earlier- I couldn't step into an arbitrary assertion. However I didn't try both states of the controlling predicate.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018