Deep Recursion break/protection

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

Deep Recursion break/protection

Esteban A. Maringolo
Hi,

Is there a way to add deep recursion protection to the system?

eg.
RecursiveObject>>#recurse
  self recurse

So calling `RecursiveObject new recurse` in Dolphin raises an
exception right away...

Throws the following error with this stack:
ProcessorScheduler>>stackOverflow:
[] in ProcessorScheduler>>vmi:list:no:with:
BlockClosure>>ifCurtailed:
ProcessorScheduler>>vmi:list:no:with:
RecursiveObject>>recurse
RecursiveObject>>recurse

In Pharo it goes forever until it hits the memory limit (3.6GiB), at
which point doing an Alt+. is useless and you have to kill the VM.

The example is pretty simple, but when doing Seaside rendering, it is
easy to miss some return, causing the receiver to render recursively,
turning your image useless.

e.g.
MyComponent>>renderContentOn: html
  html render: self someSubComponent

MyComponent>>someSubComponent
  "Here I forget returning the subcomponent"
  someSubComponent ifNil: [someSubcomponent := OtherComponent new].

When you render MyComponent... boom, because
#MyComponent>>#renderContentOn: will be called recursively.

Regards,

Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Esteban A. Maringolo
I just checked in VisualWorks, where I also develop Seaside and also
make these mistakes, and these recursions launch a "Process Monitor
Emergency: No space left" process monitor, with the option of killing
any running Smalltalk process.

Regards,

Esteban A. Maringolo

On Thu, Apr 25, 2019 at 9:30 AM Esteban Maringolo <[hidden email]> wrote:

>
> Hi,
>
> Is there a way to add deep recursion protection to the system?
>
> eg.
> RecursiveObject>>#recurse
>   self recurse
>
> So calling `RecursiveObject new recurse` in Dolphin raises an
> exception right away...
>
> Throws the following error with this stack:
> ProcessorScheduler>>stackOverflow:
> [] in ProcessorScheduler>>vmi:list:no:with:
> BlockClosure>>ifCurtailed:
> ProcessorScheduler>>vmi:list:no:with:
> RecursiveObject>>recurse
> RecursiveObject>>recurse
>
> In Pharo it goes forever until it hits the memory limit (3.6GiB), at
> which point doing an Alt+. is useless and you have to kill the VM.
>
> The example is pretty simple, but when doing Seaside rendering, it is
> easy to miss some return, causing the receiver to render recursively,
> turning your image useless.
>
> e.g.
> MyComponent>>renderContentOn: html
>   html render: self someSubComponent
>
> MyComponent>>someSubComponent
>   "Here I forget returning the subcomponent"
>   someSubComponent ifNil: [someSubcomponent := OtherComponent new].
>
> When you render MyComponent... boom, because
> #MyComponent>>#renderContentOn: will be called recursively.
>
> Regards,
>
> Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Sven Van Caekenberghe-2
We also have an OutOfMemory exception, we even have tests provoking such a situation (check usage).

However, I believe such tight loops end up in JIT machine code.

Checking stack overflow on each stack manipulation is costly.

But I totally agree that we should try to catch these situations even if there is a cost.

> On 25 Apr 2019, at 14:39, Esteban Maringolo <[hidden email]> wrote:
>
> I just checked in VisualWorks, where I also develop Seaside and also
> make these mistakes, and these recursions launch a "Process Monitor
> Emergency: No space left" process monitor, with the option of killing
> any running Smalltalk process.
>
> Regards,
>
> Esteban A. Maringolo
>
> On Thu, Apr 25, 2019 at 9:30 AM Esteban Maringolo <[hidden email]> wrote:
>>
>> Hi,
>>
>> Is there a way to add deep recursion protection to the system?
>>
>> eg.
>> RecursiveObject>>#recurse
>>  self recurse
>>
>> So calling `RecursiveObject new recurse` in Dolphin raises an
>> exception right away...
>>
>> Throws the following error with this stack:
>> ProcessorScheduler>>stackOverflow:
>> [] in ProcessorScheduler>>vmi:list:no:with:
>> BlockClosure>>ifCurtailed:
>> ProcessorScheduler>>vmi:list:no:with:
>> RecursiveObject>>recurse
>> RecursiveObject>>recurse
>>
>> In Pharo it goes forever until it hits the memory limit (3.6GiB), at
>> which point doing an Alt+. is useless and you have to kill the VM.
>>
>> The example is pretty simple, but when doing Seaside rendering, it is
>> easy to miss some return, causing the receiver to render recursively,
>> turning your image useless.
>>
>> e.g.
>> MyComponent>>renderContentOn: html
>>  html render: self someSubComponent
>>
>> MyComponent>>someSubComponent
>>  "Here I forget returning the subcomponent"
>>  someSubComponent ifNil: [someSubcomponent := OtherComponent new].
>>
>> When you render MyComponent... boom, because
>> #MyComponent>>#renderContentOn: will be called recursively.
>>
>> Regards,
>>
>> Esteban A. Maringolo
>


Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Esteban A. Maringolo
I downloaded a fresh 7.0.3 image and VM, created the above class and
method, and called it.

