views:

254

answers:

5

i have a function to calculate several different values:

int ASPfile::get_dimensions(int* Lat, int* Lon, 
     vector<double>* Latgrid, vector<double>* Longrid) {

    _latsize = get_latsize();
    _lonsize = get_lonsize();

    Lat = &_latsize;
    Lon = &_lonsize;

    latgrid = read_latgrid();
    longrid = read_longrid();

    *Latgrid = latgrid;
    *Longrid = longrid;

    return 0;
}

This function is called as follows:

int* Latsize = NULL;
int* Lonsize = NULL;
vector<double>* Latgrid = NULL;
vector<double>* Longrid = NULL;
int res = asp->get_dimensions(Latsize,Lonsize,Latgrid,Longrid);

and then, I try to access the values as follows:

cout << (*Szagrid)[4];

or like this

cout << Szagrid->at(4);

The program compiles with no warnings. However, when I try to access the pointers which are supposed to be 'filled' by get_dimensions(), valgrind shows me the following:

==10531== Invalid read of size 8
==10531==    at 0x633D5DA: std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) (in /home/myhome/src/libiup/Release/libiup.so)
==10531==    by 0x633CADC: ASPfile::get_dimensions(int*, int*, int*, std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*) (in /home/myhome/src/libiup/Release/libiup.so)
==10531==    by 0x41B90B: ASPfileTest::test_get_dimensions() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41BACC: ASPfileTest::operator()() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41E229: boost::function0<void>::operator()() const (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41E7C2: cute::runner<cute::eclipse_listener>::runit(cute::test const&) (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41D26A: runSuite() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41DBC4: main (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==10531== 
==10531== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==10531==  Access not within mapped region at address 0x0
==10531==    at 0x633D5DA: std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) (in /home/myhome/src/libiup/Release/libiup.so)
==10531==    by 0x633CADC: ASPfile::get_dimensions(int*, int*, int*, std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*) (in /home/myhome/src/libiup/Release/libiup.so)
==10531==    by 0x41B90B: ASPfileTest::test_get_dimensions() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41BACC: ASPfileTest::operator()() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41E229: boost::function0<void>::operator()() const (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41E7C2: cute::runner<cute::eclipse_listener>::runit(cute::test const&) (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41D26A: runSuite() (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==    by 0x41DBC4: main (in /home/myhome/src/libiup_test/Release/libiup_test)
==10531==  If you believe this happened as a result of a stack overflow in your
==10531==  program's main thread (unlikely but possible), you can try to increase
==10531==  the size of the main thread stack using the --main-stacksize= flag.
==10531==  The main thread stack size used in this run was 8388608.

I don't quite understand what I'm doing wrong; probably something obvious, but I cannot seem to find the problem.

Any help is greatly appreciated!

+5  A: 

You're writing to memory in get_dimensions, but you're never actually allocating that memory. Instead, you are just passing NULL pointers.

One potential fix is to change your calling code to:

int Latsize, Lonsize;
vector<double> Latgrid;
vector<double> Longrid;
int res = asp->get_dimensions(&Latsize,&Lonsize,&Latgrid,&Longrid);

This allocates space for the variables automatically on the stack, then you pass the address of that allocated space to get_dimensions, which will modify the values.

Michael
+1  A: 

Where are 'latgrid' and 'longrid' defined? If they are local to ASPFile::get_dimensions, then their destructors will be called as the function returns, destroying them.

Mark P Neyer
thanks for the hint, i would've forgotten that. however, the problem ẃas solved with the above answer by michael.
andreash
+5  A: 

Your question is being answered well by others, but I want to point out that since this is C++, not C, all of this confusion could be avoided if you just used references instead of pointers. This is generally what you should do in a case like this (if NULL return values are not needed)

int ASPfile::get_dimensions(int& Lat, int& Lon, 
        vector<double>& Latgrid, vector<double>& Longrid) {

    Lat = get_latsize();
    Lon = get_lonsize();

    Latgrid = read_latgrid();
    Longrid = read_longrid();

    return 0;
}

// Call like this

int Latsize;
int Lonsize;
vector<double> Latgrid;
vector<double> Longrid;
int res = asp->get_dimensions(Latsize,Lonsize,Latgrid,Longrid);
Tyler McHenry
Aw, you beat me to it by a minute! +1
sbi
+3  A: 

The function's signature taking pointers to me signals I might just as well pass in NULL pointers, if I don't have a fitting object at hand or if I am not interested in a particular result. Your function, however, doesn't check for this and happily writes to address 0.

If proper objects must be passed into the function, then why doesn't it take references instead of pointers? They are meant to be used for what you want to do, are easier to understand, and harder to get wrong.

int ASPfile::get_dimensions( int& Lat
                           , int& Lon
                           , vector<double>& Latgrid
                           , vector<double>& Longrid );
sbi
A: 

Agree with all said about pointers. As a rule of the thumb - don't use them unless you really have to. In the meantime, the pattern used here looks messy and ugly and the need of get_dimensions function is entirely obscure. You are adding unnecessary level of complexity.

Instead of this, I suspect making those get_ and read_ functions you already using in your prototype function public on ASPFile would be enough:

int Latsize = asp->get_latsize();
int Lonsize = asp->get_lonsize();
vector<double> Latgrid = asp->read_latgrid();
vector<double> Longrid = asp->read_longrid();

Just keep it simple.

blinnov.com