pharo-contributions / MethodProxies

A library to decorate and control method execution.
6 stars 7 forks source link

Infinite recursion bug when allocating Strings #18

Closed jordanmontt closed 3 months ago

jordanmontt commented 8 months ago

When one installs a proxy allocator methods (see below) and when one uses String streamContents: [:s | ] and a asString; the image enters to an infinite recursion of allocations.

To reproduce

First, create a simple Handler class:

MpHandler >> #MyHandler 

and add a beforeMethod that get asString of any object.

beforeMethod
    String streamContents: [ :stream | stream << OrderedCollection new asString ]

Now, if you run this script on a Playground (or a test, doesn't matter), the image will be frozen.

aHandler := MyHandler new.

"Proxy some allocator methods"
proxyA := MpMethodProxy onMethod: Behavior >> #basicNew handler: aHandler.
proxyB := MpMethodProxy onMethod: Behavior >> #basicNew: handler: aHandler.

proxyA install.
proxyB install.

"Make an allocation"
Object new.

proxyA uninstall.
proxyB uninstall.

This is because we end up doing infinite allocations because of a recursion.

This problem does not occur when proxing the same allocator methods but allocating anything else, but no a String. For example, if we have our before method like this.

beforeMethod
    OrderedCollection new.
        Array new.
        Set new.

No recursion happens. So, the issue happens to be related to the String streamContents: [ ] and with asString: related to the String allocation.

Other findings

if one puts in the before method

beforeMethod
    String new.

The behavior is uncertain. Sometimes it hags the image, and sometimes don't.

Ducasse commented 8 months ago

Thanks. I do not get why we have this behavior because I thought that we handled the meta recursion.

jordanmontt commented 8 months ago

Yes, indeed. The weirdest is that only happens with Strings. With other allocations, the meta recursion is handled as expected.

jordanmontt commented 3 months ago

Fixed!