Hi Christoph,

looking for a new way to crash the image? :-) Here is one:
Highlighted on my todo list :)


In the meantime here's a VM crasher I came across while studying a bug in #return:from:

    Process new return: nil value: nil.

It generates an infinite stream of debuggers. I can't figure out what is going on but it has something to do with the recursion in #effectiveProcess (when I removed the recursion the infinite debuggers stream and VM crash was gone).

The crash is irrecoverable and I'm only able to capture the notifier window before killing the process. The system seems so confused it managed to send a non-integer to #priority :) (And that points to #effectiveProcess)


I'm just curious... I remember you worked on infinite debugger chains. Any explanation very welcome.
Best,
Jaromir


On 28-Nov-23 7:58:38 PM, christoph.thiede@student.hpi.uni-potsdam.de wrote:

Hi all,

looking for a new way to crash the image? :-) Here is one:

gen := Generator on: [:gen |
    
self assert: gen next isNil.
    
self error].
gen yield: 1.

This is a less idiomatic but more comprehensible version:

[c := thisContext.
[h := thisContext.
[h swapSender: thisContext sender.
c := thisContext swapSender: c] value.
thisContext swapSender: c] value] value.
[c := thisContext swapSender: c.
self error] value.

In a nutshell, the Generator temporarily creates a loop on the stack while switching coroutines. I didn't fully get behind its implementation at the moment, and I acknowledge that I am using the generator in the "wrong" way - usually the #on: block is the producer not the consumer. However, and especially with the recent debate on safe languages in mind, I wonder whether we would be able and willing to make Squeak safe against this phenomen (loops on the stack).

The actual crash (or better: hang) comes from primitiveFindHandlerContext, but I assume primitiveFindNextUnwindContext and primitiveTerminateTo would cause a similar effect. A simple fix would be to disable these optional primitives and use the image fallback instead. This makes the method interruptable similar to a convenient infinite loop. However, this is obviously much slower. I wonder whether these primitives could be made aware of possible context stack loops and fail when a loop is detected. When the primitive fails, the fallback code would run so the image would be interruptable again, or even better, we could also detect particular stack loops then:

Context>>findNextHandlerContextStarting
    "Return the next handler marked context, returning nil if there is none. Search starts with self and proceeds up to nil."

-    | ctx |
-    <primitive: 197>
+    | ctx known |
    ctx := self.
+    known := IdentitySet new.
        [ctx isHandlerContext ifTrue:[^ctx].
+        (known ifAbsentAdd: ctx) ifFalse: [Processor debugWithTitle: 'Loop on stack detected!' translated full: false].
        (ctx := ctx sender) == nil ] whileFalse.
    ^nil

So my questions to you are: Do we want to support this kind of safety (I would like it!)? Is this possible to implement in the VM without a concerning performance impact?

Best,
Christoph

---
Sent from Squeak Inbox Talk