Question

I have an exception class called Exception, and I'm invoking a recursive function which gets called approximately 200 times while looping through a map. RecursiveFunction() is part of a class that contains a parameters map (which maps a string to a class param). The class param contains a min, a max, and number of steps between min and max, so that a set of functions can be run with each parameter set. RecursiveFunction() therefore loops through the map to run a set of functions given the 'current' parameters.

bool RecursiveFunction(map<string,param>::iterator current) {
   map<string,param>::iterator last = parameters.end();
   last--;
   if( current == last )
       return true;
   else {
       // Do some things
       if(something_wrong)
           throw Exception("RecursiveFunction()","Something went wrong");
       ++current;
       RecursiveFunction(current);
   }
}

The code above fails after about 120 recursive calls. It seems to be a memory issue, because most of the time it fails on the line:

last--;

The weird thing is that the code runs smoothly in both of the following cases:

bool RecursiveFunction(map<string,param>::iterator current) {
    ...
    if(something_wrong)
        throw "";
    ...
   }

or

bool RecursiveFunction(map<string,param>::iterator current) {
    ...
    if(something_wrong) {
        Exception exc = Exception("RecursiveFunction()","Something went wrong");
        ThrowException(exc); //ThrowException() { throw exc; }
    }
    ...
   }

The code isn't hitting the 'throw' so the Exception is not being constructed or copied (confirmed with breakpoints). Why would the existence of a class affect the outcome of a function, if that class isn't getting instantiated in the function?

EDIT:

I was able to reproduce this using a complete example (with Visual Studio 2010):

#include <iostream>

using namespace std;

class Exception: public std::exception {
private:
    char        gsCallPath[1001];
    char        gsError[1001];
public:
    Exception(const char* sErrorCallPath, const char* sThrownError)
    {
       strcpy(gsError,sThrownError);
       strcpy(gsCallPath,sErrorCallPath);
    }
    ~Exception() {
    }
};

bool RecursiveFunction(int n);

int main() {
    RecursiveFunction(500);
}

bool RecursiveFunction(int n) {

    cout << n << '\n';

    if (n == 0)
        return true;
    else {
        if(false) {
            throw Exception("","");
            //throw "";
        }
        else
        {
            RecursiveFunction( n-1 );
        }
    }
}

The run crashed with a Stack Overflow exception. Replacing throw Exception("",""); with throw ""; allowed the program to run to completion. Note: the size of the Exception class had an impact on how big n needed to be in order to overflow. Thanks @catscradle and @Yakk for your comments.

Was it helpful?

Solution

#include <exception>
void f() {
    if (false) {
        throw "";
        //throw std::exception();
    }
    return f();
}
int main() {
    f();
}

Looking at the assembly, it seems that the function reserves stack space for the exception object and it doesn't matter if it gets thrown or not. So in case of "" this function reserves 204 bytes(sub esp, 0CCh) and in case of std::exception it's sub esp, 0D4h, i.e. 8 bytes more, which is sizeof(std::exception) - sizeof(char*).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top