views:

625

answers:

4

I'm attempting to write a junit test to guard against a piece of code getting stuck in a endless iteration which will eventually cause a StackOverflow.

so i'm looking for a way to decrease the stack size at runtime so the Junittest will fail faster.

setting the max stack as a jvm argument is not possible because the test is part of a much larger test suite.

thanks, P.V. Goddijn

+1  A: 

It's not possible to set the stack size at runtime, but perhaps you can:

  • invoke that piece of code inside a different thread - retaining the reference to it;
  • periodically poll thread.getStackTrace() and fail if its size is larger than x;
  • cancel the check if execution terminates correctly.


not-compiled proof of concept code ( does not properly check all edge conditions ):

AtomicBoolean success = new AtomicBoolean(false);

Thread t= new Thread(new Runnable() {
   public void run() {
       codeToTest();
       success.set(true);
   }

});

t.start();

while ( t.isAlive() ) {
     if ( t.getStackTrace().length > 50 )
          fail("Stack trace too large");

     Thread.sleep(50);
}

assertTrue(sucess.get());
Robert Munteanu
+4  A: 

You could run a recursive method which will run itself a given number of times and then execute a given action. Sounds pretty flaky though :(

Something like:

public void eatStackThenExecute(int depth, Runnable action)
{
    // Maybe put some locals here (and use them) to eat more stack per iteration?
    if (depth == 0)
    {
        action();
    }
    else
    {
        eatStackThenExecute(depth - 1, action);
    }
}

EDIT: It's possible that smart JVMs will optimise the tail call here, so it may be that we'd need to do "something" after the recursive call to stop that from happening...

Ick 'n stuff :(

Jon Skeet
Wow. What an awful idea. But it does, in effect, set the stack depth to the JVM's Max - the depth arg at runtime, so +1 anyway.
Ian McLaird
A: 

You can only set parameters like this at startup, however you can start another progress from Java. So you could make your unit tests start a second process with a smaller stack size to perform your test.

Peter Lawrey
A: 

This gets a bit... well, interesting... but it might be worth it.

  1. Take your .class file and decompile it with jasper.
  2. Edit the resulting JVM assembly-esque code and add or alter the ".limit stack x" argument for the routine you want to test in this manner.
  3. Recompile with Jasmin.
  4. Run it and test.
Alan
i think this introduces to many points of failure to use for a test case, but thanks.
pvgoddijn