Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursion fix to correctly reset RecursionDepth whenever a longjmp occurs #1753

Merged
merged 2 commits into from
Oct 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions doc/ref/debug.xml
Original file line number Diff line number Diff line change
Expand Up @@ -876,20 +876,35 @@ brk> return;
gap>
]]></Log>
<P/>
This behaviour can be controlled using the following procedure.

This behaviour can be controlled using the following procedures.

<ManSection>
<Func Name="SetRecursionTrapInterval" Arg='interval'/>
<Func Name="GetRecursionDepth" Arg=''/>

<Description>
<A>interval</A> must be a non-negative small integer (between 0 and
<M>2^{28}</M>). An <A>interval</A> of 0 suppresses the monitoring of recursion
<Ref Func="GetRecursionDepth"/> returns the nesting level of the GAP
interpreter. This is reset to 0 every time the break loop is entered.
<Ref Func="SetRecursionTrapInterval"/> sets the depth of the stack at which
GAP will enter the Break loop. <A>interval</A> must be a non-negative small
integer (between 0 and <M>2^{28}</M>).
An <A>interval</A> of 0 suppresses the monitoring of recursion
altogether. In this case excessive recursion may cause &GAP; to crash.
<P/>
<Log><![CDATA[
gap> dive:= function(depth) if depth>1 then dive(depth-1); fi; return; end;
function( depth ) ... end
gap> GetRecursionDepth();
0
gap> dive := function(depth)
> if depth>1 then
> dive(depth-1);
> else
> Print("Depth ", GetRecursionDepth());
> fi;
> end;;
gap> SetRecursionTrapInterval(1000);
gap> dive(100);
Depth 100
gap> dive(2500);
recursion depth trap (1000)
at
Expand All @@ -910,6 +925,8 @@ dive( depth - 1 ); called from
Entering break read-eval-print loop ...
you can 'quit;' to quit to outer loop, or
you may 'return;' to continue
brk> GetRecursionDepth();
0
brk> return;
gap> SetRecursionTrapInterval(-1);
SetRecursionTrapInterval( <interval> ): <interval> must be a non-negative smal\
Expand All @@ -918,19 +935,15 @@ not in any function
Entering break read-eval-print loop ...
you can 'quit;' to quit to outer loop, or
you can replace <interval> via 'return <interval>;' to continue
brk> return ();
SetRecursionTrapInterval( <interval> ): <interval> must be a non-negative smal\
l integer
not in any function
Entering break read-eval-print loop ...
you can 'quit;' to quit to outer loop, or
you can replace <interval> via 'return <interval>;' to continue
brk> return 0;
gap> dive(20000);
Depth 20000
gap> dive(2000000);
Segmentation fault
]]></Log>
</Description>


</ManSection>

</Section>
Expand Down
6 changes: 6 additions & 0 deletions src/funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,10 @@ Obj FuncSetRecursionTrapInterval( Obj self, Obj interval )
return 0;
}

Obj FuncGetRecursionDepth( Obj self )
{
return INTOBJ_INT(STATE(RecursionDepth));
}

/****************************************************************************
**
Expand All @@ -1731,8 +1735,10 @@ Obj FuncSetRecursionTrapInterval( Obj self, Obj interval )
static StructGVarFunc GVarFuncs [] = {

GVAR_FUNC(SetRecursionTrapInterval, 1, "interval"),
GVAR_FUNC(GetRecursionDepth, 0, ""),
{ 0, 0, 0, 0, 0 }


};

/****************************************************************************
Expand Down
2 changes: 2 additions & 0 deletions src/read.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@

#define TRY_READ \
if (!STATE(NrError)) { \
volatile Int recursionDepth = STATE(RecursionDepth); \
if (sySetjmp(STATE(ReadJmpError))) { \
STATE(RecursionDepth) = recursionDepth; \
STATE(NrError)++; \
}\
}\
Expand Down
32 changes: 32 additions & 0 deletions tst/testinstall/depth.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
gap> START_TEST("depth.tst");

# We don't know what the recursion depth will be when the test starts,
# so do relative comparisons.
gap> curdepth := GetRecursionDepth();;
gap> GetRecursionDepth() - curdepth;
0
gap> dive := function(depth)
> if depth>1 then
> dive(depth-1);
> else
> Print("Depth ", GetRecursionDepth() - curdepth, "\n");
> fi;
> end;;
gap> dive(10);
Depth 10
gap> dive(80);
Depth 80
gap> SetRecursionTrapInterval(50);
gap> dive(80);
Error, recursion depth trap (50)
gap> SetRecursionTrapInterval(5000);
gap> dive(80);
Depth 80

# Just want an error to occur to check the depth is reset correctly
gap> IsAbelian(2);
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
Error, no 1st choice method found for `IsCommutative' on 1 arguments
gap> dive(80);
Depth 80
gap> STOP_TEST( "depth.tst", 1);