[Vm-dev] VM Maker: VMMaker.oscog-eem.3142.mcz

Eliot Miranda eliot.miranda at gmail.com
Sat Jan 22 23:33:08 UTC 2022


Hi Jaromir,

On Sat, Jan 22, 2022 at 3:57 AM Jaromir Matas <mail at jaromir.net> wrote:

>
>
> Hi Eliot,
>
> I’d like to test it but the build failed for Windows and Mac; not sure
> what it means…
>
> Sorry to hear the current “incorrect” suspend behavior has been exploited
> more than expected in the existing code.
>

It's not the incorrect suspend behaviour that's being exploited, it's the
return value of suspend.  Existing code appears to depend on the
semaphore/mutex a process is blocked on being answered by suspend.

What would you think about having primitiveSuspendV2 return self instead of
> any list at all – to make all state changing methods answer consistently
> (like e.g. VW do)… if the answer expected by the “affected” code base has
> to be provided by primitiveSuspend anyways.
>

I don't see this is at all useful.  If one isn't interested in the
semaphore/mutex return value one does not have to examine it.  But there is
no way of getting the list once the process has been removed from it other
than by having the suspend primitive answer it.

So if one isn't interested in the return value simply write something of
the form

    aProcess suspend; yourself

But if one *is* interested in the result then the primitive better
answer it, nbo?

