Interesting Decompiler bug

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

Interesting Decompiler bug

Nicolas Cellier
See http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938

This bug was found by a newbie on pharo 1.1, but it's still there in 4.5 trunk image

Try to decompile this (no matter in which class)

< aNumberWithUnits
    (self compareUnits: aNumberWithUnits)
        ifTrue: [self value: ((aNumberWithUnits value) < (self value) ifTrue: [^true] ifFalse: [^false]).]
        ifFalse: [^Error new signal: 'Incompatible unit types.'].

Thanks to the newbie!
I would just have hated that!
Learning from one's own error is great, but from a dysfunctional system not so :(


Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

David T. Lewis
On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:

> See
> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>
> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
> trunk image
>
> Try to decompile this (no matter in which class)
>
> < aNumberWithUnits
>     (self compareUnits: aNumberWithUnits)
>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
> ifTrue: [^true] ifFalse: [^false]).]
>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>
> Thanks to the newbie!
> I would just have hated that!
> Learning from one's own error is great, but from a dysfunctional system not
> so :(

Good bug catch! Here is a reduced version of the method that produces the
same error when decompiled:


  Foo>>decompilerBug
      self value: (true
          ifTrue: [^ true]
          ifFalse: [^ false])

Dave


Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Frank Shearar-3
On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:

> On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>> See
>> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>>
>> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
>> trunk image
>>
>> Try to decompile this (no matter in which class)
>>
>> < aNumberWithUnits
>>     (self compareUnits: aNumberWithUnits)
>>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
>> ifTrue: [^true] ifFalse: [^false]).]
>>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>>
>> Thanks to the newbie!
>> I would just have hated that!
>> Learning from one's own error is great, but from a dysfunctional system not
>> so :(
>
> Good bug catch! Here is a reduced version of the method that produces the
> same error when decompiled:
>
>
>   Foo>>decompilerBug
>       self value: (true
>           ifTrue: [^ true]
>           ifFalse: [^ false])

I'm guessing that this is because

true
  ifTrue: [^ true]
  ifFalse: [^ false]

decompiles as

true ifTrue: [^ true]
^ false

?

I'm not terribly worried about claims of a "dysfunctional system".
This bug is so severe that noone has noticed it before! I agree that
we need to fix the bug, but the original code makes no sense in the
first place. #value: is unreachable.

frank

> Dave
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Nicolas Cellier
The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value on the stack (same as emitEffect: rather than emitValue:)
The decompiler wants to find the argument of self value: ... on the stack and it's not there.

So either we should forbid such construct at compile time
(emit an 'un-reachable code' error when emitValue: does not emit any value)

Or patch Decompiler like mad to work around...
(but Decompiler's methods are yet well below usual quality in term of complexity - long methods, many instance variables, incredibly complex state, ...)

I agree, this is going to be a rare problem only for newbies, because an experimented Smalltalker will avoid writing unreachable code.
So, the third solution is DO NOTHING, or more exactly add a test and an expected failure.
Like that we'll say next time, hey bad luck, this is a known limitation.

Nicolas



2013/6/20 Frank Shearar <[hidden email]>
On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
> On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>> See
>> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>>
>> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
>> trunk image
>>
>> Try to decompile this (no matter in which class)
>>
>> < aNumberWithUnits
>>     (self compareUnits: aNumberWithUnits)
>>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
>> ifTrue: [^true] ifFalse: [^false]).]
>>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>>
>> Thanks to the newbie!
>> I would just have hated that!
>> Learning from one's own error is great, but from a dysfunctional system not
>> so :(
>
> Good bug catch! Here is a reduced version of the method that produces the
> same error when decompiled:
>
>
>   Foo>>decompilerBug
>       self value: (true
>           ifTrue: [^ true]
>           ifFalse: [^ false])

I'm guessing that this is because

true
  ifTrue: [^ true]
  ifFalse: [^ false]

decompiles as

true ifTrue: [^ true]
^ false

?

I'm not terribly worried about claims of a "dysfunctional system".
This bug is so severe that noone has noticed it before! I agree that
we need to fix the bug, but the original code makes no sense in the
first place. #value: is unreachable.

frank

> Dave
>
>




Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Frank Shearar-3
On 20 June 2013 11:20, Nicolas Cellier
<[hidden email]> wrote:

> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value
> on the stack (same as emitEffect: rather than emitValue:)
> The decompiler wants to find the argument of self value: ... on the stack
> and it's not there.
>
> So either we should forbid such construct at compile time
> (emit an 'un-reachable code' error when emitValue: does not emit any value)
>
> Or patch Decompiler like mad to work around...
> (but Decompiler's methods are yet well below usual quality in term of
> complexity - long methods, many instance variables, incredibly complex
> state, ...)
>
> I agree, this is going to be a rare problem only for newbies, because an
> experimented Smalltalker will avoid writing unreachable code.
> So, the third solution is DO NOTHING, or more exactly add a test and an
> expected failure.
> Like that we'll say next time, hey bad luck, this is a known limitation.

Not great, mind you. Once Opal has settled down, maybe that's
something to look at porting. The problem is the tool integration: so
far, Pharo and Squeak haven't diverged much below the UI level, so at
least for now I wouldn't anticipate _huge_ pain in bringing over Opal.
But it's the mappings, and the Debugger, and interactions with the
Browsers and MessageSets and things where I'd expect to suffer.

frank

> Nicolas
>
>
>
> 2013/6/20 Frank Shearar <[hidden email]>
>>
>> On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
>> > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>> >> See
>> >>
>> >> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>> >>
>> >> This bug was found by a newbie on pharo 1.1, but it's still there in
>> >> 4.5
>> >> trunk image
>> >>
>> >> Try to decompile this (no matter in which class)
>> >>
>> >> < aNumberWithUnits
>> >>     (self compareUnits: aNumberWithUnits)
>> >>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
>> >> ifTrue: [^true] ifFalse: [^false]).]
>> >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>> >>
>> >> Thanks to the newbie!
>> >> I would just have hated that!
>> >> Learning from one's own error is great, but from a dysfunctional system
>> >> not
>> >> so :(
>> >
>> > Good bug catch! Here is a reduced version of the method that produces
>> > the
>> > same error when decompiled:
>> >
>> >
>> >   Foo>>decompilerBug
>> >       self value: (true
>> >           ifTrue: [^ true]
>> >           ifFalse: [^ false])
>>
>> I'm guessing that this is because
>>
>> true
>>   ifTrue: [^ true]
>>   ifFalse: [^ false]
>>
>> decompiles as
>>
>> true ifTrue: [^ true]
>> ^ false
>>
>> ?
>>
>> I'm not terribly worried about claims of a "dysfunctional system".
>> This bug is so severe that noone has noticed it before! I agree that
>> we need to fix the bug, but the original code makes no sense in the
>> first place. #value: is unreachable.
>>
>> frank
>>
>> > Dave
>> >
>> >
>>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

David T. Lewis
In reply to this post by Nicolas Cellier
On Thu, Jun 20, 2013 at 12:20:00PM +0200, Nicolas Cellier wrote:
> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value
> on the stack (same as emitEffect: rather than emitValue:)
> The decompiler wants to find the argument of self value: ... on the stack
> and it's not there.
>
> So either we should forbid such construct at compile time
> (emit an 'un-reachable code' error when emitValue: does not emit any value)

The original code example (before I reduced it to a trivial version)
was this:

    < aNumberWithUnits
        (self compareUnits: aNumberWithUnits)
            ifTrue: [self value: (aNumberWithUnits value < self value
                            ifTrue: [^ true]
                            ifFalse: [^ false])]
            ifFalse: [^ Error new signal: 'Incompatible unit types.']

This does not have the unreachable branch, and it displays the same
decompiler error.

Dave



>
> Or patch Decompiler like mad to work around...
> (but Decompiler's methods are yet well below usual quality in term of
> complexity - long methods, many instance variables, incredibly complex
> state, ...)
>
> I agree, this is going to be a rare problem only for newbies, because an
> experimented Smalltalker will avoid writing unreachable code.
> So, the third solution is DO NOTHING, or more exactly add a test and an
> expected failure.
> Like that we'll say next time, hey bad luck, this is a known limitation.
>
> Nicolas
>
>
>
> 2013/6/20 Frank Shearar <[hidden email]>
>
> > On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
> > > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
> > >> See
> > >>
> > http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
> > >>
> > >> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
> > >> trunk image
> > >>
> > >> Try to decompile this (no matter in which class)
> > >>
> > >> < aNumberWithUnits
> > >>     (self compareUnits: aNumberWithUnits)
> > >>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
> > >> ifTrue: [^true] ifFalse: [^false]).]
> > >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
> > >>
> > >> Thanks to the newbie!
> > >> I would just have hated that!
> > >> Learning from one's own error is great, but from a dysfunctional system
> > not
> > >> so :(
> > >
> > > Good bug catch! Here is a reduced version of the method that produces the
> > > same error when decompiled:
> > >
> > >
> > >   Foo>>decompilerBug
> > >       self value: (true
> > >           ifTrue: [^ true]
> > >           ifFalse: [^ false])
> >
> > I'm guessing that this is because
> >
> > true
> >   ifTrue: [^ true]
> >   ifFalse: [^ false]
> >
> > decompiles as
> >
> > true ifTrue: [^ true]
> > ^ false
> >
> > ?
> >
> > I'm not terribly worried about claims of a "dysfunctional system".
> > This bug is so severe that noone has noticed it before! I agree that
> > we need to fix the bug, but the original code makes no sense in the
> > first place. #value: is unreachable.
> >
> > frank
> >
> > > Dave
> > >
> > >
> >
> >

>


Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Frank Shearar-3
On 20 June 2013 12:58, David T. Lewis <[hidden email]> wrote:

> On Thu, Jun 20, 2013 at 12:20:00PM +0200, Nicolas Cellier wrote:
>> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value
>> on the stack (same as emitEffect: rather than emitValue:)
>> The decompiler wants to find the argument of self value: ... on the stack
>> and it's not there.
>>
>> So either we should forbid such construct at compile time
>> (emit an 'un-reachable code' error when emitValue: does not emit any value)
>
> The original code example (before I reduced it to a trivial version)
> was this:
>
>     < aNumberWithUnits
>         (self compareUnits: aNumberWithUnits)
>             ifTrue: [self value: (aNumberWithUnits value < self value
>                             ifTrue: [^ true]
>                             ifFalse: [^ false])]
>             ifFalse: [^ Error new signal: 'Incompatible unit types.']
>
> This does not have the unreachable branch, and it displays the same
> decompiler error.

The #value: send to self is unreachable because both of the inner
#ifTrue:ifFalse: blocks force a return.

frank

> Dave
>
>
>
>>
>> Or patch Decompiler like mad to work around...
>> (but Decompiler's methods are yet well below usual quality in term of
>> complexity - long methods, many instance variables, incredibly complex
>> state, ...)
>>
>> I agree, this is going to be a rare problem only for newbies, because an
>> experimented Smalltalker will avoid writing unreachable code.
>> So, the third solution is DO NOTHING, or more exactly add a test and an
>> expected failure.
>> Like that we'll say next time, hey bad luck, this is a known limitation.
>>
>> Nicolas
>>
>>
>>
>> 2013/6/20 Frank Shearar <[hidden email]>
>>
>> > On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
>> > > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>> > >> See
>> > >>
>> > http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>> > >>
>> > >> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
>> > >> trunk image
>> > >>
>> > >> Try to decompile this (no matter in which class)
>> > >>
>> > >> < aNumberWithUnits
>> > >>     (self compareUnits: aNumberWithUnits)
>> > >>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
>> > >> ifTrue: [^true] ifFalse: [^false]).]
>> > >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>> > >>
>> > >> Thanks to the newbie!
>> > >> I would just have hated that!
>> > >> Learning from one's own error is great, but from a dysfunctional system
>> > not
>> > >> so :(
>> > >
>> > > Good bug catch! Here is a reduced version of the method that produces the
>> > > same error when decompiled:
>> > >
>> > >
>> > >   Foo>>decompilerBug
>> > >       self value: (true
>> > >           ifTrue: [^ true]
>> > >           ifFalse: [^ false])
>> >
>> > I'm guessing that this is because
>> >
>> > true
>> >   ifTrue: [^ true]
>> >   ifFalse: [^ false]
>> >
>> > decompiles as
>> >
>> > true ifTrue: [^ true]
>> > ^ false
>> >
>> > ?
>> >
>> > I'm not terribly worried about claims of a "dysfunctional system".
>> > This bug is so severe that noone has noticed it before! I agree that
>> > we need to fix the bug, but the original code makes no sense in the
>> > first place. #value: is unreachable.
>> >
>> > frank
>> >
>> > > Dave
>> > >
>> > >
>> >
>> >
>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

David T. Lewis
On Thu, Jun 20, 2013 at 01:04:00PM +0100, Frank Shearar wrote:

> On 20 June 2013 12:58, David T. Lewis <[hidden email]> wrote:
> > On Thu, Jun 20, 2013 at 12:20:00PM +0200, Nicolas Cellier wrote:
> >> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value
> >> on the stack (same as emitEffect: rather than emitValue:)
> >> The decompiler wants to find the argument of self value: ... on the stack
> >> and it's not there.
> >>
> >> So either we should forbid such construct at compile time
> >> (emit an 'un-reachable code' error when emitValue: does not emit any value)
> >
> > The original code example (before I reduced it to a trivial version)
> > was this:
> >
> >     < aNumberWithUnits
> >         (self compareUnits: aNumberWithUnits)
> >             ifTrue: [self value: (aNumberWithUnits value < self value
> >                             ifTrue: [^ true]
> >                             ifFalse: [^ false])]
> >             ifFalse: [^ Error new signal: 'Incompatible unit types.']
> >
> > This does not have the unreachable branch, and it displays the same
> > decompiler error.
>
> The #value: send to self is unreachable because both of the inner
> #ifTrue:ifFalse: blocks force a return.
>

D'oh! Now I see it. Thanks.

Dave


Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Levente Uzonyi-2
In reply to this post by Nicolas Cellier
On Thu, 20 Jun 2013, Nicolas Cellier wrote:

> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any value on the stack (same as emitEffect: rather than emitValue:)
> The decompiler wants to find the argument of self value: ... on the stack and it's not there.
>
> So either we should forbid such construct at compile time
> (emit an 'un-reachable code' error when emitValue: does not emit any value)

I think this is the right thing to do, but the problem is a bit more
complex.

The following doesn't break the decompier, but it won't be decompiled
correctly, because the decompiler avoids creating branches:

decompilerBug2

  true ifTrue: [ ^1 ] ifFalse: [ ^1 ].
  ^2

The decompiler will produce this:

decompilerBug2
  true
  ifTrue: [^ 1].
  ^ 1.
  ^ 2

Which can't be compiled anymore.


The original bug also appears with #caseOf:otherwise: :

decompilerBug3

  self foo: (
  true
  caseOf: { [ false ] -> [ ^1 ] }
  otherwise: [ ^1 ])

#caseOf: :

decompilerBug4

  self foo: (true caseOf: { [ false ] -> [  ^1 ] })

and #repeat :

decompilerBug5

  self foo: [ ^self ] repeat


Levente

>
> Or patch Decompiler like mad to work around...
> (but Decompiler's methods are yet well below usual quality in term of complexity - long methods, many instance variables, incredibly complex state, ...)
>
> I agree, this is going to be a rare problem only for newbies, because an experimented Smalltalker will avoid writing unreachable code.
> So, the third solution is DO NOTHING, or more exactly add a test and an expected failure.
> Like that we'll say next time, hey bad luck, this is a known limitation.
>
> Nicolas
>
>
>
> 2013/6/20 Frank Shearar <[hidden email]>
>       On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
>       > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>       >> See
>       >> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>       >>
>       >> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
>       >> trunk image
>       >>
>       >> Try to decompile this (no matter in which class)
>       >>
>       >> < aNumberWithUnits
>       >>     (self compareUnits: aNumberWithUnits)
>       >>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
>       >> ifTrue: [^true] ifFalse: [^false]).]
>       >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>       >>
>       >> Thanks to the newbie!
>       >> I would just have hated that!
>       >> Learning from one's own error is great, but from a dysfunctional system not
>       >> so :(
>       >
>       > Good bug catch! Here is a reduced version of the method that produces the
>       > same error when decompiled:
>       >
>       >
>       >   Foo>>decompilerBug
>       >       self value: (true
>       >           ifTrue: [^ true]
>       >           ifFalse: [^ false])
>
> I'm guessing that this is because
>
> true
>   ifTrue: [^ true]
>   ifFalse: [^ false]
>
> decompiles as
>
> true ifTrue: [^ true]
> ^ false
>
> ?
>
> I'm not terribly worried about claims of a "dysfunctional system".
> This bug is so severe that noone has noticed it before! I agree that
> we need to fix the bug, but the original code makes no sense in the
> first place. #value: is unreachable.
>
> frank
>
> > Dave
> >
> >
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Frank Shearar-3
On 20 June 2013 15:09, Levente Uzonyi <[hidden email]> wrote:

> On Thu, 20 Jun 2013, Nicolas Cellier wrote:
>
>> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any
>> value on the stack (same as emitEffect: rather than emitValue:)
>> The decompiler wants to find the argument of self value: ... on the stack
>> and it's not there.
>>
>> So either we should forbid such construct at compile time
>> (emit an 'un-reachable code' error when emitValue: does not emit any
>> value)
>
>
> I think this is the right thing to do, but the problem is a bit more
> complex.
>
> The following doesn't break the decompier, but it won't be decompiled
> correctly, because the decompiler avoids creating branches:
>
> decompilerBug2
>
>         true ifTrue: [ ^1 ] ifFalse: [ ^1 ].
>         ^2

This is what I was talking about. The Compiler inlines
#ifTrue:ifFalse: and produces bytecodes that, when decompiled, don't
match the original source.

frank

> The decompiler will produce this:
>
> decompilerBug2
>         true
>                 ifTrue: [^ 1].
>         ^ 1.
>         ^ 2
>
> Which can't be compiled anymore.
>
>
> The original bug also appears with #caseOf:otherwise: :
>
> decompilerBug3
>
>         self foo: (
>                 true
>                         caseOf: { [ false ] -> [ ^1 ] }
>                         otherwise: [ ^1 ])
>
> #caseOf: :
>
> decompilerBug4
>
>         self foo: (true caseOf: { [ false ] -> [  ^1 ] })
>
> and #repeat :
>
> decompilerBug5
>
>         self foo: [ ^self ] repeat
>
>
> Levente
>
>
>>
>> Or patch Decompiler like mad to work around...
>> (but Decompiler's methods are yet well below usual quality in term of
>> complexity - long methods, many instance variables, incredibly complex
>> state, ...)
>>
>> I agree, this is going to be a rare problem only for newbies, because an
>> experimented Smalltalker will avoid writing unreachable code.
>> So, the third solution is DO NOTHING, or more exactly add a test and an
>> expected failure.
>> Like that we'll say next time, hey bad luck, this is a known limitation.
>>
>> Nicolas
>>
>>
>>
>> 2013/6/20 Frank Shearar <[hidden email]>
>>       On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
>>       > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>>       >> See
>>       >>
>> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>>       >>
>>       >> This bug was found by a newbie on pharo 1.1, but it's still there
>> in 4.5
>>       >> trunk image
>>       >>
>>       >> Try to decompile this (no matter in which class)
>>       >>
>>       >> < aNumberWithUnits
>>       >>     (self compareUnits: aNumberWithUnits)
>>       >>         ifTrue: [self value: ((aNumberWithUnits value) < (self
>> value)
>>       >> ifTrue: [^true] ifFalse: [^false]).]
>>       >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>>       >>
>>       >> Thanks to the newbie!
>>       >> I would just have hated that!
>>       >> Learning from one's own error is great, but from a dysfunctional
>> system not
>>       >> so :(
>>       >
>>       > Good bug catch! Here is a reduced version of the method that
>> produces the
>>       > same error when decompiled:
>>       >
>>       >
>>       >   Foo>>decompilerBug
>>       >       self value: (true
>>       >           ifTrue: [^ true]
>>       >           ifFalse: [^ false])
>>
>> I'm guessing that this is because
>>
>> true
>>   ifTrue: [^ true]
>>   ifFalse: [^ false]
>>
>> decompiles as
>>
>> true ifTrue: [^ true]
>> ^ false
>>
>> ?
>>
>> I'm not terribly worried about claims of a "dysfunctional system".
>> This bug is so severe that noone has noticed it before! I agree that
>> we need to fix the bug, but the original code makes no sense in the
>> first place. #value: is unreachable.
>>
>> frank
>>
>> > Dave
>> >
>> >
>>
>>
>>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

Levente Uzonyi-2
On Thu, 20 Jun 2013, Frank Shearar wrote:

> On 20 June 2013 15:09, Levente Uzonyi <[hidden email]> wrote:
>> On Thu, 20 Jun 2013, Nicolas Cellier wrote:
>>
>>> The bug is that (true ifTrue:[^true] ifFalse:[^false]) won't push any
>>> value on the stack (same as emitEffect: rather than emitValue:)
>>> The decompiler wants to find the argument of self value: ... on the stack
>>> and it's not there.
>>>
>>> So either we should forbid such construct at compile time
>>> (emit an 'un-reachable code' error when emitValue: does not emit any
>>> value)
>>
>>
>> I think this is the right thing to do, but the problem is a bit more
>> complex.
>>
>> The following doesn't break the decompier, but it won't be decompiled
>> correctly, because the decompiler avoids creating branches:
>>
>> decompilerBug2
>>
>>         true ifTrue: [ ^1 ] ifFalse: [ ^1 ].
>>         ^2
>
> This is what I was talking about. The Compiler inlines
> #ifTrue:ifFalse: and produces bytecodes that, when decompiled, don't
> match the original source.

That's because for both

  true ifTrue: [ ^1 ] ifFalse: [ ^1 ]

and

  true ifTrue: [ ^1 ].
  ^1

the compiler will generate the same bytecode sequence:

17 <71> pushConstant: true
18 <99> jumpFalse: 21
19 <76> pushConstant: 1
20 <7C> returnTop
21 <76> pushConstant: 1
22 <7C> returnTop

The only way this could be "fixed" is to add some extra markers
(e.g. bytecodes or some trailer data) to help the decompiler decide which
construct was used in the original source code. But that's just a waste of
resources most of the time.


Levente

>
> frank
>
>> The decompiler will produce this:
>>
>> decompilerBug2
>>         true
>>                 ifTrue: [^ 1].
>>         ^ 1.
>>         ^ 2
>>
>> Which can't be compiled anymore.
>>
>>
>> The original bug also appears with #caseOf:otherwise: :
>>
>> decompilerBug3
>>
>>         self foo: (
>>                 true
>>                         caseOf: { [ false ] -> [ ^1 ] }
>>                         otherwise: [ ^1 ])
>>
>> #caseOf: :
>>
>> decompilerBug4
>>
>>         self foo: (true caseOf: { [ false ] -> [  ^1 ] })
>>
>> and #repeat :
>>
>> decompilerBug5
>>
>>         self foo: [ ^self ] repeat
>>
>>
>> Levente
>>
>>
>>>
>>> Or patch Decompiler like mad to work around...
>>> (but Decompiler's methods are yet well below usual quality in term of
>>> complexity - long methods, many instance variables, incredibly complex
>>> state, ...)
>>>
>>> I agree, this is going to be a rare problem only for newbies, because an
>>> experimented Smalltalker will avoid writing unreachable code.
>>> So, the third solution is DO NOTHING, or more exactly add a test and an
>>> expected failure.
>>> Like that we'll say next time, hey bad luck, this is a known limitation.
>>>
>>> Nicolas
>>>
>>>
>>>
>>> 2013/6/20 Frank Shearar <[hidden email]>
>>>       On 20 June 2013 02:12, David T. Lewis <[hidden email]> wrote:
>>>      > On Thu, Jun 20, 2013 at 01:26:14AM +0200, Nicolas Cellier wrote:
>>>      >> See
>>>      >>
>>> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>>>      >>
>>>      >> This bug was found by a newbie on pharo 1.1, but it's still there
>>> in 4.5
>>>      >> trunk image
>>>      >>
>>>      >> Try to decompile this (no matter in which class)
>>>      >>
>>>      >> < aNumberWithUnits
>>>      >>     (self compareUnits: aNumberWithUnits)
>>>      >>         ifTrue: [self value: ((aNumberWithUnits value) < (self
>>> value)
>>>      >> ifTrue: [^true] ifFalse: [^false]).]
>>>      >>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>>>      >>
>>>      >> Thanks to the newbie!
>>>      >> I would just have hated that!
>>>      >> Learning from one's own error is great, but from a dysfunctional
>>> system not
>>>      >> so :(
>>>      >
>>>      > Good bug catch! Here is a reduced version of the method that
>>> produces the
>>>      > same error when decompiled:
>>>      >
>>>      >
>>>      >   Foo>>decompilerBug
>>>      >       self value: (true
>>>      >           ifTrue: [^ true]
>>>      >           ifFalse: [^ false])
>>>
>>> I'm guessing that this is because
>>>
>>> true
>>>   ifTrue: [^ true]
>>>   ifFalse: [^ false]
>>>
>>> decompiles as
>>>
>>> true ifTrue: [^ true]
>>> ^ false
>>>
>>> ?
>>>
>>> I'm not terribly worried about claims of a "dysfunctional system".
>>> This bug is so severe that noone has noticed it before! I agree that
>>> we need to fix the bug, but the original code makes no sense in the
>>> first place. #value: is unreachable.
>>>
>>> frank
>>>
>>>> Dave
>>>>
>>>>
>>>
>>>
>>>
>>
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interesting Decompiler bug

mokurai
In reply to this post by Nicolas Cellier
I am in the process of filing dozens of Squeak bugs that I found while
researching the Etoys Reference Manual, and making notes on them in the
Squeak interface section of the manual.

http://booki.flossmanuals.net/etoys-reference-manual-vol-ii/_edit/

On Wed, June 19, 2013 7:26 pm, Nicolas Cellier wrote:

> See
> http://stackoverflow.com/questions/17129583/smalltalk-collection-is-empty-error-when-saving/17202938#17202938
>
> This bug was found by a newbie on pharo 1.1, but it's still there in 4.5
> trunk image
>
> Try to decompile this (no matter in which class)
>
> < aNumberWithUnits
>     (self compareUnits: aNumberWithUnits)
>         ifTrue: [self value: ((aNumberWithUnits value) < (self value)
> ifTrue: [^true] ifFalse: [^false]).]
>         ifFalse: [^Error new signal: 'Incompatible unit types.'].
>
> Thanks to the newbie!
> I would just have hated that!
> Learning from one's own error is great, but from a dysfunctional system
> not
> so :(
>
>


--
Edward Mokurai
(&#40664;&#38647;/&#2344;&#2367;&#2358;&#2348;&#2381;&#2342;&#2327;&#2352;&#2381;&#2332;/&#1606;&#1588;&#1576;&#1583;&#1711;&#1585;&#1580;)
Cherlin
Silent Thunder is my name, and Children are my nation.
The Cosmos is my dwelling place, the Truth my destination.
http://wiki.sugarlabs.org/go/Replacing_Textbooks