The image is running in Ubuntu within a VirtualBox with 4GB RAM.

Such exception was not triggered in my image when it actually filled
all the available OS RAM, and I had to kill it using the operative
system process manager.

If I call it and press Alt+. right away it halts the execution (if
running on the main thread).
In Dolphin, because it is not JITted, it is instantaneous after a long
chain of calls.

Crashing the image by such a simple to make mistake should be avoided.
Fortunately we have other tools such as Epicea to recover changes, but
even still.


Regards,

Esteban A. Maringolo

On Thu, Apr 25, 2019 at 9:47 AM Sven Van Caekenberghe <[hidden email]> wrote:

>
> We also have an OutOfMemory exception, we even have tests provoking such a situation (check usage).
>
> However, I believe such tight loops end up in JIT machine code.
>
> Checking stack overflow on each stack manipulation is costly.
>
> But I totally agree that we should try to catch these situations even if there is a cost.
>
> > On 25 Apr 2019, at 14:39, Esteban Maringolo <[hidden email]> wrote:
> >
> > I just checked in VisualWorks, where I also develop Seaside and also
> > make these mistakes, and these recursions launch a "Process Monitor
> > Emergency: No space left" process monitor, with the option of killing
> > any running Smalltalk process.
> >
> > Regards,
> >
> > Esteban A. Maringolo
> >
> > On Thu, Apr 25, 2019 at 9:30 AM Esteban Maringolo <[hidden email]> wrote:
> >>
> >> Hi,
> >>
> >> Is there a way to add deep recursion protection to the system?
> >>
> >> eg.
> >> RecursiveObject>>#recurse
> >>  self recurse
> >>
> >> So calling `RecursiveObject new recurse` in Dolphin raises an
> >> exception right away...
> >>
> >> Throws the following error with this stack:
> >> ProcessorScheduler>>stackOverflow:
> >> [] in ProcessorScheduler>>vmi:list:no:with:
> >> BlockClosure>>ifCurtailed:
> >> ProcessorScheduler>>vmi:list:no:with:
> >> RecursiveObject>>recurse
> >> RecursiveObject>>recurse
> >>
> >> In Pharo it goes forever until it hits the memory limit (3.6GiB), at
> >> which point doing an Alt+. is useless and you have to kill the VM.
> >>
> >> The example is pretty simple, but when doing Seaside rendering, it is
> >> easy to miss some return, causing the receiver to render recursively,
> >> turning your image useless.
> >>
> >> e.g.
> >> MyComponent>>renderContentOn: html
> >>  html render: self someSubComponent
> >>
> >> MyComponent>>someSubComponent
> >>  "Here I forget returning the subcomponent"
> >>  someSubComponent ifNil: [someSubcomponent := OtherComponent new].
> >>
> >> When you render MyComponent... boom, because
> >> #MyComponent>>#renderContentOn: will be called recursively.
> >>
> >> Regards,
> >>
> >> Esteban A. Maringolo
> >
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Sven Van Caekenberghe-2
What if you did something like:

RecursiveObject>>#recurse
 | data |
 data := Array new: 1e5.
 self recurse.
 ^ data

This way, you should run out of heap before the stack gets too large, since you allocate and hold on to an array in each frame.