Best,
>
> Jaromir
>
>
>
> *From: *commits at source.squeak.org
> *Sent: *Saturday, January 22, 2022 2:11
> *To: *vm-dev at lists.squeakfoundation.org
> *Subject: *[Vm-dev] VM Maker: VMMaker.oscog-eem.3142.mcz
>
>
>
>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3142.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.3142
> Author: eem
> Time: 21 January 2022, 5:10:43.282744 pm
> UUID: ecaa84c0-26c9-440b-bc13-59a6e56c5e7c
> Ancestors: VMMaker.oscog-eem.3141
>
> Change the revised primitiveSuspend to behave clkoser to the original,
> always answeriong the list the receiver was on if bnlocked.  make the newer
> variant available as a named prim itive (primitiveSuspendV2).  AFAICT using
> primitiveSuspendV2 breaks lots of things (SqueakSSL tests hang, Virtend
> login hangs).  So while the idea is right, in practice answering nil if the
> receiver is suspended while waiting on a condition variable breaks more
> things than it fixes.
>
> =============== Diff against VMMaker.oscog-eem.3141 ===============
>
> Item was changed:
>   ----- Method: CoInterpreterPrimitives>>primitiveSuspend (in category
> 'process primitives') -----
>   primitiveSuspend
>          "Primitive. Suspend the receiver, aProcess, such that it can be
> executed again
>           by sending #resume. If the given process is not the active
> process, take it off
>           its corresponding list. If the list was not its run queue assume
> it was on some
>           condition variable (Semaphore, Mutex) and back up its pc to the
> send that
>           invoked the wait state the process entered.  Hence when the
> process resumes
> +         it will reenter the wait state. Answer the list the receiver was
> previously on,
> +         unless it was the activ eProcess, in which case answer nil."
> -         it will reenter the wait state. Answer the list the receiver was
> previously on iff
> -         it was not active and not blocked, otherwise answer nil."
>          | process myList myContext ok |
>          process := self stackTop.
>          process = self activeProcess ifTrue:
>                  [| inInterpreter |
>                  "We're going to switch process, either to an interpreted
> frame or a machine
>                   code frame. To know whether to return or enter machine
> code we have to
>                   know from whence we came.  We could have come from the
> interpreter,
>                   either directly or via a machine code primitive.  We
> could have come from
>                   machine code.  The instructionPointer tells us where
> from:"
>                  self pop: 1 thenPush: objectMemory nilObject.
>                  inInterpreter := instructionPointer >= objectMemory
> startOfMemory.
>                  self transferTo: self wakeHighestPriority from: CSSuspend.
>                  ^self
> forProcessPrimitiveReturnToExecutivePostContextSwitch: inInterpreter].
>          myList := objectMemory fetchPointer: MyListIndex ofObject:
> process.
>          myContext := objectMemory fetchPointer: SuspendedContextIndex
> ofObject: process.
>          ((objectMemory isPointers: myList)
>           and: [(objectMemory numSlotsOf: myList) > LastLinkIndex
>           and: [(objectMemory isContext: myContext)
>           and: [self isResumableContext: myContext]]]) ifFalse:
>                  [^self primitiveFailFor: PrimErrBadReceiver].
>          ok := self removeProcess: process fromList: myList.
>          ok ifFalse:
>                  [^self primitiveFailFor: PrimErrOperationFailed].
>          objectMemory storePointerUnchecked: MyListIndex ofObject: process
> withValue: objectMemory nilObject.
>          self assert: RevisedSuspend.
>          (RevisedSuspend
> +         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag]) ifTrue:
> +                [self backupContext: myContext toBlockingSendTo: myList].
> +        self pop: 1 thenPush: myList!
> -         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag])
> -                ifTrue:
> -                        [self backupContext: myContext toBlockingSendTo:
> myList.
> -                         self pop: 1 thenPush: objectMemory nilObject]
> -                ifFalse:
> -                        [self pop: 1 thenPush: myList]!
>
> Item was added:
> + ----- Method: CoInterpreterPrimitives>>primitiveSuspendV2 (in category
> 'process primitives') -----
> + primitiveSuspendV2
> +        "Primitive. Suspend the receiver, aProcess, such that it can be
> executed again
> +         by sending #resume. If the given process is not the active
> process, take it off
> +         its corresponding list. If the list was not its run queue assume
> it was on some
> +         condition variable (Semaphore, Mutex) and back up its pc to the
> send that
> +         invoked the wait state the process entered.  Hence when the
> process resumes
> +         it will reenter the wait state. Answer the list the receiver was
> previously on iff
> +         it was not active and not blocked, otherwise answer nil.
> +         c.f. primitiveSuspend, which always answers the list the process
> was on, if blocked."
> +        <export: true>
> +        | process myList myContext ok |
> +        process := self stackTop.
> +        process = self activeProcess ifTrue:
> +                [| inInterpreter |
> +                "We're going to switch process, either to an interpreted
> frame or a machine
> +                 code frame. To know whether to return or enter machine
> code we have to
> +                 know from whence we came.  We could have come from the
> interpreter,
> +                 either directly or via a machine code primitive.  We
> could have come from
> +                 machine code.  The instructionPointer tells us where
> from:"
> +                self pop: 1 thenPush: objectMemory nilObject.
> +                inInterpreter := instructionPointer >= objectMemory
> startOfMemory.
> +                self transferTo: self wakeHighestPriority from: CSSuspend.
> +                ^self
> forProcessPrimitiveReturnToExecutivePostContextSwitch: inInterpreter].
> +        myList := objectMemory fetchPointer: MyListIndex ofObject:
> process.
> +        myContext := objectMemory fetchPointer: SuspendedContextIndex
> ofObject: process.
> +        ((objectMemory isPointers: myList)
> +         and: [(objectMemory numSlotsOf: myList) > LastLinkIndex
> +         and: [(objectMemory isContext: myContext)
> +         and: [self isResumableContext: myContext]]]) ifFalse:
> +                [^self primitiveFailFor: PrimErrBadReceiver].
> +        ok := self removeProcess: process fromList: myList.
> +        ok ifFalse:
> +                [^self primitiveFailFor: PrimErrOperationFailed].
> +        objectMemory storePointerUnchecked: MyListIndex ofObject: process
> withValue: objectMemory nilObject.
> +        self assert: RevisedSuspend.
> +        (RevisedSuspend
> +         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag])
> +                ifTrue:
> +                        [self backupContext: myContext toBlockingSendTo:
> myList.
> +                         self pop: 1 thenPush: objectMemory nilObject]
> +                ifFalse:
> +                        [self pop: 1 thenPush: myList]!
>
> Item was changed:
>   ----- Method: CogVMSimulator class>>initialize (in category 'class
> initialization') -----
>   initialize
>          "These are primitives that alter the state of the stack.  They
> are here simply for assert checking.
>           After invocation the Cogit should not check for the expected
> stack delta when these primitives
>           succeed, because the stack will usually have been modified."
>          StackAlteringPrimitives := #(   primitiveClosureValue
> primitiveClosureValueWithArgs primitiveClosureValueNoContextSwitch
>
> primitiveClone primitiveInstVarAt primitiveSlotAt "because these can cause
> code compactions..."
>
> primitiveEnterCriticalSection primitiveExitCriticalSection
>
> primitiveFullClosureValue primitiveFullClosureValueWithArgs
> primitiveFullClosureValueNoContextSwitch
> +
> primitiveSignal primitiveWait primitiveResume primitiveSuspend
> primitiveSuspendV2 primitiveYield
> -
> primitiveSignal primitiveWait primitiveResume primitiveSuspend
> primitiveYield
>
> primitiveExecuteMethodArgsArray primitiveExecuteMethod
>
> primitivePerform primitivePerformWithArgs primitivePerformInSuperclass
>
> primitiveTerminateTo primitiveStoreStackp primitiveDoPrimitiveWithArgs)
> asIdentitySet!
>
> Item was changed:
>   ----- Method: StackInterpreterPrimitives>>primitiveSuspend (in category
> 'process primitives') -----
>   primitiveSuspend
>          "Primitive. Suspend the receiver, aProcess, such that it can be
> executed again
>           by sending #resume. If the given process is not the active
> process, take it off
>           its corresponding list. If the list was not its run queue assume
> it was on some
>           condition variable (Semaphore, Mutex) and back up its pc to the
> send that
>           invoked the wait state the process entered.  Hence when the
> process resumes
> +         it will reenter the wait state. Answer the list the receiver was
> previously on,
> +         unless it was the activ eProcess, in which case answer nil."
> -         it will reenter the wait state. Answer the list the receiver was
> previously on iff
> -         it was not active and not blocked, otherwise answer nil."
>          | process myList myContext ok |
>          process := self stackTop.
>          process = self activeProcess ifTrue:
>                  [self pop: 1 thenPush: objectMemory nilObject.
>                   ^self transferTo: self wakeHighestPriority].
>          myList := objectMemory fetchPointer: MyListIndex ofObject:
> process.
>          myContext := objectMemory fetchPointer: SuspendedContextIndex
> ofObject: process.
>          ((objectMemory isPointers: myList)
>           and: [(objectMemory numSlotsOf: myList) > LastLinkIndex
>           and: [(objectMemory isContext: myContext)
>           and: [self isResumableContext: myContext]]]) ifFalse:
>                  [^self primitiveFailFor: PrimErrBadReceiver].
>          ok := self removeProcess: process fromList: myList.
>          ok ifFalse:
>                  [^self primitiveFailFor: PrimErrOperationFailed].
>          objectMemory storePointerUnchecked: MyListIndex ofObject: process
> withValue: objectMemory nilObject.
>          self assert: RevisedSuspend.
>          (RevisedSuspend
> +         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag]) ifTrue:
> +                [self backupContext: myContext toBlockingSendTo: myList].
> +        self pop: 1 thenPush: myList!
> -         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag])
> -                ifTrue:
> -                        [self backupContext: myContext toBlockingSendTo:
> myList.
> -                         self pop: 1 thenPush: objectMemory nilObject]
> -                ifFalse:
> -                        [self pop: 1 thenPush: myList]!
>
> Item was added:
> + ----- Method: StackInterpreterPrimitives>>primitiveSuspendV2 (in
> category 'process primitives') -----
> + primitiveSuspendV2
> +        "Primitive. Suspend the receiver, aProcess, such that it can be
> executed again
> +         by sending #resume. If the given process is not the active
> process, take it off
> +         its corresponding list. If the list was not its run queue assume
> it was on some
> +         condition variable (Semaphore, Mutex) and back up its pc to the
> send that
> +         invoked the wait state the process entered.  Hence when the
> process resumes
> +         it will reenter the wait state. Answer the list the receiver was
> previously on iff
> +         it was not active and not blocked, otherwise answer nil.
> +         c.f. primitiveSuspend, which always answers the list the process
> was on, if blocked."
> +        <export: true>
> +        | process myList myContext ok |
> +        process := self stackTop.
> +        process = self activeProcess ifTrue:
> +                [self pop: 1 thenPush: objectMemory nilObject.
> +                 ^self transferTo: self wakeHighestPriority].
> +        myList := objectMemory fetchPointer: MyListIndex ofObject:
> process.
> +        myContext := objectMemory fetchPointer: SuspendedContextIndex
> ofObject: process.
> +        ((objectMemory isPointers: myList)
> +         and: [(objectMemory numSlotsOf: myList) > LastLinkIndex
> +         and: [(objectMemory isContext: myContext)
> +         and: [self isResumableContext: myContext]]]) ifFalse:
> +                [^self primitiveFailFor: PrimErrBadReceiver].
> +        ok := self removeProcess: process fromList: myList.
> +        ok ifFalse:
> +                [^self primitiveFailFor: PrimErrOperationFailed].
> +        objectMemory storePointerUnchecked: MyListIndex ofObject: process
> withValue: objectMemory nilObject.
> +        self assert: RevisedSuspend.
> +        (RevisedSuspend
> +         and: [(objectMemory fetchClassTagOfNonImm: myList) ~=
> classLinkedListClassTag])
> +                ifTrue:
> +                        [self backupContext: myContext toBlockingSendTo:
> myList.
> +                         self pop: 1 thenPush: objectMemory nilObject]
> +                ifFalse:
> +                        [self pop: 1 thenPush: myList]!
>
>
>


-- 
_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20220122/c097783e/attachment-0001.html>


More information about the Vm-dev mailing list