[squeak-dev] autopsy of a nasty environment bug

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Tue Oct 25 08:30:10 UTC 2016


    "Create a foreign environment importing all from Smalltalk globals"
    foreign := Environment withName: #Foreign.
    foreign exportSelf.
    foreign import: Smalltalk globals.

    "Bind a new global"
    fooKey := #ClassVarScopeFoo.
    fooValue := Smalltalk globals at: fooKey put: Object basicNew.
    fooBinding := Smalltalk globals bindingOf: fooKey.
    self assert: (foreign bindingOf: fooKey) == fooBinding.

    "Unbind the global: it is moved to, and shared by both undeclared"
    Smalltalk globals removeKey: fooKey.
    self assert: (Smalltalk globals undeclared associationAt: fooKey) ==
fooBinding.
    self assert: (foreign undeclared associationAt: fooKey) == fooBinding.

    "Create a class var: the undeclared binding is moved to classPool.
    This is questionable, it was a global with potentially larger/different
scope."
    parent := Object
        subclass: #ClassVarScopeParent
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Dummy-Tests-Class'.
    child := parent
        subclass: #ClassVarScopeChild
        instanceVariableNames: ''
        classVariableNames: 'ClassVarScopeFoo'
        poolDictionaries: ''
        category: 'Dummy-Tests-Class'.
    self assert: (child classPool associationAt: fooKey) == fooBinding.

    "The global is no more in Smalltalk globals undeclared"
    self assert: (Smalltalk globals undeclared includesKey: fooKey) not.
    "But it is still in foreign undeclared"
    self assert: (foreign undeclared associationAt: fooKey) == fooBinding.

    "Rebind a new global"
    fooValue := Smalltalk globals at: fooKey put: Object basicNew.
    globalFooBinding := Smalltalk globals bindingOf: fooKey.

    "The binding has been removed from foreign undeclared"
    self assert: (foreign undeclared includesKey: fooKey) not.
    self assert: (foreign bindingOf: fooKey) == globalFooBinding.

    "But because #showBinding: did use a becomeForward: the class pool and
global bindings are now surprisingly fused.
    That explains that a foreign environment importing Smalltalk globals is
enough to make ClassVarScopeTest fail"
    self assert: globalFooBinding == fooBinding.
    self assert: (child classPool associationAt: fooKey) ==
globalFooBinding.

    "save our souls"
    classes := { child. parent }.
    child := parent := nil.
    classes do: [ :each |
        each
            removeFromChanges;
            removeFromSystemUnlogged ].
    classes := nil.
    Smalltalk globals removeKey: fooKey.
    foreign destroy.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20161025/48e183d5/attachment.htm


More information about the Squeak-dev mailing list