Re: Bug with valueWithReceiver:arguments:

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

Re: Bug with valueWithReceiver:arguments:

Andreas.Raab
 
Hi Frederic -

Congrats! You found the first real VM bug in five years or so ;-) I'm
not completely sure what the problem is but there is obviously something
wrong here. It's easiest to recreate the problem by copying the #/
method and simply do something like:

SmallInteger>>foo: aNumber
        "(SmallInteger>>#foo:) valueWithReceiver: 11 arguments: {2}"
        <primitive: 10>
self halt.
        aNumber isZero ifTrue: [^(ZeroDivide dividend: self) signal].
        (aNumber isMemberOf: SmallInteger)
                ifTrue: [^(Fraction numerator: self denominator: aNumber) reduced]
                ifFalse: [^super / aNumber]

When you run this, you'll see that the debugger shows *two* frames with
SmallInteger>>foo: on them. Inspecting the "parent" frame will
eventually crash the system since it has a completely bogus stack
pointer (-1).

It seems that in a failing primitive method we end up with a bogus
activation record in primitiveExecMethodWithArgs (removing the primitive
from the above makes it work fine). I'm somewhat at a loss here as to
what the problem might be given that the implementations of
primPerformWithArgs and primExecWithArgs are so similar but
interestingly, the equivalent:

        11 perform: #foo: withArguments:{2}.

works fine with or without the primitive. Somewhere there must be a
difference ...

Cheers,
   - Andreas

Frederic Pluquet wrote:

