Recent

Author Topic: intercepting exceptions  (Read 15030 times)

Rik

  • Jr. Member
  • **
  • Posts: 67
intercepting exceptions
« on: August 17, 2018, 12:06:31 pm »
I have a problem with intercepting an exception:

A  Bitmap.Canvas.FillRect() leads to a Debugger Exception Notification (Canvas does not allow drawing) caused in canvas.inc:
      CreateHandle;
      if FHandle = 0 then
        raise EInvalidOperation.Create(rsCanvasDoesNotAllowDrawing);

Trying to intercept this exception by
      try
        MyBitmap.Canvas.FillRect(0,0,ImgWidth,ImgHeight);
      except
        on E: Exception do
          ShowMessage('An exception was raised: ' + E.Message);
      end;
 does not work.

What is the correct way to intercept this exception?

Thanks, Rik

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: intercepting exceptions
« Reply #1 on: August 17, 2018, 12:16:35 pm »
Your application catching the exception and dealing with it is independent of the debugger showing you the exception.

The debugger does not know (at the time of an exception) if (or how) your code will deal with it.

You can add an exception type (class) to the ignore list of the debugger. But then all exceptions of this type will be ignored, independent of your code dealing with a specific one or not.

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #2 on: August 17, 2018, 03:55:27 pm »
Thanks for the fast reply.

But if I add the exception class I get a error message (program raised exception) instead of the debugger notification.
What I want to do is to "catch" the error and handle it instead of running into the error message (that halts the program).

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: intercepting exceptions
« Reply #3 on: August 17, 2018, 04:16:43 pm »
Are you sure this is the only call to FillRect (or similar) that can raise the exception.

When you get the debugger notification, did you check the callstack that the exception was inside the try / except?

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #4 on: August 20, 2018, 09:12:51 am »
There is more than one call to FillRect, but the error disappears when I skip (comment out) that particular one.
The exception is not directly raised in the program I am writing but in canvas.inc (line 1700 - Lazarus version 1.6.2.):

Code: Pascal  [Select][+][-]
  1. if FHandle = 0 then raise EInvalidOperation.Create(rsCanvasDoesNotAllowDrawing);

In my program I am trying to intercept the error by:

Code: Pascal  [Select][+][-]
  1. try
  2.   MyBitmap.Canvas.FillRect(0,0,ImgWidth,ImgHeight);
  3. except
  4.   On E :Exception do
  5.   begin
  6.     ShowMessage(E.Message); // just to check if the error is caught, to be changed later
  7.   end;
  8. end;

Will a "try ... except ..." in my program catch an exception raised in canvas.inc (probably called by FillRect)?

In case it is of any help:
Running the program from the Lazarus IDE results in p1.png (attached).
Running the program from the Lazarus IDE with EInvalidOperation ignored results in p2.png (attached).
Running the program (exe) outside the Lazarus IDE results in p3.png (attached).

Thanks,

Rik


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: intercepting exceptions
« Reply #5 on: August 20, 2018, 11:46:36 am »
Getting a SigSegV may be an unrelated error.
This may be even if it depends on the presence of that line. SigSegV often happen at a line different from the actual error.


In any case, when you get the Exception, and you press "Break", and then open the StackWindow => then where is the FillRect called from?


Same for the SigSegV, what does the stack say?

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: intercepting exceptions
« Reply #6 on: August 20, 2018, 12:08:53 pm »
1. The debugger catches an exception before the program catches it. If you do not want to do this, uncheck the "Tools/Options/Debugger/Language Exceptions/Notify on Lazarus Exceptions" or "Run without debugging".
2. Specific Bitmap? This code run without error:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2.  
  3. uses Interfaces, Graphics;
  4.  
  5. var
  6.   B: TBitmap;
  7. begin
  8.   B := TBitmap.Create;
  9.   try
  10.     B.Width := 30;
  11.     B.Height := 15;
  12.     B.Canvas.FillRect(0, 0, 15, 30);
  13.   finally
  14.     B.Free;
  15.   end;
  16.   Readln;
  17. end.
Even if lines 10 and 11 are commented out.

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #7 on: August 20, 2018, 12:18:26 pm »
Getting a SigSegV may be an unrelated error.
In any case, when you get the Exception, and you press "Break", and then open the StackWindow => then where is the FillRect called from?

The call stack window:

#0 fpc_raiseexception at :0
#1 REQUIREDSTATE(0x1d0540d0, 9) at include\canvas.inc:1700
#2 FILLRECT(0x1d0540d0, {LEFT = 0, TOP = 0, RIGHT = 600, BOTTOM = 480, TOPLEFT = {X = 0, Y = 0}, BOTTOMRIGHT = {X = 600, Y = 480}}) at include\canvas.inc:1005
#3 FILLRECT(0x1d0540d0, 0, 0, 600, 480) at include\canvas.inc:1015
#4 CREATEBITMAP(3295) at mainunit.pas:204
#5 VIDEOBUTTONCLICK(0x11e6ea0, 0x11d86e0) at mainunit.pas:731
#6 CLICK(0x11d86e0) at include\control.inc:2736
#7 CLICK(0x11d86e0) at include\buttoncontrol.inc:54
#8 CLICK(0x11d86e0) at include\buttons.inc:169
#9 WMDEFAULTCLICKED(0x11d86e0, {MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {FILLER = {0, 0, 0, 0}}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {FILLER = {0, 0, 0, 0}}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {FILLER = {0, 0, 0, 0}}}) at include\buttoncontrol.inc:20
#10 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal at :0
#11 ?? at :0


