Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference in behaviour (GCC and Visual C++)

Consider the following code.

#include <stdio.h>
#include <vector>
#include <iostream>

struct XYZ { int X,Y,Z; };
std::vector<XYZ> A;

int rec(int idx)
{

   int i = A.size();
   A.push_back(XYZ());
   if (idx >= 5)
     return i;

   A[i].X = rec(idx+1);

   return i;
}

int main(){
  A.clear();
  rec(0);
  puts("FINISH!");

}

I couldn't figure out the reason why the code gives a segmentation fault on Linux (IDE used: Code::Blocks) whereas on Windows (IDE used: Visual C++) it doesn't.

When I used Valgrind just to check what actually the problem was, I got this output.

I got Invalid write of size 4 at four different places. Then why didn't the code crash when I used Visual C++?

Am I missing something?

like image 953
Prasoon Saurav Avatar asked May 06 '10 06:05

Prasoon Saurav


2 Answers

The recursive call to rec() might modify the vector while you're assigning a value to it.

What happens if you replace

A[i].X = rec(idx+1);

with

int tmp = rec(idx+1);
A[i].X = tmp;

?

Also, just to summarize the useful comments: the operand evaluation order of a = operation is unspecified and since the vector wasn't preallocated, several resizes can occur during a recursive call to rec(), thus invalidating any iterator to values in the vector.

like image 102
ereOn Avatar answered Sep 23 '22 23:09

ereOn


I get "* error for object 0x300180: incorrect checksum for freed object - object was probably modified after being freed. *" when I run that code.

As I recall, A[i].X = rec(idx+1) has three sequence points. When operator[] is called on A, when rec is called, and at the end. But the order of the first two is unspecified. So if g++ calculates A[i] first, and then calls rec(idx+1), then when rec returns the reference returned by A[i] could have been invalidated by a reallocation of the vector's internal memory. Under VC++, it might be evaluating rec(idx+1) first, so all the push_back calls are done up front, which means the A[i] calls refer to the correct block of memory. Alternatively, it might do things the same way, and you just happen to not segfault... that's one of the problems of undefined behavior.

Changing std::vector<XYZ> A; to std::vector<XYZ> A(10); will reserve enough space for 10 elements. This prevents your specific implementation of rec from ever needing to reallocate, and that fixes the error on my end.

like image 23
Dennis Zickefoose Avatar answered Sep 20 '22 23:09

Dennis Zickefoose