C++ segfault on pointer comparison [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have an std::vector of struct pointers, in which I would like to remove duplicate entries. However, I would like to compare one member of the struct instead of the pointer directly. When I do it the incorrect way (comparing the pointers directly) there is no segfault; the dupes simply don't get removed. However, when I access the element in question to compare, I get a segfault.
My first guess would be that the structs are invalid/freed, but I can put that member in a char array and print it to the debug log right before without an issue, so this does not seem to be the case.
If the structs are valid (which they both seem to be and should be; I calloc every one before adding it), then I don't know why comparing their members would cause any issue.
Anyways, here is my code:
struct definition:
81 struct fp_node{
82 Tile *t;
83 unsigned int g;
84 unsigned int h;
85 unsigned int score;
86 struct fp_node *parent;
87 char type;
88 };
Accessing that member without issue
279 #ifdef DEBUG
280 for(unsigned int i = 0; i < open_list.size(); ++i){
281 char address[11];
282 snprintf(address, 11, "0x%08x", open_list[i]->t);
283 gui::log("Open list entry " + std::to_string(i) + ": " + std::string(address));
284 }
285 #endif
dupe filtering causing the issue:
291 for(unsigned int i = 0; i < open_list.size(); ++i){
292 for(unsigned int j = 0; j < open_list.size(); ++j){
293 if(i == j) continue;
294 if(open_list[i]->t == open_list[j]->t){
295 free(open_list[j]);
296 open_list.erase(open_list.begin() + j);
297 i -= 1;
298 j -= 1;
299 }
300 }
301
302 for(unsigned int j = 0; j < closed_list.size(); ++j){
303 if(open_list[i] != closed_list[j]) continue;
304 free(open_list[i]);
305 open_list.erase(open_list.begin() + i);
306 i -= 1;
307 }
308 }
Notice that in the first j for loop, I access the t member of the struct. This causes the segfault. The second j loop does simply compares the pointers. It doesn't segfault but it isn't what I want.
I tried accessing methods from the tile class, but those segfault as well, so I do think the memory is somehow being freed automatically in the meantime. I don't know why though, as everything is on the heap except for the vectors themselves, which are in a larger scope and shouldn't die.
However, when I try to access the member in only one part of the comparison (if((Tile *)open_list[i] == open_list[j]->t)), I don't get a segfault; same with the other side.
I'm completely lost here, can someone please help me?
Thanks.

Hope the sleepy in my eyes is not making my mind see spots, but something jumps out at me.
Hard to say for sure as you don't say how open_list is allocated. Since open_list is released by free() I'm going to assume it is a simple pointer allocated by malloc() or calloc() and these are C functions. Never tried mixing malloc() and size(), or new() and free(), but I would fear that array size reported by from open_list.size() would not change under free().
See http://www.cplusplus.com/reference/array/array/size/

Related

Getting Unexpected value

I was playing around with array and when i did this , im expecting IndexOutOfBound
however , the program still ran and gave an output 54
Where does the extra number come from ?
How to avoid these kind of indexing problem?
#include <iostream>
int main(){
int array[] = {1,2,3,4,5,6};
int total;
for(int i = 0 ; i<=7 ; i++){
total += array[i];
}
std::cout << total;
return 0;
}
C++ does not do any checking to make sure that your indices are valid for the length of your array.
Like churill notes above, indexing out of range is undefined behavior. For example, in your question, the value of array[6] is whatever is stored your memory at the location where the 6th element would have existed. In your case, this was a random value for instance from another variable.
Although rare, C++ will also let you use a negative index, with similarly undesirable results.

Why does this fix a heap corruption?

So I've got code:
float **array = new float*[width + 1]; //old line was '= new float*[width]'
//Create dynamic 2D array
for (int i = 0; i < width; ++i) {
array[i] = new float[height + 1]; //old line was '= new float[height]'
}
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
//deallocate heap memory
for (int i = 0; i < width; ++i) {
delete [] array[i]; //Where corrupted memory error used to be
}
delete [] array;
(For the record, I know it would be more efficient to allocate a single block of memory, but I work closely with scientists who would never understand why/how to use it. Since it's run on servers, the bosses say this is preferred.)
My question is why does the height+1/width+1 fix the corrupted memory issue? I know the extra space is for the null terminator, but why is it necessary? And why did it work when height and width were the same, but break when they were different?
SOLN:
I had my height/width backwards while filling my array... -.-; Thank you to NPE.
The following comment is a red herring:
delete [] array[i]; //Where corrupted memory error used to be
This isn't where the memory error occurred. This is where it got detected (by the C++ runtime). Note that the runtime isn't obliged to detect this sort of errors, so in a way it's doing you a favour. :-)
You have a buffer overrun (probably an off-by-one error in a loop) in the part of your code that you're not showing.
If you can't find it by examining the code, try Valgrind or -fsanitize=address in GCC.
edit: The issue with the code that you've added to the question:
//Hardcode 2D array for testing
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
array[i][j] = i + j;
}
}
is that it has width and height (or, equivalently, i and j) the wrong way round. Unless width == height, your code has undefined behaviour.
Changing height and weight by height+1 and weight+1 is probably not going to be enough.
The code you posted was correct with height and weight.
This means that something was likely writing just past the end of those arrays in some other part of the code, and when you grew those arrays, it made the faulty code write right at the end of the arrays instead of crashing. You didn't fix the issue, you just hid it.
The code actually crashed on the delete[] due to some limitations in how the OS detects heap corruptions. Very often off-by-one errors on the heap will be detected by the next call to new/delete/malloc/free, not when they actually happen.
You can use tools like Valgrind if you want to know exactly when and where your program does illegal things with pointers.
You didn't fix the code. What you are doing is changing the executable with the new code, thus moving the corruption bug to another part of your program.
One thing you should not do -- do not change your program to the one you say "works" with the + 1 and then accept it. I know it may be tempting if the bug is hard to diagnose, but don't go this route.
What you must do is go back to the non-working version, and really fix the issue. By "fix", meaning you can explain what the fix does, why it fixes the problem, etc.