I hope that is what you asked for.

Rik

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #8 on: August 20, 2018, 12:25:46 pm »
Quote
1. The debugger catches an exception before the program catches it. If you do not want to do this, uncheck the "Tools/Options/Debugger/Language Exceptions/Notify on Lazarus Exceptions" or "Run without debugging".

After disabling debugging I get an "External: SIGSEGV" error.

The call stack window is now:

#0 fpc_ansistr_decr_ref at :0
#1 ?? at :0


Rik

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: intercepting exceptions
« Reply #9 on: August 20, 2018, 12:49:51 pm »
And is " CREATEBITMAP(3295) at mainunit.pas:204" the function in which you have the try/except?

----------------
Anyway it will be more important to first find out what causes the SigSegV.

The SigSegV most likely means that some of your programs memory got seriously corrupted (eg maybe you wrote to an object that you previously freed, or never created).
Once you got memory corruption you get all kind of unexpected behaviour.

The bad news is, that such SigSegV are rather hard to find.

Compile your application with the following settings (add them under custom options, it the project options

-Criot -CR -gh -Sa -O-

See if that changes anything (if you get a diff error).


Btw, what OS are you using?

--------------------
Also set a breakpoint on the following lines:
Code: Pascal  [Select][+][-]
  1. try
  2.   MyBitmap.Canvas.FillRect(0,0,ImgWidth,ImgHeight);  // <<<< breakpoint
  3. except
  4.   On E :Exception do
  5.   begin
  6.     ShowMessage(E.Message);  // <<<< breakpoint
  7.   end;
And on whatever line follows after this code.
So you know which line where passed when the error happens.

When the exception is caught by the debugger, select break, and then press F8 until you get to the ShowMessage.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: intercepting exceptions
« Reply #10 on: August 20, 2018, 11:15:18 pm »
 When the Bitmap was first created, did the Width, height of the bitmap get set first?

 Bitmap.SetSize or Bitmap.Width := 600 ….

Something of that order.
The only true wisdom is knowing you know nothing

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #11 on: August 21, 2018, 08:51:21 am »
Quote
Compile your application with the following settings (add them under custom options, it the project options
-Criot -CR -gh -Sa -O-
See if that changes anything (if you get a diff error).
No changes.

Quote
Btw, what OS are you using?
Windows 7 Professional

Quote
The SigSegV most likely means that some of your programs memory got seriously corrupted
I think I got the cause: I am creating too many Bitmaps and probably running out of memory when I fill them. When I reduce the number of bitmaps the error (exception) no longer occurs.

What brings me to the next question:
How can I check the available memory and stop filling bitmaps before running out of memory?
I tried to use GlobalMemoryStatusEx (see http://forum.lazarus.freepascal.org/index.php?topic=30855.0), I can see the some of values decreasing as I fill the Bitmaps, but none of them goes (close) to zero before the error occurs.

Maybe I should start a new thread?

Rik
« Last Edit: August 21, 2018, 08:57:53 am by Rik »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: intercepting exceptions
« Reply #12 on: August 21, 2018, 08:59:38 am »
If you really run out of (heap) memory you will get a EOutOfMemory exception, that is pre-allocated and doesn't cause a sigsev. I think the most likely cause is a stack overflow or stack corruption. Try increasing the stack size if you are allocating the bitmaps as a variable inside a method, procedure or function. If that helps(even a little), make the bitmaps fields of your class, don't declare them locally.
Specialize a type, not a var.

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: intercepting exceptions
« Reply #13 on: August 21, 2018, 09:11:34 am »
Quote
The SigSegV most likely means that some of your programs memory got seriously corrupted
I think so too.

Quote
I think I got the cause: I am creating too many Bitmaps and probably running out of memory when I fill them. When I reduce the number of bitmaps the error (exception) no longer occurs.

What brings me to the next question:
How can I check the available memory and stop filling bitmaps before running out of memory?
I tried to use GlobalMemoryStatusEx (see http://forum.lazarus.freepascal.org/index.php?topic=30855.0), I can see the some of values decreasing as I fill the Bitmaps, but none of them goes (close) to zero before the error occurs.
Maybe I should start a new thread?

Rik

Rik, if creating fewer bitmaps makes the exception go away, it's more likely that the exception occurs because of corrupted memory, not because of running out of memory.   

Is it possible for you to create a small standalone program that isolates the code that generates the exception and post it ?   

How do you keep track of all the bitmaps ?... do you have an array of handles ?  ... some list ?  (any of those may be too small to hold the handles to the bitmaps you're creating causing memory to be corrupted.)
« Last Edit: August 21, 2018, 09:13:12 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Rik

  • Jr. Member
  • **
  • Posts: 67
Re: intercepting exceptions
« Reply #14 on: August 21, 2018, 09:32:58 am »
Quote
If you really run out of (heap) memory you will get a EOutOfMemory exception, that is pre-allocated and doesn't cause a sigsev. I think the most likely cause is a stack overflow or stack corruption. Try increasing the stack size if you are allocating the bitmaps as a variable inside a method, procedure or function. If that helps(even a little), make the bitmaps fields of your class, don't declare them locally

I increased the stack to its maximum size (according to https://www.freepascal.org/docs-html/prog/progsu101.html#x109-1100001.3.18):
Code: Pascal  [Select][+][-]
  1. {$MAXSTACKSIZE $7FFFFFFF}
But the exception still occurs after the same number of Bitmaps filled.

Rik

 

TinyPortal © 2005-2018