[VW7.4.1] SymbolicPaint hangs VM with infinite recursion

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[VW7.4.1] SymbolicPaint hangs VM with infinite recursion

Andre Schnoor

Does anybody know a safe rule of thumb for building up a consistent
color scheme using SymbolicPaint? It seems that even the slightest
modifications to the methods of
   
    LookPolicy>>installPlatformPreferencesFrom:on:  (in subclasses)

cause infinite recursion upon color lookup, which effectively hangs the VM.

Where's the best place to trap this recursion? (and possibly break it up
by answering a default value). Unfortunately this is extremely hard to
debug, because the debugger window will - of course - also access the
paint hierarchy.

After hours of digging, it's getting frustrating. Any hint is appreciated.

Andre


Reply | Threaded
Open this post in threaded view
|

RE: [VW7.4.1] SymbolicPaint hangs VM with infinite recursion

mark.b.ballard
Don't know if this will help.  I added the following to our system quite
awhile ago to detect an infinite recursion.  Instead of the halt:, you
could install a default paint.

HierarchicalSymbolicPaint


installOn: aGraphicsContext
        | foundPaint |
        self needsFixingMethod.
        foundPaint := aGraphicsContext paintPreferencesMatchAt: self.
        foundPaint = self ifTrue: [self halt: 'infinite loop installing
paint'].
        ^(foundPaint) installOn: aGraphicsContext

        "detect infinite loop.  we have not seen this problem in awhile.
the last case occured bringing up an image on linux that was last saved
on windows"

-----Original Message-----
From: [hidden email] [mailto:[hidden email]]
Sent: Friday, February 23, 2007 9:18 AM
To: vwnc-list
Subject: [VW7.4.1] SymbolicPaint hangs VM with infinite recursion



Does anybody know a safe rule of thumb for building up a consistent
color scheme using SymbolicPaint? It seems that even the slightest
modifications to the methods of
   
    LookPolicy>>installPlatformPreferencesFrom:on:  (in subclasses)

cause infinite recursion upon color lookup, which effectively hangs the
VM.

Where's the best place to trap this recursion? (and possibly break it up

by answering a default value). Unfortunately this is extremely hard to
debug, because the debugger window will - of course - also access the
paint hierarchy.

After hours of digging, it's getting frustrating. Any hint is
appreciated.

Andre


Reply | Threaded
Open this post in threaded view
|

Re: [VW7.4.1] SymbolicPaint hangs VM with infinite recursion

Andre Schnoor

[hidden email] wrote:
> Don't know if this will help.  I added the following to our system quite
> awhile ago to detect an infinite recursion.  Instead of the halt:, you
> could install a default paint.
>  
Thank you. This led me to a more detailed examination of the matter. I
understood that the hierarchy itself is static, i.e. initialized only
once. So checking the hierarchy at runtime doesn't make sense. Where the
actual recursion happens is with the assignments made in a
ColorPreferences dictionary dynamically.

Problems only occur when one SymbolicPaint is associated with another
SymbolicPaint that's already in its parent chain. I've seen this when
look policies decide to "customize" the LookPreferences of widgets on
the fly. This is especially the case with the WindowsXP look that
"patches" background colors during widget creation. Basically, I
discovered assignments of the form (example)

    aColorPreferences
        matchAt: SymbolicPaint background
        put: SymbolicPaint buttonBackground

The above message will create an infinite recursion, if there's no
physical Paint assigned to 'buttonBackground' yet, which would terminate
the recursive lookup. A simple solution would be to detect these illegal
assignments before they are made. I wrote the following code that
effectively eliminates the problem:

    Paint>>hasParent: aPaint
        "Physical paint is not in a hierarchy"
        ^false

    HierarchicalSymbolicPaint>>hasParent: aPaint
        "Answer true, if the argument is in the parent chain of the
receiver"
        ^parent = aPaint
            or:[ parent hasParent: aPaint ]

    Paint>>isLegalValueFor: aSymbolicPaint
        "Answer true, if the receiver may be mapped to the argument
         in a ChainedColorPreferences"
        ^true

    SymbolicPaint>>isLegalValueFor: aSymbolicPaint
        "Answer true, if the receiver may be mapped to the argument
         in a ChainedColorPreferences"
        ^self ~= aSymbolicPaint
            and:[ (self hasParent: aSymbolicPaint) not ]

    ChainedColorPreferences>>matchAt: aSymbolicPaint put: value
        "### OVERRIDE: Check if we are about to create an infinite cycle:"
        (value isLegalValueFor: aSymbolicPaint)
            ifFalse:[
                (self exactMatchAt: value ifAbsent: nil) isNil
                    ifTrue:[ ^aSymbolicPaint hierarchyCorruptedError:
value ]].
        node == nil ifTrue: [node := self allocateNode].
        node matchAt: aSymbolicPaint put: value.
        ^value

    SymbolicPaint>>hierarchyCorruptedError: aPaint
        "Issue a warning and answer a default paint"
        Transcript cr; show: ( 'ERROR: matchAt: <1s> put: <2s> is illegal'
            expandMacrosWith: self printString
            with: aPaint printString ).
        ^self class foreground

I haven't tested if the additional guard code affects performance in any
way, but it works like a charm. I would suggest using this utility in a
development environment only, or if actual problems occured.

Andre