Recent

Author Topic: How can *this* happen (assert(assigned()) fails  (Read 1510 times)

ArminLinder

  • Sr. Member
  • ****
  • Posts: 314
  • Keep it simple.
How can *this* happen (assert(assigned()) fails
« on: May 04, 2021, 02:00:44 pm »
Please look at the following screenshot, it comes from a debug session. The component (VirtualTreeView) is upon to crash, which, btw, seems to be one of its favourite actions anyway.

As you can see, the programmer had taken precautions if somehow the node passed is NIL. According to the watch window, it is NIL. Unfortunataly the program didn't bail out, but continue, and the next statement will cause a SIGSEV.

How in earth can the code get to this point?

Armin.
« Last Edit: May 04, 2021, 02:35:32 pm by Nimral »
Lazarus 3.3.2 on Windows 7,10,11, Debian 10.8 "Buster", macOS Catalina, macOS BigSur, VMWare Workstation 15, Raspberry Pi

alpine

  • Hero Member
  • *****
  • Posts: 1062
Re: How can *this* happen (assert(assigned()) fails
« Reply #1 on: May 04, 2021, 02:06:04 pm »
Sorry for asking, but have you enabled the "Include assertion code (-Sa)" into the Options/Compiler options/Debugging?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

ArminLinder

  • Sr. Member
  • ****
  • Posts: 314
  • Keep it simple.
Re: How can *this* happen (assert(assigned()) fails
« Reply #2 on: May 04, 2021, 02:17:21 pm »
Yes, the option is enabled.
Lazarus 3.3.2 on Windows 7,10,11, Debian 10.8 "Buster", macOS Catalina, macOS BigSur, VMWare Workstation 15, Raspberry Pi

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: How can *this* happen (assert(assigned()) fails
« Reply #3 on: May 04, 2021, 02:27:19 pm »
How in earth can the code get to this point?
Triggering an assertion does not stop code execution. It raises an exception.
Presumably by the time the exception has reached the top of the stack the next few instructions have already been executed (perhaps the instructions are already cached)?

At the access violation the OS steps in with a signal which takes priority.

ArminLinder

  • Sr. Member
  • ****
  • Posts: 314
  • Keep it simple.
Re: How can *this* happen (assert(assigned()) fails
« Reply #4 on: May 04, 2021, 02:33:42 pm »
Hm, if so, how should one write such code if he wants to be absolutely sure that the code doesn't continue and SIGSEV? I mean, in this case, he has done what he could, nevertheless the program suffered a fatal crash. Or, the other way round, is it wise to use assert at all, if it's behaviour is so unreliable?

What the programmer could have done was something like

Code: Pascal  [Select][+][-]
  1.  
  2. result := false;
  3. if Node <> nil then
  4.    ...
  5.    result := true;
  6. else
  7.   raise Exception.create('....');
  8.  
  9.  

... but wasn't assert introduced as an alternative?
Lazarus 3.3.2 on Windows 7,10,11, Debian 10.8 "Buster", macOS Catalina, macOS BigSur, VMWare Workstation 15, Raspberry Pi

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: How can *this* happen (assert(assigned()) fails
« Reply #5 on: May 04, 2021, 03:03:24 pm »
Firstly, my surmise as to the cause of the assertion not doing what you hoped may be wrong.
Also, you are running the program under the debugger. This introduces a completely different run environment from that which an executable "normally" encounters.
Assertions were introduced as an aid to developers. Their code is not included (or should not be included) in production code. They are there to highlight situations that "should never happen" (i.e. usually programmer errors of one kind or another).

They are not a panacea designed to get you to recover from a bad situation. They are inserted as a flag to the programmer that she needs to think more deeply about how that situation which can never occur has occurred.

If a class instance is Nil when the programmer does not expect it, then either her expectation is incorrect, or she has overlooked a situation which causes or allows the instance to be Nil.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5469
  • Compiler Developer
Re: How can *this* happen (assert(assigned()) fails
« Reply #6 on: May 05, 2021, 09:06:41 am »
Presumably by the time the exception has reached the top of the stack the next few instructions have already been executed (perhaps the instructions are already cached)?

Explicitly raising an exception is synchronous (it's essentially an ordinary call). The CPU will not continue executing the original code, cause it's inside the exception generating code (e.g. RaiseException on Windows).

As you can see, the programmer had taken precautions if somehow the node passed is NIL. According to the watch window, it is NIL. Unfortunataly the program didn't bail out, but continue, and the next statement will cause a SIGSEV.

Would you please add an {$Assertions On} before the GetFullyVisible method to be sure that assertions are indeed enabled?

MarkMLl

  • Hero Member
  • *****
  • Posts: 6685
Re: How can *this* happen (assert(assigned()) fails
« Reply #7 on: May 05, 2021, 09:33:38 am »
Explicitly raising an exception is synchronous (it's essentially an ordinary call). The CPU will not continue executing the original code, cause it's inside the exception generating code (e.g. RaiseException on Windows).

Thanks for that, I was bothered. I suspect that there might possibly be a bit of confusion regarding speculative execution, but my understanding is that state related to that should never "leak".

I think that one thing worth explicitly checking is that    in Node.States    in OP's example relates to a simple set, rather than to something more complex that's accessed via a pointer.

Also for completeness I think that OP should be telling us much more about his test environment, in case there's something like a delay slow involved.

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

alpine

  • Hero Member
  • *****
  • Posts: 1062
Re: How can *this* happen (assert(assigned()) fails
« Reply #8 on: May 05, 2021, 11:29:31 am »
Explicitly raising an exception is synchronous (it's essentially an ordinary call). The CPU will not continue executing the original code, cause it's inside the exception generating code (e.g. RaiseException on Windows).
I'm also appreciating that. Keeps me from losing my sanity.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018