> Hello,
>
> I found a fondamental bug in Squeak and Pharo. The next code
>
> 11 / 2
>
> gives the fraction (11/2). It's correct. But the next code
>
> (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
>
> gives 1 !
>
> The problem is the method valueWithReceiver:arguements: is used hugely
> with method wrappers...
>
> After long time of debugging, I found a point to debug: this method
> don't have the good behavior with compiled methods having a primitive
> that fails and executes some code after (as in SmallInteger>>#/ method
> when the division don't give a whole integer). In fact, when I send this
> message, the vm executes normally the compiled method but, in place of
> returns simply the good result, seems to rerun the the compiled method
> with other arguments (completly wrong) and returns so a wrong result.
>
> For example,
> (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
>
> has the following execution trace :
>
> 2 isZero
> |  2 = 0
> |  returns: false
> returns: false
> 2 isMemberOf: SmallInteger
> |  2 class
> |  returns: SmallInteger
> |  SmallInteger == SmallInteger
> |  returns: true
> returns: true
> Fraction numerator: 101 denominator: 2
> |  Fraction new
> |  |  Fraction basicNew
> |  |  returns: a Fraction instance
> |  |  (a Fraction instance) initialize
> |  |  returns: a Fraction instance
> |  returns: a Fraction instance
> |  a Fraction instance setNumerator: 101 denominator: 2
> |  |  2 = 0
> |  |  returns: false
> |  |  101 asInteger
> |  |  returns: 101
> |  |  2 asInteger
> |  |  returns: 2
> |  |  2 abs
> |  |  |  2 < 0
> |  |  |  returns: false
> |  |  returns: 2
> |  |  2 < 0
> |  |  returns: false
> |  returns: (101/2)
> returns: (101/2)
> (101/2) reduced
> |  101 = 0
> |  returns: false
> |  101 gcd: 2
> |  |  101 = 0
> |  |  returns: false
> |  |  2 \\ 101
> |  |  returns: 2
> |  |  2 = 0
> |  |  returns: false
> |  |  101 \\ 2
> |  |  returns: 1
> |  |  1 = 0
> |  |  returns: false
> |  |  2 \\ 1
> |  |  returns: 0
> |  |  0 = 0
> |  |  returns: true
> |  |  1 abs
> |  |  |  1 < 0
> |  |  |  returns: false
> |  |  returns: 1
> |  returns: 1
> |  101 // 1
> |  returns: 101
> |  2 // 1
> |  returns: 2
> |  2 = 1
> |  returns: false
> |  Fraction numerator: 101 denominator: 2
> |  |  Fraction new
> |  |  |  Fraction basicNew
> |  |  |  returns: a Fraction instance
> |  |  |  (a Fraction instance) initialize
> |  |  |  returns: a Fraction instance
> |  |  returns: a Fraction instance
> |  |  (a Fraction instance) setNumerator: 101 denominator: 2
> |  |  |  2 = 0
> |  |  |  returns: false
> |  |  |  101 asInteger
> |  |  |  returns: 101
> |  |  |  2 asInteger
> |  |  |  returns: 2
> |  |  |  2 abs
> |  |  |  |  2 < 0
> |  |  |  |  returns: false
> |  |  |  returns: 2
> |  |  |  2 < 0
> |  |  |  returns: false
> |  |  returns: (101/2)
> |  returns: (101/2)
> returns: (101/2)
> 2 isZero
> |  2 = 0
> |  returns: false
> returns: false
> false isMemberOf: SmallInteger
> |  false class
> |  returns: False
> |  False == SmallInteger
> |  returns: false
> returns: false
>
>
> Please help me to fix this bug. I really need it works fine !
>
> Fréd
> --
> Frédéric Pluquet
> Université Libre de Bruxelles (ULB)
> Assistant
> http://www.ulb.ac.be/di/fpluquet
>
>
> ------------------------------------------------------------------------
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Bug with valueWithReceiver:arguments:

Klaus D. Witzel
 
On Sun, 26 Oct 2008 13:39:04 +0100, Andreas Raab wrote:

> Hi Frederic -
>
> Congrats! You found the first real VM bug in five years or so ;-) I'm  
> not completely sure what the problem is but there is obviously something  
> wrong here. It's easiest to recreate the problem by copying the #/  
> method and simply do something like:
>
> SmallInteger>>foo: aNumber
> "(SmallInteger>>#foo:) valueWithReceiver: 11 arguments: {2}"
> <primitive: 10>
> self halt.
> aNumber isZero ifTrue: [^(ZeroDivide dividend: self) signal].
> (aNumber isMemberOf: SmallInteger)
> ifTrue: [^(Fraction numerator: self denominator: aNumber) reduced]
> ifFalse: [^super / aNumber]
>
> When you run this, you'll see that the debugger shows *two* frames with  
> SmallInteger>>foo: on them. Inspecting the "parent" frame will  
> eventually crash the system since it has a completely bogus stack  
> pointer (-1).
>
> It seems that in a failing primitive method we end up with a bogus  
> activation record in primitiveExecMethodWithArgs (removing the primitive  
> from the above makes it work fine). I'm somewhat at a loss here as to  
> what the problem might be given that the implementations of  
> primPerformWithArgs and primExecWithArgs are so similar but  
> interestingly, the equivalent:
>
> 11 perform: #foo: withArguments:{2}.
>
> works fine with or without the primitive. Somewhere there must be a  
> difference ...

The difference can be this: #primitiveExecuteMethod is called as part of  
#primitiveResponse, and in turn calls #executeNewMethod which again does  
#primitiveResponse. If the latter does #primitiveFail, the now *two*  
activations of #primitiveResponse want to handle the situation - without  
knowing from each other.

Perhaps #primitiveExecuteMethod should end with an explicit [ ... ^ self  
success: true] in its true-branch (this is just a thought, I have as yet  
not looked deeper).

Besides: if #primitiveExecuteMethod would do its own #primitiveFail, it  
looks like its arguments are no longer on the stack.

/Klaus

> Cheers,
>    - Andreas
>
> Frederic Pluquet wrote:
>> Hello,
>>  I found a fondamental bug in Squeak and Pharo. The next code
>>  11 / 2  gives the fraction (11/2). It's correct. But the next code
>>  (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
>>  gives 1 !
>>  The problem is the method valueWithReceiver:arguements: is used hugely  
>> with method wrappers...
>>  After long time of debugging, I found a point to debug: this method  
>> don't have the good behavior with compiled methods having a primitive  
>> that fails and executes some code after (as in SmallInteger>>#/ method  
>> when the division don't give a whole integer). In fact, when I send  
>> this message, the vm executes normally the compiled method but, in  
>> place of returns simply the good result, seems to rerun the the  
>> compiled method with other arguments (completly wrong) and returns so a  
>> wrong result.
>>  For example, (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
>>  has the following execution trace :
>>  2 isZero
>> |  2 = 0
>> |  returns: false
>> returns: false
>> 2 isMemberOf: SmallInteger
>> |  2 class
>> |  returns: SmallInteger
>> |  SmallInteger == SmallInteger
>> |  returns: true
>> returns: true
>> Fraction numerator: 101 denominator: 2
>> |  Fraction new
>> |  |  Fraction basicNew
>> |  |  returns: a Fraction instance
>> |  |  (a Fraction instance) initialize
>> |  |  returns: a Fraction instance
>> |  returns: a Fraction instance
>> |  a Fraction instance setNumerator: 101 denominator: 2
>> |  |  2 = 0
>> |  |  returns: false
>> |  |  101 asInteger
>> |  |  returns: 101
>> |  |  2 asInteger
>> |  |  returns: 2
>> |  |  2 abs
>> |  |  |  2 < 0
>> |  |  |  returns: false
>> |  |  returns: 2
>> |  |  2 < 0
>> |  |  returns: false
>> |  returns: (101/2)
>> returns: (101/2)
>> (101/2) reduced
>> |  101 = 0
>> |  returns: false
>> |  101 gcd: 2
>> |  |  101 = 0
>> |  |  returns: false
>> |  |  2 \\ 101
>> |  |  returns: 2
>> |  |  2 = 0
>> |  |  returns: false
>> |  |  101 \\ 2
>> |  |  returns: 1
>> |  |  1 = 0
>> |  |  returns: false
>> |  |  2 \\ 1
>> |  |  returns: 0
>> |  |  0 = 0
>> |  |  returns: true
>> |  |  1 abs
>> |  |  |  1 < 0
>> |  |  |  returns: false
>> |  |  returns: 1
>> |  returns: 1
>> |  101 // 1
>> |  returns: 101
>> |  2 // 1
>> |  returns: 2
>> |  2 = 1
>> |  returns: false
>> |  Fraction numerator: 101 denominator: 2
>> |  |  Fraction new
>> |  |  |  Fraction basicNew
>> |  |  |  returns: a Fraction instance
>> |  |  |  (a Fraction instance) initialize
>> |  |  |  returns: a Fraction instance
>> |  |  returns: a Fraction instance
>> |  |  (a Fraction instance) setNumerator: 101 denominator: 2
>> |  |  |  2 = 0
>> |  |  |  returns: false
>> |  |  |  101 asInteger
>> |  |  |  returns: 101
>> |  |  |  2 asInteger
>> |  |  |  returns: 2
>> |  |  |  2 abs
>> |  |  |  |  2 < 0
>> |  |  |  |  returns: false
>> |  |  |  returns: 2
>> |  |  |  2 < 0
>> |  |  |  returns: false
>> |  |  returns: (101/2)
>> |  returns: (101/2)
>> returns: (101/2)
>> 2 isZero
>> |  2 = 0
>> |  returns: false
>> returns: false
>> false isMemberOf: SmallInteger
>> |  false class
>> |  returns: False
>> |  False == SmallInteger
>> |  returns: false
>> returns: false
>>   Please help me to fix this bug. I really need it works fine !
>>  Fréd
>> -- Frédéric Pluquet
>> Université Libre de Bruxelles (ULB)
>> Assistant
>> http://www.ulb.ac.be/di/fpluquet
>>    
>> ------------------------------------------------------------------------
>>
>
>
>



--
“If at first, the idea is not absurd, then there is no hope for it”.  
Albert Einstein