> On 25 Apr 2019, at 14:56, Esteban Maringolo <[hidden email]> wrote:
>
> I downloaded a fresh 7.0.3 image and VM, created the above class and
> method, and called it.
>
> The image is running in Ubuntu within a VirtualBox with 4GB RAM.
>
> Such exception was not triggered in my image when it actually filled
> all the available OS RAM, and I had to kill it using the operative
> system process manager.
>
> If I call it and press Alt+. right away it halts the execution (if
> running on the main thread).
> In Dolphin, because it is not JITted, it is instantaneous after a long
> chain of calls.
>
> Crashing the image by such a simple to make mistake should be avoided.
> Fortunately we have other tools such as Epicea to recover changes, but
> even still.
>
>
> Regards,
>
> Esteban A. Maringolo
>
> On Thu, Apr 25, 2019 at 9:47 AM Sven Van Caekenberghe <[hidden email]> wrote:
>>
>> We also have an OutOfMemory exception, we even have tests provoking such a situation (check usage).
>>
>> However, I believe such tight loops end up in JIT machine code.
>>
>> Checking stack overflow on each stack manipulation is costly.
>>
>> But I totally agree that we should try to catch these situations even if there is a cost.
>>
>>> On 25 Apr 2019, at 14:39, Esteban Maringolo <[hidden email]> wrote:
>>>
>>> I just checked in VisualWorks, where I also develop Seaside and also
>>> make these mistakes, and these recursions launch a "Process Monitor
>>> Emergency: No space left" process monitor, with the option of killing
>>> any running Smalltalk process.
>>>
>>> Regards,
>>>
>>> Esteban A. Maringolo
>>>
>>> On Thu, Apr 25, 2019 at 9:30 AM Esteban Maringolo <[hidden email]> wrote:
>>>>
>>>> Hi,
>>>>
>>>> Is there a way to add deep recursion protection to the system?
>>>>
>>>> eg.
>>>> RecursiveObject>>#recurse
>>>> self recurse
>>>>
>>>> So calling `RecursiveObject new recurse` in Dolphin raises an
>>>> exception right away...
>>>>
>>>> Throws the following error with this stack:
>>>> ProcessorScheduler>>stackOverflow:
>>>> [] in ProcessorScheduler>>vmi:list:no:with:
>>>> BlockClosure>>ifCurtailed:
>>>> ProcessorScheduler>>vmi:list:no:with:
>>>> RecursiveObject>>recurse
>>>> RecursiveObject>>recurse
>>>>
>>>> In Pharo it goes forever until it hits the memory limit (3.6GiB), at
>>>> which point doing an Alt+. is useless and you have to kill the VM.
>>>>
>>>> The example is pretty simple, but when doing Seaside rendering, it is
>>>> easy to miss some return, causing the receiver to render recursively,
>>>> turning your image useless.
>>>>
>>>> e.g.
>>>> MyComponent>>renderContentOn: html
>>>> html render: self someSubComponent
>>>>
>>>> MyComponent>>someSubComponent
>>>> "Here I forget returning the subcomponent"
>>>> someSubComponent ifNil: [someSubcomponent := OtherComponent new].
>>>>
>>>> When you render MyComponent... boom, because
>>>> #MyComponent>>#renderContentOn: will be called recursively.
>>>>
>>>> Regards,
>>>>
>>>> Esteban A. Maringolo
>>>
>>
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Esteban A. Maringolo
Hi Sven,

On Thu, Apr 25, 2019 at 10:04 AM Sven Van Caekenberghe <[hidden email]> wrote:
> This way, you should run out of heap before the stack gets too large, since you allocate and hold on to an array in each frame.

I don't understand the purpose of such expression, since I'm not
writing recursive code, where I pay special attention or save the
image before running it, but I'm trying to find a way around
accidental deep recursions.

However I ran these examples in Dolphin and Pharo 7, and in Dolphin it
triggers an memory exhaustion exception right away, and in Pharo it
grows in memory use, slower than with the previous example, but with
the same behavior (unresponsive image once the memory fills the
available OS memory).

Regards,

Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Sven Van Caekenberghe-2


> On 25 Apr 2019, at 15:27, Esteban Maringolo <[hidden email]> wrote:
>
> Hi Sven,
>
> On Thu, Apr 25, 2019 at 10:04 AM Sven Van Caekenberghe <[hidden email]> wrote:
>> This way, you should run out of heap before the stack gets too large, since you allocate and hold on to an array in each frame.
>
> I don't understand the purpose of such expression, since I'm not
> writing recursive code, where I pay special attention or save the
> image before running it, but I'm trying to find a way around
> accidental deep recursions.

I know, it was an experiment.

> However I ran these examples in Dolphin and Pharo 7, and in Dolphin it
> triggers an memory exhaustion exception right away, and in Pharo it
> grows in memory use, slower than with the previous example, but with
> the same behavior (unresponsive image once the memory fills the
> available OS memory).

Too bad, this is a VM issue anyway.

> Regards,
>
> Esteban A. Maringolo
>


Reply | Threaded
Open this post in threaded view
|

Re: Deep Recursion break/protection

Esteban A. Maringolo
On Thu, Apr 25, 2019 at 10:41 AM Sven Van Caekenberghe <[hidden email]> wrote:
> > On 25 Apr 2019, at 15:27, Esteban Maringolo <[hidden email]> wrote:

> > However I ran these examples in Dolphin and Pharo 7, and in Dolphin it
> > triggers an memory exhaustion exception right away, and in Pharo it
> > grows in memory use, slower than with the previous example, but with
> > the same behavior (unresponsive image once the memory fills the
> > available OS memory).
>
> Too bad, this is a VM issue anyway.

I think this is user related (those who accidentally create deep
recursions), but should this be reported on the vm-list?

Regards,

Esteban A. Maringolo