compiler behaving abnormally c++

I am using this simple program.
#include<iostream>
using namespace std;
int main(){
int arr[200]={0};
int i = 200;
arr[i] = 1;
cout << i << endl;
}
I expect the result to be 200; In my system its showing result as 1.
Can anyone explain the abnormal behavior.
You allocated an array with 200 elements which gives you indexes 0 through 199. You set the item at index 200 to be 1, which is beyond the bounds of your array. C++ is happy to let you stomp whatever memory you want. You declared i right after arr and so it literally got allocated on the stack right after arr in memory, so you set it to 1 when you went past the end of your array by one element.
You can verify by declaring i before arr and see what happens. Or set i to 199, which is probably what you meant to do.

C++ Dynamic bool array causes crash

Today I tried to program the Sieve of Eratosthenes and it works as far as it provides me with the prime numbers. But I have a problem with the dynamic array I don't understand.
First problem: As soon as I try to enter a "big" value for n (for example 120), the program crashes, it doesn't even allocate the memory.
Second problem: If I enter a value like 50 it is able to give out the correct prime numbers but crashes before it deletes the array.
Third problem: If I enter a very small value like 5 it is able to execute the entire program, it gives out the correct numbers and deletes the memory.
But I don't understand why it acts so differently. 120 boolean values can't crash my memory, at least I think so. And why isn't it able to delete an array of 50 values but is actually able to delete an array of 5 values?
Can anyone tell me what's the problem?
int n;
cin >> n;
n=n+1;
bool *feld = new bool[n];
for(int i=2;i<n;i++)
{
int j=i*i;
feld[j]=true;
for(;j<n;j+=i)
feld[j]=true;
}
for(int i=2;i<n;i++)
if(!feld[i])
cout << i << endl;
else;
delete[] feld;
feld = NULL;
Your problem is here:
int j=i*i;
feld[j]=true;
there is no check as to whether j < n so you are stomping over unallocated memory when j >= n.
This code is wrong
bool *feld = new bool[n];
for(int i=2;i<n;i++)
{
int j=i*i;
feld[j]=true;
...
}
Suppose n == 10 and i == 9, then j == 81 but you only have 10 elements in your bool array.
This is how it works when you write bugged programs, sometimes it seems to work, it might even give the right answer, other times it will crash. This is a very important lesson, and you're actually lucky to have learned it early.
Actually It's not just that feld[j]=true; is causing the error.
Also, you don't need that line at all before the loop.
because, it's the first case inside the loop.

Run-Time Check Failure #2 - Stack around the variable 'temp' was corrupted [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
When i am running this code I am getting below error as
Run-Time Check Failure #2 - Stack around the variable 'temp' was corrupted
int main()
{
UINT8 temp[7];
for (int i = 0; i <= 7; i++)
{
temp[i] = 0x01;
}
return 0;
}//The error falls here
Please help me.
you are accessing array out of boundry
change:
for (int i = 0; i <= 7; i++)
to
for (int i = 0; i < 7; i++)
Or more C++ way:
std::fill_n(temp, 7, 0x01);
the size of temp is 7 and the for loop reach 8 elements and not 7
change
for (int i = 0; i <= 7; i++)
by
for (int i = 0; i < 7; i++)
The array index in c start from 0. so if you go from index 0 to index 7 in your array that means you reach the 8th element in your array, but your array size is 7
The cycle should be excluding 7 - your array is of size 7, so there is no element with index 7 in it.
Declaring UINT8 temp[7]; creates an array of 7 variables. Starting from temp[0] to temp[6]
Your for loop however tries to access temp[7] which is undefined.
The below loop will work
for (int i = 0; i < 7; i++)
{
temp[i] = 0x01;
}
There are 7 elements in the array ([0..6]), your for loop tries to access 8 elements [0..7], therefore you get a corrupted stack.
for (int i = 0; i < 7; i++)
{
temp[i] = 0x01;
}
This will help you.. you are writing back to the temp again.. that is the error you are getting
Note that in C and C++, array indexes are 0-based. So, if you have an array of N items, valid index values are 0,1,2,...,(N-1).
In your case, N = 7, so valid index values are 0,1,2,3,4,5,6.
So, substitute <= with < in your for loop:
UINT8 temp[7];
for (int i = 0; i < 7; i++) // Use <, not <=
....
Moreover, there is a convenient _countof() macro available with VS in <stdlib.h>, which makes your code easier to read and maintain (instead of using the "magic number" 7 in your for loop):
for (int i = 0; i < _countof(temp); i++)
Using _countof(), if you change the size of the array, your loop code will still work, without modifying 7 to the new array size.
Note also that in C++11 it's possible to use range-based for loops (but they are not available in VC10/Visual Studio 2010, which you used as a tag in this question).
Note that if you want to fill a buffer with a given byte sequence you can use memset (a C-like way):
memset(temp, 0x01, sizeof(temp));
Or, more generally (even for elements larger than one byte), you can use C++ std::fill from <algorithm>:
fill(begin(temp), end(temp), 0x01);
Using an explicit algorithm like std::fill makes your code more readable, because it rises the "semantic level" of the source code (you just read "fill" instead of reading a "raw" for loop, the meaning of which you have to interpret).