Weird thing her. I was trying out my old Plumbing example, mostly just as a way to improve the swiki page. Using a 19292 update 5.3 image on Mac.
Found a recursion related bug in the behaviour when there are two faucets. Toggled the break on entry, triggered the recursion. Went to step over the #break and.... whoosh, boom. Some very weird behaviour that is not at all what I'd expect. I also tried stepping into the #break to see if that might show me sometihng but that wasn't any better at all. Tested in a 198229 image and no problem. Someone done borked it. The best I could capture any log is - ---------------------------------- Error: subscript is out of bounds: 0 26 January 2020 8:59:18.032815 pm VM: Mac OS - Smalltalk Image: Squeak5.3beta [latest update: #19292] SecurityManager state: Restricted: false FileAccess: true SocketAccess: true Working Dir /Users/tim/Documents/Squeak Trusted Dir /Users/tim/Documents/Squeak/secure Untrusted Dir /Users/tim/Documents/Squeak/My Squeak Context(Object)>>error: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: aString: 'subscript is out of bounds: 0' Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context(Object)>>errorSubscriptBounds: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) Context>>at: Receiver: FaucetPlumbinTileMorph(Object)>>break Arguments and temporary variables: index: 0 Receiver's instance variables: sender: BlockClosure>>on:do: pc: 44 stackp: 0 method: (Object>>#break "a CompiledMethod(2334054)") closureOrNil: nil receiver: a FaucetPlumbinTileMorph(1038220) --- The full stack --- Context(Object)>>error: Context(Object)>>errorSubscriptBounds: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: Context>>at: tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim You never really learn to swear until you learn to drive in Silicon Valley |
Something pretty weird is happening when the break is hit. I *finally* got a debugger open on a backtrace that includes the problem with Context>at: failing becasue the argument is 0. It's all a bit strange and unless I managed to do something very odd it looks like a fairly serious bug.
I actually caught this because something went wrong in code I added to try to log the dan initial error. Despite that it does appear to be a trace on the #break problem. debugger>doStep called from #stepOver. #handleLabelUpdatesIn:whenExecuting: used and does [interruptedProcess completeStep: currentContext] which uses... Process>>evaluate:onBehalfOf: Context>runUntilErrorOrReturnFrom: Context>jump - *we are checking for stackp = 0 which is the very thing that causes problems later with the #pop* In the #stepToSendOrReturn we use interpretNextInstructionFor: which leads to InterpretV3ClosuresExtension: 7 in: (Object>>break) for: ( aContext sender #on:do:, pc 24 stackp 0 method Object>>break, etc) -> doPop -> pop (presumably stackp was 0 here? See above re: #jump) -> at: ... but if so why did the error code appear to skip over the first two tests of it? <primitive: 210> index = 0 ifTrue:[FileStream newFileNamed: 'squeakBreak.log' do:[:f| self errorReportOn: f]]. index isInteger ifTrue: [self errorSubscriptBounds: index]. index isNumber ifTrue: [^self at: index asInteger]"<--- it went here and on the second go around it picked up that index = 0 properly." ifFalse: [self errorNonIntegerIndex] So I *think* that there is an issue in Context>jump where we explicitly check for stackp = 0 but then call code that carefully does a pop via #at:. Something about the primitive: 210 (maybe?) does something weird and the index is both 0 and not 0 - nor even an Integer. As an interesting bonus, the clause I added to log things when 'index = 0' went very wrong because the 'f' getting passed to the block is apparently the MultiByteFileStream *class* rather than the opened file! The bit bothering me at the moment is just how this can be a problem that hasn't whacked us before. I haven't been able to cause it with 'normal' code but all I was doing to fall over this was loading & testing the old Plumbing demo code. Oh, I did just try to see if a newer vm (I am running the 201912311458 ARMv6) would have a fix for the prim 210 but no newer ARM VM will run at all. The latest Mac vm runs but fails with the same huge list of notifiers reporting the error in Context>at: - the fact that there is a *lot* of #at: on the stack is a little more odd. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- If you stand close enough to him, you can hear the ocean |
Hi Tim, excellent work!
Coincidentally, I studied the same problem yesterday, but I did not yet complete to report my observations to you. So let me to this hereby:
After many hours of funny debugging, now I could create this minimum failing example:
Expected behavior: First, a debugger is shown, and after proceeding it, a dialog window is shown. Actual behavior: Both the debugger and the dialog window are shown asynchronously! Suspicion of someone who did not yet dive deeply into the activeProcess concept: The debugger resumes the wrong process, as the activeProcess concept simulates a different running process for the error, even against the debugger. If my theory is correct, we would need to find a way to look behind the scenes of the activeProcess and use it in the debugging code. But first, I really need to learn more about this concept.
(Connection to our Context >> #at: problems: Probably no primitive issue at all, just the fact, that #at: calls itself recursively after the error was proceeded - similar like #doesNotUnderstand: does.)
This is an in-midst-of-work message; just did not want us to any duplicate or redundant work. Will have a closer look at this disgusting problem ASAP! And vice versa, it would be very nice if you could keep me/us up-to-date!
(Oh, what a fun to debug a self-simulating system ...)
Best, Christoph Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Dienstag, 28. Januar 2020 03:08 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Code simulation error (was Re: I broke the debugger?) Something pretty weird is happening when the break is hit. I *finally* got a debugger open on a backtrace that includes the problem with Context>at: failing becasue the argument is 0. It's all a bit strange and unless I managed to do
something very odd it looks like a fairly serious bug.
I actually caught this because something went wrong in code I added to try to log the dan initial error. Despite that it does appear to be a trace on the #break problem. debugger>doStep called from #stepOver. #handleLabelUpdatesIn:whenExecuting: used and does [interruptedProcess completeStep: currentContext] which uses... Process>>evaluate:onBehalfOf: Context>runUntilErrorOrReturnFrom: Context>jump - *we are checking for stackp = 0 which is the very thing that causes problems later with the #pop* In the #stepToSendOrReturn we use interpretNextInstructionFor: which leads to InterpretV3ClosuresExtension: 7 in: (Object>>break) for: ( aContext sender #on:do:, pc 24 stackp 0 method Object>>break, etc) -> doPop -> pop (presumably stackp was 0 here? See above re: #jump) -> at: ... but if so why did the error code appear to skip over the first two tests of it? <primitive: 210> index = 0 ifTrue:[FileStream newFileNamed: 'squeakBreak.log' do:[:f| self errorReportOn: f]]. index isInteger ifTrue: [self errorSubscriptBounds: index]. index isNumber ifTrue: [^self at: index asInteger]"<--- it went here and on the second go around it picked up that index = 0 properly." ifFalse: [self errorNonIntegerIndex] So I *think* that there is an issue in Context>jump where we explicitly check for stackp = 0 but then call code that carefully does a pop via #at:. Something about the primitive: 210 (maybe?) does something weird and the index is both 0 and not 0 - nor even an Integer. As an interesting bonus, the clause I added to log things when 'index = 0' went very wrong because the 'f' getting passed to the block is apparently the MultiByteFileStream *class* rather than the opened file! The bit bothering me at the moment is just how this can be a problem that hasn't whacked us before. I haven't been able to cause it with 'normal' code but all I was doing to fall over this was loading & testing the old Plumbing demo code. Oh, I did just try to see if a newer vm (I am running the 201912311458 ARMv6) would have a fix for the prim 210 but no newer ARM VM will run at all. The latest Mac vm runs but fails with the same huge list of notifiers reporting the error in Context>at: - the fact that there is a *lot* of #at: on the stack is a little more odd. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- If you stand close enough to him, you can hear the ocean
Carpe Squeak!
|
Hi all,
I took a closer look at the ActiveProcess concept and I think I found a solution approach to fix all these nasty infinite debugger chains that occurred when any bytecode simulation error occurred. Please see the attached changeset.
The main cognition was the issue that any bytecode simulation error, which is executed behind an #evaluate:onBehalfOf: call, should *not* be debugged on the "behalf-of" process but indeed on the "basic" active process who called #evaluate:onBehalfOf:. Otherwise, the simulating process would not have been stopped by the debugger. See Process >> #step:, for example. So I added Process >> #basicActiveProcess, which returns the real activeProcess without regard to #effectiveProcess. This method is used by StandardToolSet & debugger in order to identify the process to debug. At other places, #effectiveProcess must be never used as this would take the idea of ActiveProcess ad absurdum and make it impossible to debug certain processing logic. The changeset also consists of a new test method in DebuggerTests that tests this regression.
So this is a list of recent issues that *won't* crash your image after loading this changeset:
They still may raise a "usual" error because the context simulation is buggy in some respects, but so far I did not manage to find another bug that crashes your image. And this should make it so much easier to debug and fix the remaining simulation bugs!
In any case, please review! :-) I'm almost sure you will have some criticism, but how do you think about the approach in general? I wonder whether there will be any situation where we cannot debug the senders of #basicActiveProcess properly because they
don't follow the ActiveProcess concept. But in general, I think it's clearly an improvement against the current state of Trunk. I'm looking forward to your feedback!
Best,
Christoph
Von: Squeak-dev <[hidden email]> im Auftrag von Thiede, Christoph
Gesendet: Dienstag, 28. Januar 2020 09:17 Uhr An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Code simulation error (was Re: I broke the debugger?) Hi Tim, excellent work!
Coincidentally, I studied the same problem yesterday, but I did not yet complete to report my observations to you. So let me to this hereby:
After many hours of funny debugging, now I could create this minimum failing example:
Expected behavior: First, a debugger is shown, and after proceeding it, a dialog window is shown. Actual behavior: Both the debugger and the dialog window are shown asynchronously! Suspicion of someone who did not yet dive deeply into the activeProcess concept: The debugger resumes the wrong process, as the activeProcess concept simulates a different running process for the error, even against the debugger. If my theory is correct, we would need to find a way to look behind the scenes of the activeProcess and use it in the debugging code. But first, I really need to learn more about this concept.
(Connection to our Context >> #at: problems: Probably no primitive issue at all, just the fact, that #at: calls itself recursively after the error was proceeded - similar like #doesNotUnderstand: does.)
This is an in-midst-of-work message; just did not want us to any duplicate or redundant work. Will have a closer look at this disgusting problem ASAP! And vice versa, it would be very nice if you could keep me/us up-to-date!
(Oh, what a fun to debug a self-simulating system ...)
Best, Christoph Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Dienstag, 28. Januar 2020 03:08 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Code simulation error (was Re: I broke the debugger?) Something pretty weird is happening when the break is hit. I *finally* got a debugger open on a backtrace that includes the problem with Context>at: failing becasue the argument is 0. It's all a bit strange and unless I managed to do
something very odd it looks like a fairly serious bug.
I actually caught this because something went wrong in code I added to try to log the dan initial error. Despite that it does appear to be a trace on the #break problem. debugger>doStep called from #stepOver. #handleLabelUpdatesIn:whenExecuting: used and does [interruptedProcess completeStep: currentContext] which uses... Process>>evaluate:onBehalfOf: Context>runUntilErrorOrReturnFrom: Context>jump - *we are checking for stackp = 0 which is the very thing that causes problems later with the #pop* In the #stepToSendOrReturn we use interpretNextInstructionFor: which leads to InterpretV3ClosuresExtension: 7 in: (Object>>break) for: ( aContext sender #on:do:, pc 24 stackp 0 method Object>>break, etc) -> doPop -> pop (presumably stackp was 0 here? See above re: #jump) -> at: ... but if so why did the error code appear to skip over the first two tests of it? <primitive: 210> index = 0 ifTrue:[FileStream newFileNamed: 'squeakBreak.log' do:[:f| self errorReportOn: f]]. index isInteger ifTrue: [self errorSubscriptBounds: index]. index isNumber ifTrue: [^self at: index asInteger]"<--- it went here and on the second go around it picked up that index = 0 properly." ifFalse: [self errorNonIntegerIndex] So I *think* that there is an issue in Context>jump where we explicitly check for stackp = 0 but then call code that carefully does a pop via #at:. Something about the primitive: 210 (maybe?) does something weird and the index is both 0 and not 0 - nor even an Integer. As an interesting bonus, the clause I added to log things when 'index = 0' went very wrong because the 'f' getting passed to the block is apparently the MultiByteFileStream *class* rather than the opened file! The bit bothering me at the moment is just how this can be a problem that hasn't whacked us before. I haven't been able to cause it with 'normal' code but all I was doing to fall over this was loading & testing the old Plumbing demo code. Oh, I did just try to see if a newer vm (I am running the 201912311458 ARMv6) would have a fix for the prim 210 but no newer ARM VM will run at all. The latest Mac vm runs but fails with the same huge list of notifiers reporting the error in Context>at: - the fact that there is a *lot* of #at: on the stack is a little more odd. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- If you stand close enough to him, you can hear the ocean fix-infinite-debuggers.2.cs (6K) Download Attachment
Carpe Squeak!
|
>
> <fix-infinite-debuggers.2.cs> Interesting. I filed that into a 19230 image (because that's what I had running) and tried my PlumbingDemo-crash again. It *doesn't( make stepping over the break work but it *does* result in a clean new debugger on the debugger that shows the problem I reported with the Context>jump leading to Context>at: 0. More interestingly the #at: 0 problem is now a simple case of doPop->pop->at:->errorSubscriptBounds with no strange #at: failing to notice index = 0. I'm still baffled by how this can be breaking so strangely; it's just the usual 'self break' at the beginning of a perfectly ordinary looking method. Maybe it's the whole Morphic drawing method thing. And clearly there is some interaction with Eliot's work on process-faithful debugging. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- One clown short of a circus. |
Here is a second approach to fix the bug:
Best,
Christoph
Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Dienstag, 28. Januar 2020 21:24 Uhr An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Fixing the infinite debugger chains? (was: Code simulation error (was Re: I broke the debugger?)) >
> <fix-infinite-debuggers.2.cs> Interesting. I filed that into a 19230 image (because that's what I had running) and tried my PlumbingDemo-crash again. It *doesn't( make stepping over the break work but it *does* result in a clean new debugger on the debugger that shows the problem I reported with the Context>jump leading to Context>at: 0. More interestingly the #at: 0 problem is now a simple case of doPop->pop->at:->errorSubscriptBounds with no strange #at: failing to notice index = 0. I'm still baffled by how this can be breaking so strangely; it's just the usual 'self break' at the beginning of a perfectly ordinary looking method. Maybe it's the whole Morphic drawing method thing. And clearly there is some interaction with Eliot's work on process-faithful debugging. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- One clown short of a circus.
Carpe Squeak!
|
> Unfortunately, for reasons I did not yet figure out, this fixes all
recursions listed in my latest post, with exception of Generator>>#nextPut:. Short update: The latter can be explained by looking at Context >> #cannotReturn:, which spawns a debugger on the activeProcess (!) manually. Not sure why we cannot simply raise a regular exception here? This would also be analogous to BlockCannotReturn ... Best, Christoph -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
Carpe Squeak!
|
Hi all,
Want another easy way to still get endless debuggers? [^ self halt] ensure: [1 asString] Do it, then step over the return (I have to click twice actually) --> endless debuggers on findContextSuchThat:. Triggers in both current Trunk and in 5.3, and 5.2, and 5.0. In 5.1 and 4.6 I get repeated emergency evaluators instead. If you proceed in the debugger after the halt, the expression evaluates flawlessly. If this example is not actually a new one, just be reminded that the problem still exists... ;-) Kind regards, Jakob Am So., 23. Feb. 2020 um 23:45 Uhr schrieb Christoph Thiede <[hidden email]>: > > > Unfortunately, for reasons I did not yet figure out, this fixes all > recursions listed in my latest post, with exception of Generator>>#nextPut:. > > Short update: The latter can be explained by looking at Context >> > #cannotReturn:, which spawns a debugger on the activeProcess (!) manually. > Not sure why we cannot simply raise a regular exception here? This would > also be analogous to BlockCannotReturn ... > > Best, > Christoph > > > > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > |
Oh, my 4.5 images open only one debugger for findContextSuchThat:.
That is, one debugger per further click on "Over". Am Do., 18. Juni 2020 um 01:14 Uhr schrieb Jakob Reschke <[hidden email]>: > > Hi all, > > Want another easy way to still get endless debuggers? > > [^ self halt] ensure: [1 asString] > > Do it, then step over the return (I have to click twice actually) --> > endless debuggers on findContextSuchThat:. > > Triggers in both current Trunk and in 5.3, and 5.2, and 5.0. In 5.1 > and 4.6 I get repeated emergency evaluators instead. > > If you proceed in the debugger after the halt, the expression > evaluates flawlessly. > > If this example is not actually a new one, just be reminded that the > problem still exists... ;-) > > Kind regards, > Jakob > > Am So., 23. Feb. 2020 um 23:45 Uhr schrieb Christoph Thiede > <[hidden email]>: > > > > > Unfortunately, for reasons I did not yet figure out, this fixes all > > recursions listed in my latest post, with exception of Generator>>#nextPut:. > > > > Short update: The latter can be explained by looking at Context >> > > #cannotReturn:, which spawns a debugger on the activeProcess (!) manually. > > Not sure why we cannot simply raise a regular exception here? This would > > also be analogous to BlockCannotReturn ... > > > > Best, > > Christoph > > > > > > > > -- > > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > > |
Nice finding. The basisActiveProcess patch catches this, but we still get a BlockCannotReturn there. I guess this has the same reason as http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-gt-gt-nextPut-td5108125.html#a5109109 ...
Von: Squeak-dev <[hidden email]> im Auftrag von Jakob Reschke <[hidden email]>
Gesendet: Donnerstag, 18. Juni 2020 01:44:28 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Fixing the infinite debugger chains? (was: Code simulation error (was Re: I broke the debugger?)) Oh, my 4.5 images open only one debugger for findContextSuchThat:.
That is, one debugger per further click on "Over". Am Do., 18. Juni 2020 um 01:14 Uhr schrieb Jakob Reschke <[hidden email]>: > > Hi all, > > Want another easy way to still get endless debuggers? > > [^ self halt] ensure: [1 asString] > > Do it, then step over the return (I have to click twice actually) --> > endless debuggers on findContextSuchThat:. > > Triggers in both current Trunk and in 5.3, and 5.2, and 5.0. In 5.1 > and 4.6 I get repeated emergency evaluators instead. > > If you proceed in the debugger after the halt, the expression > evaluates flawlessly. > > If this example is not actually a new one, just be reminded that the > problem still exists... ;-) > > Kind regards, > Jakob > > Am So., 23. Feb. 2020 um 23:45 Uhr schrieb Christoph Thiede > <[hidden email]>: > > > > > Unfortunately, for reasons I did not yet figure out, this fixes all > > recursions listed in my latest post, with exception of Generator>>#nextPut:. > > > > Short update: The latter can be explained by looking at Context >> > > #cannotReturn:, which spawns a debugger on the activeProcess (!) manually. > > Not sure why we cannot simply raise a regular exception here? This would > > also be analogous to BlockCannotReturn ... > > > > Best, > > Christoph > > > > > > > > -- > > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > >
Carpe Squeak!
|
Hi all! :-)
After a lot of time, I would like to give this issue another push. These bugs are really serious and we should finally fix them. Short summary for everyone who would not like to re-read the whole thread: / Over the last months, several issues have been reported about infinite chains of debuggers popping up in your image and, most of the time, eventually making it unusable. Some months ago, I traced these issues down to several simulation errors that occurred while pressing the Over button in the debugger. The simulation errors can be fixed separately, but the debugger chains are caused by a second phenomenon which I could break down in the following snippet: Processor activeProcess evaluate: [self error: #first. self inform: #second] onBehalfOf: [] newProcess You would expect to see first a debugger window for the #error, and second, after you resume this error, a dialog window for the #inform:. However, surprisingly, both windows appear at the same time. The opening debugger does not suspend the process correctly. / I also had a talk about it with Marcel and Patrick and we ended up with the finding that the semantics of Process >> #evaluate:onBehalfOf: are not 100% clear at the moment. Its method comment states: "Evaluate aBlock setting effectiveProcess to aProcess, and all other variables other than the scheduling ones to those of aProcess." However, the situation is unclear when an exception is raised from aBlock. Should it be handled still on behalf of the behalfOf process or rather on the original receiver process instead? At the moment, the former is the case, and this leads to the problem that the behalfOf process is debugged (i.e. interrupted) when an error is raised from aBlock while the - technically actually causing - receiver process keeps running, eventually ignoring the just-raised exception. See StandardToolSet class >> #handleError: for the place where "Processor activeProcess" is determined for debugging, which is redirected to the onBehalf process during the execution of aBlock. At this place, we actually would like to see something like this: thisContext process debug: anError signalerContext title: anError description Which, however, is not possible because a stack frame cannot know its containing process. So in my first changeset (fix-infinite-debuggers.2.cs below), I had proposed to rewrite that method like this: Processor basicActiveProcess debug: anError signalerContext title: anError description where basicActiveProcess would return the "true" active process neglecting the onBehalfOf redirection. However, *could there be any situation where you would like to respect the process redirection indeed in #handleError:?* (highlighting this as the open key question of this thread) We did not find a plausible example, the only case I could imagine is the following situation (which, admittedly, is not an every-day use case): Debug the expression "self halt", step down until in StandardToolSet class>>handleError:, step into #activeProcess and then step over repeatedly until #debug:title: is sent. In Trunk, this opens a second debugger on the same process. When using #basicActiveProcess, however, the first debugger stops working (dead process). So, your comments and thoughts are important: How would you think about the proposed #basicActiveProcess solution? Do you see any scenario where the onBehalfOf redirection needs to be perpetuated in ToolSet >> #handleError:? Or would you prefer another approach to fix the problem? Looking forward to an interesting discussion! :-) Best, Christoph -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
Carpe Squeak!
|
Hi all,
> On Oct 28, 2020, at 5:50 AM, Christoph Thiede <[hidden email]> wrote: > > Hi all! :-) > > After a lot of time, I would like to give this issue another push. These > bugs are really serious and we should finally fix them. > > Short summary for everyone who would not like to re-read the whole thread: > / > Over the last months, several issues have been reported about infinite > chains of debuggers popping up in your image and, most of the time, > eventually making it unusable. Some months ago, I traced these issues down > to several simulation errors that occurred while pressing the Over button in > the debugger. The simulation errors can be fixed separately, but the > debugger chains are caused by a second phenomenon which I could break down > in the following snippet: > > Processor activeProcess > evaluate: [self error: #first. self inform: #second] > onBehalfOf: [] newProcess > > You would expect to see first a debugger window for the #error, and > second, after you resume this error, a dialog window for the #inform:. > However, surprisingly, both windows appear at the same time. The opening > debugger does not suspend the process correctly. > / > > > I also had a talk about it with Marcel and Patrick and we ended up with the > finding that the semantics of Process >> #evaluate:onBehalfOf: are not 100% > clear at the moment. Its method comment states: > > "Evaluate aBlock setting effectiveProcess to aProcess, and all other > variables other than the scheduling ones to those of aProcess." > > However, the situation is unclear when an exception is raised from aBlock. > Should it be handled still on behalf of the behalfOf process or rather on > the original receiver process instead? Conceptually Process >> #evaluate:onBehalfOf: is a private method if the debugger, which exists only to ensure that while simulating code on behalf of done process being debugged, the right process is found by the simulated code even though another process is actually executing the code. Therefore the block being evaluated within Process >> #evaluate:onBehalfOf: is always evaluating some simulation on behalf of the debugger. Therefore, *any* error which occurs during the block is not an error in the process being debugged (that error delivery should be simulated, and delivered within the process being debugged), but an error in the simulation, and should stop the simulation. Therefore, an error within the evaluate block of Process >> #evaluate:onBehalfOf: could be caught within Process >> #evaluate:onBehalfOf: but delivered outside. One could experiment with adding an exception handler around the evaluation block that would copy the stack of the exception, terminate the block, and then open a debugger on the copy of the stack once the effectiveProcess has been restored. [P.S. I think the right way to implement this is to use Context>>cut: to snip the section of the stack containing the simulation error and stitch this back in after the evaluate block, but I *think* I am seeing bugs in the context-to-stack mapping machinery in the VM which is causing the stitching back of the stack to fail, which is why I’m trying (successfully does far) to simulate the simulator. So hopefully in a few days the stitching approach will be viable, but did the moment the stack copying approach will work, even though it introduces unnecessary overhead.] I hope this helps, and I hope I’m understanding the issue correctly. If I’m not I thank you for your patience :-). > At the moment, the former is the case, and this leads to the problem that > the behalfOf process is debugged (i.e. interrupted) when an error is raised > from aBlock while the - technically actually causing - receiver process > keeps running, eventually ignoring the just-raised exception. See > StandardToolSet class >> #handleError: for the place where "Processor > activeProcess" is determined for debugging, which is redirected to the > onBehalf process during the execution of aBlock. > At this place, we actually would like to see something like this: > > thisContext process > debug: anError signalerContext > title: anError description > > Which, however, is not possible because a stack frame cannot know its > containing process. > So in my first changeset (fix-infinite-debuggers.2.cs below), I had proposed > to rewrite that method like this: > > Processor basicActiveProcess > debug: anError signalerContext > title: anError description > > where basicActiveProcess would return the "true" active process neglecting > the onBehalfOf redirection. > However, *could there be any situation where you would like to respect the > process redirection indeed in #handleError:?* (highlighting this as the open > key question of this thread) > We did not find a plausible example, the only case I could imagine is the > following situation (which, admittedly, is not an every-day use case): > > Debug the expression "self halt", step down until in StandardToolSet > class>>handleError:, step into #activeProcess and then step over repeatedly > until #debug:title: is sent. > In Trunk, this opens a second debugger on the same process. When using > #basicActiveProcess, however, the first debugger stops working (dead > process). > > > So, your comments and thoughts are important: How would you think about the > proposed #basicActiveProcess solution? Do you see any scenario where the > onBehalfOf redirection needs to be perpetuated in ToolSet >> #handleError:? > Or would you prefer another approach to fix the problem? > Looking forward to an interesting discussion! :-) > > Best, > Christoph Eliot _,,,^..^,,,_ (phone) |
Hi Eliot,
thanks for your reply! > Therefore, an error within the evaluate block of Process >> #evaluate:onBehalfOf: could be caught within Process >> #evaluate:onBehalfOf: but delivered outside. One could experiment
with adding an exception handler around the evaluation block that would copy the stack of the exception, terminate the block, and then open a debugger on the copy of the stack once the effectiveProcess has been restored.
This sounds pretty much like what I proposed here: http://forum.world.st/I-broke-the-debugger-tp5110752p5111016.html
This solution would also have the advantage of a lower footprint than any #basicActiveProcess solution.
How would you think about it? :-)
Best,
Christoph
Von: Squeak-dev <[hidden email]> im Auftrag von Eliot Miranda <[hidden email]>
Gesendet: Mittwoch, 28. Oktober 2020 14:43:51 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Fixing the infinite debugger chains? (was: Code simulation error (was Re: I broke the debugger?)) Hi all,
> On Oct 28, 2020, at 5:50 AM, Christoph Thiede <[hidden email]> wrote: > > Hi all! :-) > > After a lot of time, I would like to give this issue another push. These > bugs are really serious and we should finally fix them. > > Short summary for everyone who would not like to re-read the whole thread: > / > Over the last months, several issues have been reported about infinite > chains of debuggers popping up in your image and, most of the time, > eventually making it unusable. Some months ago, I traced these issues down > to several simulation errors that occurred while pressing the Over button in > the debugger. The simulation errors can be fixed separately, but the > debugger chains are caused by a second phenomenon which I could break down > in the following snippet: > > Processor activeProcess > evaluate: [self error: #first. self inform: #second] > onBehalfOf: [] newProcess > > You would expect to see first a debugger window for the #error, and > second, after you resume this error, a dialog window for the #inform:. > However, surprisingly, both windows appear at the same time. The opening > debugger does not suspend the process correctly. > / > > > I also had a talk about it with Marcel and Patrick and we ended up with the > finding that the semantics of Process >> #evaluate:onBehalfOf: are not 100% > clear at the moment. Its method comment states: > > "Evaluate aBlock setting effectiveProcess to aProcess, and all other > variables other than the scheduling ones to those of aProcess." > > However, the situation is unclear when an exception is raised from aBlock. > Should it be handled still on behalf of the behalfOf process or rather on > the original receiver process instead? Conceptually Process >> #evaluate:onBehalfOf: is a private method if the debugger, which exists only to ensure that while simulating code on behalf of done process being debugged, the right process is found by the simulated code even though another process is actually executing the code. Therefore the block being evaluated within Process >> #evaluate:onBehalfOf: is always evaluating some simulation on behalf of the debugger. Therefore, *any* error which occurs during the block is not an error in the process being debugged (that error delivery should be simulated, and delivered within the process being debugged), but an error in the simulation, and should stop the simulation. Therefore, an error within the evaluate block of Process >> #evaluate:onBehalfOf: could be caught within Process >> #evaluate:onBehalfOf: but delivered outside. One could experiment with adding an exception handler around the evaluation block that would copy the stack of the exception, terminate the block, and then open a debugger on the copy of the stack once the effectiveProcess has been restored. [P.S. I think the right way to implement this is to use Context>>cut: to snip the section of the stack containing the simulation error and stitch this back in after the evaluate block, but I *think* I am seeing bugs in the context-to-stack mapping machinery in the VM which is causing the stitching back of the stack to fail, which is why I’m trying (successfully does far) to simulate the simulator. So hopefully in a few days the stitching approach will be viable, but did the moment the stack copying approach will work, even though it introduces unnecessary overhead.] I hope this helps, and I hope I’m understanding the issue correctly. If I’m not I thank you for your patience :-). > At the moment, the former is the case, and this leads to the problem that > the behalfOf process is debugged (i.e. interrupted) when an error is raised > from aBlock while the - technically actually causing - receiver process > keeps running, eventually ignoring the just-raised exception. See > StandardToolSet class >> #handleError: for the place where "Processor > activeProcess" is determined for debugging, which is redirected to the > onBehalf process during the execution of aBlock. > At this place, we actually would like to see something like this: > > thisContext process > debug: anError signalerContext > title: anError description > > Which, however, is not possible because a stack frame cannot know its > containing process. > So in my first changeset (fix-infinite-debuggers.2.cs below), I had proposed > to rewrite that method like this: > > Processor basicActiveProcess > debug: anError signalerContext > title: anError description > > where basicActiveProcess would return the "true" active process neglecting > the onBehalfOf redirection. > However, *could there be any situation where you would like to respect the > process redirection indeed in #handleError:?* (highlighting this as the open > key question of this thread) > We did not find a plausible example, the only case I could imagine is the > following situation (which, admittedly, is not an every-day use case): > > Debug the expression "self halt", step down until in StandardToolSet > class>>handleError:, step into #activeProcess and then step over repeatedly > until #debug:title: is sent. > In Trunk, this opens a second debugger on the same process. When using > #basicActiveProcess, however, the first debugger stops working (dead > process). > > > So, your comments and thoughts are important: How would you think about the > proposed #basicActiveProcess solution? Do you see any scenario where the > onBehalfOf redirection needs to be perpetuated in ToolSet >> #handleError:? > Or would you prefer another approach to fix the problem? > Looking forward to an interesting discussion! :-) > > Best, > Christoph Eliot _,,,^..^,,,_ (phone)
Carpe Squeak!
|
In reply to this post by Eliot Miranda-2
Hi Eliot. > Therefore, *any* error which occurs during the block is not an error in the process > being debugged (that error delivery should be simulated, and delivered within the > process being debugged), but an error in the simulation, and should stop the simulation. Well, unfortunately, one cannot know. Think of simulating "7/0". Best, Marcel
|
Hi Marcel!
> Think of simulating "7/0". I don't understand what you mean. :-) [7 / 0] ifError: [#error] returns #error. [[7 / 0] newProcess runUntil: [:c | c isDead]] ifError: [#error] does not. The only exception is signaled *in* the simulation process, it shows up a debugger, but the exception does not arrive at the simulating process. Best, Christoph -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
Carpe Squeak!
|
Hi Christoph. Sounds good then. :-) Best, Marcel
|
Hi all, hi Eliot,
I have to revise my previous recommendation of the #basicEvaluate:onBehalfOf: solution. After taking another look at Jakob's example from above ([^ self halt] ensure: [1 asString]), I recognized that this approach would not fix the infinite debuggers in this situation. Here's the reason behind it: When stepping over the '^ self halt' statement in the example, a #cannotReturn: message is invoked by the VM at some point where the stack looks somehow like this: Context>>return:through: Context>>aboutToReturn:through: ... Context>>runUntilErrorOrReturnFrom: ... Process>>evaluate:onBehalfOf: ... Process>>complete: ... Debugger>>doStep However, the fact that a #cannotReturn: has been invoked means that the stack has got corrupted during the execution, so no exception can be passed back to any exception handler that we might install in #evaluate:onBehalfOf:. For this reason, when the BlockCannotReturn handling reaches StandardToolSet >> #handleError:, the effectiveProcess is suspended instead of the original activeProcess, and the debuggers are bouncing again ... Now you might argue that this situation is only the consequence of another error that occurs during the simulated execution of Context>>aboutToReturn:through: (because of the #runUntilErrorOrReturnFrom: hack, see http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-gt-gt-nextPut-td5108125.html#a5109109), but I constructed another example that is immune to the basicEvaluate:onBehalfOf: approach, too, but in this example the fault in this example is clearly located in the user code so a powerful debugger framework should not struggle about it: [] ensure: [thisContext privSender: nil] "step over #ensure:" And there is even a second problem with the basicEvaluate:onBehalfOf: process because I found two calls on Process >> #debug:title:full: from the simulator (Context) that do not even signal any exception before invoking the debugger on the activeProcess, so again, an exception handler in #basicEvaluate:onBehalfOf: would not be activated at all. tl;dr: The basicEvaluate:onBehalfOf: approach, in spite of its simplicity, would not cover all situations that can lead to an infinite debugger situation. For this reason, I recommend to use my first approach instead, which was to define #basicActiveProcess and #isBasicActiveProcess on Process that ignore the effectiveProcess mock-up for the single purpose of suspending the correct process when a debugger is spawned in whatever way inside of an #evaluate:onBehalfOf: block. Does this argument sound reasonable to you? :-) I have prepared some tests and an updated changeset and am looking forward to uploading it with your agreement. Best, Christoph -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
Carpe Squeak!
|
Hi all, hi Eliot,
sorry for double-posting on purpose, but this issue and my thoughts on it have become so complicated that I needed to separate two different subtopics from each other: I just identified another limitation in the process-faithful debugging model, it cannot be applied nestable: Consider the following expression: Processor activeProcess environmentAt: #foo put: 42. Processor halt activeProcess environmentAt: #foo. This snippet returns 42 independently of whether you click Proceed in the Halt Debugger or instead click Debug and then step over the second #activeProcess send. However, you cannot select the Over or Through button in the debugger and debug its action on a third process - if you try to do so, an environmentKeyNotFound error will be raised eventually from the DoIt. The reason for this is that the effectiveProcess approach is not nestable. I find this quite a pity in a self-supporting system ... Here is a very small patch that would eliminate this restriction: Processor >> effectiveProcess "effectiveProcess is a mechanism to allow process-faithful debugging. The debugger executes code on behalf of processes, so unless some effort is made the identity of Processor activeProcess is not correctly maintained when debugging code. The debugger uses evaluate:onBehalfOf: to assign the debugged process as the effectiveProcess of the process executing the code, preserving process identity." + ^effectiveProcess ifNil: [self] ifNotNil: [:process | process effectiveProcess] - ^effectiveProcess ifNil: [self] Would it be possible to apply this change or are there any good arguments against it? :-) If it would be possible, I would be glad to upload the patch to the inbox, and I also have prepared some tests for it. I'm proposing this change in the same thread as the #basicActiveProcess discussion because if we decide to make process-faithful debugging nestable (please! :D), #basicActiveProcess (probably #executingProcess would be a better name for it ...) as some kind of reciprocal operation for #effectiveProcess should be nestable in this case, too. Also, here are two more related questions for you (sorry for the walls of text! ;-)): 1.) Could you maybe explain the motivation for Kernel-eem.894/Kernel-eem.895 to me? Why is it necessary to modify the non-effective process? In a current Trunk image, ProcessorScheduler does never expose activeProcess itself (without wrapping it with an #effectiveProcess send). Are there any other references that need to be taken into account? I reverted to eem 9/7/2009 11:10 of #evaluate:onBehalfOf: and the environments example from above is still working. I have read [this thread](http://forum.world.st/Process-specific-state-difficult-to-debug-td4802422.html#a4802507) but I cannot reproduce your error and also System-eem.699 seems to be the wrong reference, at least I don't see how MessageTally is related to process-faithful debugging. 2.) This might be or might not be a question of coding styles, but when I browse the senders of #evaluate:onBehalfOf:, there are some methods that eventually make nested calls to #evaluate:onBehalfOf:, for instance, #popTo:/#return:value:/#activateReturn:value:. I assume this was not an intentional decision but kept for simplicity? Should we maybe eliminate these redundant nestings (and maybe speed up some things) by introducing a few basic selectors, or would this not be worth the time? I am looking forward to your help! :-) Best, Christoph -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
Carpe Squeak!
|
Free forum by Nabble | Edit this page |