Search code examples
c++arraysparameter-passingstack-overflowopen-array-parameters

How to avoid stack overflow when passing an array to a function in C++?


I am working on a code where an array is passed to a function by passing the pointer to the first location. In the function, part of the array is used. This creates an unsafe situation because there is a chance if the caller function does not guess the max size of the array correctly the callee function can write past the array size and a stack overflow can occur. I was thinking of a solution to this and thought of using a function template and passing the array as reference as shown in this example.

modifyArray.h

#define MAXSIZE 10

class modifyArray
{    
public:
    void create();

    void unsafeFunction(double*);

    template<int N>
    void safeFunction(double (&array)[N] );

private:
    int computeLength();
};

modifyArray.cpp

#include <iostream>
#include "modifyArray.h"

int modifyArray::computeLength()
{
    return 11;
}

void modifyArray::create()
{
    double testarray[MAXSIZE];
    unsafeFunction(testarray);    
    safeFunction(testarray);
}

void modifyArray::unsafeFunction(double* array)
{
    int operatingSize = computeLength();
    for(int i = 0; i < operatingSize; i++) {
        array[i] = i*i;
    }
}

template<int N>
void modifyArray::safeFunction(double (&array)[N] )
{
    int operatingSize = computeLength();
    std::cout<< "Max size" << N <<std::endl;
    if(operatingSize > N) return; // Return or raise an exception

    for(int i = 0; i < operatingSize; i++) {
        array[i] = i*i;
    }
}

main.cpp

#include "modifyArray.h"    

int main(int argc, const char * argv[]) {    
    modifyArray C;    
    C.create();
    return 0;
}

I am looking for a solution that is minimally invasive to the existing code. Here I just have to add a template statement, change the argument from double* to reference, and insert an if statement to check the size. I don’t want to do a major rewrite. Also I don’t want to use dynamic allocation, vector, or std::array mostly because of the performance reasons. This is a low level function in a numerical simulation code and performance is very important. Is there a better solution? Is there a pitfall to doing what I am doing?


Solution

  • If you really want to work with raw arrays and you want to safely modify all of the elements of the array without walking of the end then you can pass the array by reference and then use a range based for loop.

    tmeplate <typename T, typename Function, std::size_t N>
    void do_work(T (&arr)[N], Function f)
    {
        for (auto & e : arr)
            e = f();
    }
    

    The above will apply the result of calling function to every element of the array and is guaranteed to stay in the bounds of the array. You could use it like

    int main()
    {
        int arr[10];
        do_work(arr, []() { static int i = 0; i++; return i * i; });
        for (auto e : arr)
            std::cout << e << " ";
    }
    

    output:

    1 4 9 16 25 36 49 64 81 100 
    

    Live Example