BTW: I found the problem: (See my answer below)
When I build my program at home it works fine, but when I use my universities system is crashing on me. When I go at it with GDB I get this:
(gdb) r t.c-
Starting program: /home/shro8822/p5/c- t.c-
*--Code Gen Function: main
*--in function 'main' variable offsets start at 2
Program received signal SIGSEGV, Segmentation fault.
0x08084410 in ObjectCode::ResolveRef (this=0xbfb3dd20) at CodeOutput.cpp:44
44 p->Resolve(this);
(gdb) list
39 {
40 std::list<Patch*>::iterator pos;
41 for(pos = Patchups.begin(); pos != Patchups.end(); ++pos)
42 {
43 Patch* p = *pos;
44 p->Resolve(this);
45 //delete p;
46 }
47
48 }
(gdb) p p
$1 = (class ObjectCode::Patch *) 0x2064696c
(gdb) p this
$2 = (ObjectCode * const) 0xbfb3dd20
It crashes from a SEG-V on a line with a virtual function call involving 2 variable and neither is NULL. I don't think there is anywhere else that stuff from this list is deleted.
Tossing it a Valgrind gives one error:
==5714== Invalid read of size 4
==5714== at 0x8084410: ObjectCode::ResolveRef() (CodeOutput.cpp:44)
==5714== by 0x8086E00: ObjectCode::Finish() (CodeOutput.cpp:196)
==5714== by 0x807EC97: WalkGlobal::Finish() (CodeGen_G.cpp:211)
==5714== by 0x808D53C: Compile::RunV() (cs445.cpp:120)
==5714== by 0x808D7C2: ProcessFile::Run() (cs445.cpp:49)
==5714== by 0x808CCD9: main (cs445.cpp:234)
==5714== Address 0x2064696C is not stack'd, malloc'd or (recently) free'd
Seg fault
Any idea were to start looking?
BTW: I populate the list using only statements like this: Patchups.push_back(new PatchType());
shro8822 p5 $ grep Patchups *.cpp *.h -n
CodeOutput.cpp:41: for(pos = Patchups.begin(); pos != Patchups.end(); ++pos)
CodeOutput_Slot.cpp:124: { Stream->Patchups.push_back(new FunctionPatch(it,GetSlotBefor(),at)); }
CodeOutput_Slot.cpp:126: { Stream->Patchups.push_back(new GotoPatch(target,GetSlotBefor(),at,"goto")); }
CodeOutput_Slot.cpp:128: { Stream->Patchups.push_back(new GotoPatch(target,GetSlotBefor(),at,c)); }
CodeOutput_Slot.cpp:130: { Stream->Patchups.push_back(new BranchPatch(target,GetSlotBefor(),type,from,at,c)); }
CodeOutput.h:222: std::list Patchups;
Yet more: It happens that the home and school systems are both x86 (RHEL 3 and 5 respectively) so I ran the binary I compiled at home on the system at school and it runs fine.
The value of the pointer is probably the victim of a wild write from somewhere else.
The variable p shown in your debugger output is 0x2064696c. That is probably the string "lid ", depending on your byte ordering. You should look for somewhere in your code where that string (or value) was stored.
One of the pointers in your list is invalid. This could be because it is null (not in your case), uninitialized, initialized via a bad cast or the valid object that it once pointed to has been destroyed.
Because it works in one environment and not in another you are probably seeing the results of some undefined behaviour.
When you push the pointers onto the list, what objects are they pointing to and what happens to those objects at the time you call Finish?
You're dereferencing p on line 44 to an object that doesn't exist.
Either p was never initialized, or *p has already been deleted.
Edit: I'd recommend to start looking where this list is populated, and verify that your list items are initialized to 0, and that you actually assign pointers to your Patch instances to the list. Also you might look for other errors or exceptions that you're ignoring or catching during the initialization process that are allowing pointers to invalid memory like this to make it into the list.
How I found the problem.
First a tip of the hat to janm for identifying what was going wrong even if it didn't help much in finding where.
I added a Test function that is effectively a copy of the function that fails, but with all the side effects stripped out. With it running all over the place I was able to isolate where things break down into a small windows. Under the debugger, I single stepped from that last valid pass to the first invalid pass and got this:
CodeOutput.cpp:224 | ObjectCode::Test();
CodeOutput.cpp:225 | continue;
CodeOutput.cpp:111 | while(at != ops.end())
stl_list.h:598 | { return iterator(&this->_M_impl._M_node); }
stl_list.h:127 | : _M_node(__x) { }
stl_list.h:174 | { return _M_node != __x._M_node; }
CodeOutput.cpp:113 | printf("%s\n", (*at).TypeStr());
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
CodeOutput_asm.cpp:33 | switch(Type)
CodeOutput_asm.cpp:36 | Case(OpPlaceholder);
CodeOutput.cpp:115 | switch((*at).Type)
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
CodeOutput.cpp:216 | char* c = (*at).comment;
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
CodeOutput.cpp:217 | if((*at).head != NULL && (*at).head[0] != '\0')
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
CodeOutput.cpp:222 | ++at;// = ops.erase(at);
stl_list.h:141 | _M_node = _M_node->_M_next;
stl_list.h:142 | return *this;
CodeOutput.cpp:223 | (*at).head = c;
stl_list.h:132 | { return static_cast(_M_node)->_M_data; }
CodeOutput.cpp:224 | ObjectCode::Test();
Formatted for clarity, the memory corruption must be caused by one of these lines:
-- last valid test
CodeOutput.cpp:224 | ObjectCode::Test();
CodeOutput.cpp:225 | continue;
-- falls into loop ('at' is list::iterator)
CodeOutput.cpp:111 | while(at != ops.end())
CodeOutput.cpp:113 | printf("%s\n", (*at).TypeStr());
CodeOutput.cpp:115 | switch((*at).Type)
-- OpPlaceholder case
CodeOutput.cpp:216 | char* c = (*at).comment;
-- if gets false ('head' is char*)
CodeOutput.cpp:217 | if((*at).head != NULL && (*at).head[0] != '\0')
CodeOutput.cpp:222 | ++at;
CodeOutput.cpp:223 | (*at).head = c;
-- first invalid test
CodeOutput.cpp:224 | ObjectCode::Test();
-- called from CodeOutput.cpp:113
CodeOutput_asm.cpp:33 | switch(Type)
CodeOutput_asm.cpp:36 | case OpPlaceholder; return "OpPlaceholder";
Because that not to long a list, I just added even more logging till I found that these line causes the problem:
++at;
(*at).head = c;
Now that I know exactl where to look it easy to see the problem, and by switching to:
++at;
if(at != ops.end()) (*at).head = c;
the problem goes away.
The only questions I still have are 1) why did it work at all on my old system? and 2) why didn't that manifest as a seg-v right on the second line? I would think that having *(list.end()) result in a reference to NULL would be a good thing.
You should use < in your conditional statement.
When you increment a pointer using ++, it increases it by the size of whatever it points to. Since you're using !=, it's possible that you're not hitting Patchups.end() exactly, and so you're walking off then end into invalid memory.
Or it might be something else. There might be invalid memory somewhere between begin() and end(), for example.
Related
This code works OK when compiled with g++ on Linux, but when I try to execute them in VS 2015 (both debug and release) I receive runtime error. What's wrong with it?
#include "stdafx.h"
#include <string.h>
#include <iostream>
using namespace std;
struct Stru1
{
int mem;
};
struct Stru2 : public Stru1
{
char szMem1[256];
int dwMem2;
int dwMem3;
};
static void clFun(Stru1* s) {
Stru2* s2 = (Stru2*)s;
cout << s2->szMem1 << endl;//blahblah
cout << s2->dwMem2 << endl;//runtime error
}
class Temp {
public:
void callDispatch() {
simRecv->mem = 2;
Stru2* sro = (Stru2*)simRecv;
strcpy(sro->szMem1, "blahblah");
sro->dwMem2 = 11;
sro->dwMem3 = 77;
//cout << sro->szMem1 << endl;//blahblah
//cout << sro->dwMem2 << endl;//runtime error when uncommented
clFun(simRecv);
}
~Temp() { delete simRecv; }
Stru1* simRecv = new Stru1;
};
int main()
{
Temp tmp;
tmp.callDispatch();
return 0;
}
Error:
Exception thrown at 0x0000000077A0F23C (ntdll.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x00000FB00188C508.
Stru2* sro = (Stru2*)simRecv;
simRecv is a Stru1, so your unsafe cast to Stru2 is invalid in this line.
In this line you create this Stru1,
Stru1* simRecv = new Stru1;
Here Stru1 is assigned the memory needed to create a Stru1, which is smaller than a Stru2.
By doing:
Stru2* sro = (Stru2*)simRecv;
You are just saying: I have this "thing" and treat it as a Stru2. But there hasn't been a new Stru2 created anywhere so the object just isn't there.
It is basically the same as saying
I have a large wall, but I'll treat it as a house and expect a door in it.
The reason that it might work on a different platform can be due to a different memory allocation of the platform.
As for the analogy: you might have reached the end of the wall and hence don't hurt your head, but you are not inside the house and you won't leave your wallet there.
For example, this line will eventually point to somewhere:
sro->dwMem3 = 77;
The question is: is this within valid program space? If it is, no error will occur, but that doesn't mean it is good. You are probably altering a variable, somewhere else, leading to unpredictable results.
An example:
Platform1:
| Stru1 | some variable | some other variable |
| mem | 0 | 11 |
| | | ((Stru2*) simRecv)->dwMem2 |
//no errors, but strange side effects
Platform2:
| Stru1 | some variable | some other program space |
| mem | 0 | ERROR: ACCES VIOLATION |
| | | ((Stru2*) simRecv)->dwMem2 |
//0xC0000005
If you assign a Stru2 (by actually creating it) in the first place, all will be good:
Stru1* simRecv = (Stru1*) new Stru2;
Having said that; these cast are considered unsafe (for now obvious reasons).
The alternative is to use, for example a static_cast. It will make sure you'll get a build error when trying to do something "illegal".
http://www.cplusplus.com/doc/tutorial/typecasting/
additional note about cplusplus see: What's wrong with cplusplus.com?
I am trying to build and run some complicated code that was written by someone else, I don't know who they are and can't ask them to help. The code reads a bpf (brain potential file) and converts it to a readable ascii format. It has 3 C files, and 2 corresponding header files. I got it to build successfully with minor changes, however now it crashes
with a segmentation fault.
I narrowed the problem down to FindSectionEnd() (in ReadBPFHeader.c) and find that the error occurs when sscanfLine() (in the file sscanfLine.c) is called (code for both is below).
ui1 is defined as unsigned char.
si1 is defined as char.
Just before returning from sscanfLine(), the address pointed to by dp is 0x7e5191, or something similar ending with 191. However, on returning to FindSectionEnd(), dp points to 0x20303035 and it says 'Address 0x20303035 is out of bounds', which then causes a fault at strstr(). The loop in FindSectionEnd() runs without problem for 14 iterations before the fault occurs. I have no idea what is going wrong. I really hope the information I have given here is adequate.
ui1 *FindSectionEnd(ui1 *dp)
{
si1 Line[256], String[256];
int cnt=0;
while (sscanfLine(dp, Line) != EOF){
dp = (ui1 *)strstr(dp, Line);
dp+= strlen(Line);
sscanf(Line,"%s",String);
if(SectionEnd(String))
return(dp);
}
return(NULL);
}
si1 *sscanfLine(ui1 *dp, si1 *s)
{
int i = 0;
*s = NULL;
int cnt = 0;
while (sscanf(dp, "%c", s + i) != EOF){
cnt++;
dp++;
if(*(s + i) == '\n') {
*(s + i + 1) = '\0';
return s;
}
++i;
}
*(s + i) = '\0';
return s;
}
The sscanfLine function doesn't respect the size of the buffer passed in, and if it doesn't find '\n' within the first 256 bytes, happily trashes the stack next to the Line array.
You may be able to work around this by making Line bigger.
If you're going to improve the code, you should pass the buffer size to sscanfLine and make it stop when the count is reached even if a newline wasn't found. While you're at it, instead of returning s, which the caller already has, make sscanfLine return the new value of dp, which will save the caller from needing to use strstr and strlen.
My first guess would be that your string is not null terminated and strstr() segfaults because it reads past the boundaries of the array
i'm doing some OpenCL programming and at one location in my code I get strange error.
a and a_end are pointers to local memory
if (a+POS<=a_end) {
max = ....
} else {
max = *(a_end-1);
}
In my case "else" isn't reached in the current loop. However, the application crashes with -5 CL_OUT_OF_RESOURCES if the line is part of the code.
If I comment the line the program works well. This is very strange.
Do you have any suggestions?
Regards,
Chris
Edit: Some more code
Values of a, a_end and POS1 before it crashes:
a: 3298304
a_end: 3311264
POS1: 34
border=b-b_end; //TODO: Check if all dummy elements are removed in this case
if(POS1<border && a+POS1<a_end) {
s_data[POS1+s_maxes[2]-border+1]=a[POS1];
s_ids[POS1+s_maxes[2]-border+1] = a_pos+POS1;
}
if(POS1+1==border) {
debug[0] = a+POS1;
debug[1] = a_end;
s_maxes[1]=*(b_end-1);
if(a+POS1<=a_end) {
s_maxes[0]=s_data[s_maxes[2]];
} else {
s_maxes[0]=*(a_end-1); //Here is the line where it crashes
}
}
if(POS2<border && a+POS2<a_end) {
s_data[POS2+s_maxes[2]-border+1]=a[POS2];
a_pos+POS2;
}
if(POS2+1==border) {
s_maxes[1]=*(b_end-1);
if(a+POS2<=a_end) {
s_maxes[0]=s_data[s_maxes[2]];
} else {
s_maxes[0]=*(a_end-1);
}
}
a+=border;a_pos+=border;
There is a good chance that the following scenario happens: before your if the value of a_end is corrupted, highly possibly it gets initialized to 0 (without further knowledge of the code this is my best shot, but it also might be a value which is smaller than a + POS) and then obviously the else branch gets executed which tries to de-reference the value found at address 0 - 1 which is a pretty big number and then the application crashes. Obviously if you remove the else branch this code is not executed.
Hint: Put some printouts for the value of a_end.
I'm new to C++, I have experience with C#, Objective-C and JavaScript.
At the moment I'm trying to write a function that takes a path and returns a directory listing (all files and folders at that path). I'm doing this on Ubuntu.
Here's my code so far, to be honest I'm struggling to understand the double pointer syntax and what it's achieving but this is where my googling has lead me...
int FileManager::GetDirectoryListing(char *path, dirent **directoryEntries)
{
// Debug output...
printf("Listing directory at %s\n", path);
// Allocate memory for the directory entries
*directoryEntries = new dirent[MAX_FILES];
// Open the path we were provided
DIR *directory = opendir(path);
// A counter of how many entries we have read
int entryCount = 0;
// Make sure we were able to open the directory
if(directory) {
printf("Successfully opened directory\n");
// Read the first entry in the directory
struct dirent *directoryEntry = readdir(directory);
// While we have a directory entry
while(directoryEntry) {
// Debug output...
printf("%s\n", directoryEntry->d_name);
// Copy the directory entry to the array of directory entries we will return
memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent));
// Increase our counter
++entryCount;
// Read the next directory
directoryEntry = readdir(directory);
}
// Close the directory
closedir(directory);
}
return entryCount;
}
And then I call this function by:
dirent *directoryEntries = NULL;
int numberOfEntries = FileManager::GetDirectoryListing(deviceRootPath, &directoryEntries);
printf("File Manager returned directory listing.\n");
for(int i = 0; i < numberOfEntries; ++i) {
printf("Looping through directory entries, at index: %i\n", i);
printf("%s\n", directoryEntries[i].d_name);
}
It's locking up when it tries to access the first element in directoryEntries i.e. The first time around the loop.
I know I'm not understanding what the double pointer is doing and I don't have a clear picture in my head about the structure of directoryEntries after the call to GetDirectoryListing.
What is happening and what is the correct way to loop through directoryEntries?
This line
memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent));
should instead be this:
memcpy(&(*directoryEntries)[entryCount], directoryEntry, sizeof(struct dirent));
or equivalently:
memcpy(*directoryEntries + entryCount, directoryEntry, sizeof(struct dirent));
The reason is that directoryEntries is a pointer to a pointer to an array. In memory, it looks like this:
+------------+
directoryEntries --> array_head --> | dirents[0] |
+------------+
| dirents[1] |
+------------+
| dirents[2] |
+------------+
| ... |
But you're treating it like directoryEntries is a pointer to an array, which it is not:
WRONG! +------------+
directoryEntries --> | dirents[0] |
+------------+
| dirents[1] |
+------------+
| ... |
So you're writing out-of-bounds into memory you don't own, resulting in Undefined Behavior.
The reason you need an extra level of indirection is because in C, function parameters are always passed by value. In order to modify a parameter, you need to pass in a pointer to the original value, which is what you're doing. You just have to remember that when dealing with that pointer, you have an extra level of indirection.
If you're using C++ and not C, you would be much better off using a reference parameter instead of a pointer, and you should also use a std::vector<struct dirent>. You don't have the extra level of indirection to worry about, and the memory management is handled for you automatically.
*directoryEntries = new dirent[MAX_FILES];
What if the number of directories is greater than MAX_FILES? How do you know that it cannot be greater than MAX_FILES?
I think you should use std::vector<dirent> instead of dirent*. Many of the problems will be solved.
I would implement the function as:
std::vector<dirent> FileManager::GetDirectoryListing(char *path)
{
std::vector<dirent> dirs;
DIR *directory = opendir(path);
if(directory) {
struct dirent *directoryEntry = readdir(directory);
while(directoryEntry) {
dirs.push_back(*directoryEntry); //push a copy of the original!
directoryEntry = readdir(directory);
}
closedir(directory);
}
return dirs;
}
Modern compilers will most probably optimize this code, to avoiding copy of the return value. This optimization is called:
Return Value Optimization (RVO) (or Named RVO)
Also note that directories.size() will tell you the number of entries. So at call site, you can simply do this:
std::vector<dirent> dirs = FileManager::GetDirectoryListing(deviceRootPath);
for(size_t i = 0; i < dirs.size() ; ++i)
{
std::cout << dirs[i].d_name << std:endl;
}
In general, prefer std::cout over printf, as the latter is not safe!
Your mistake is in this line:
memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent));
Your directoryEntries is pointer to pointers to struct dirent. Each entry in it is a pointer to a struct dirent. Your '&' causes you to copy into the address of a pointer, which is not what you wanted. You want:
memcpy(directoryEntries[entryCount], directoryEntry, sizeof(struct dirent));
When I try to debug the following function segment, the execution brakes (jumps out of the function) at line pCellTower->m_pCellTowerInfo = pCellInfo:
RILCELLTOWERINFO* pCellInfo = (RILCELLTOWERINFO*)lpData;
CCellTower *pCellTower = (CCellTower*)cbData;
if(pCellTower != NULL)
{
pCellTower->m_pCellTowerInfo = pCellInfo;
}
(the pointer pCellInfo is not set)
Then I tried to comment the line:
RILCELLTOWERINFO* pCellInfo = (RILCELLTOWERINFO*)lpData;
CCellTower *pCellTower = (CCellTower*)cbData;
if(pCellTower != NULL)
{
//pCellTower->m_pCellTowerInfo = pCellInfo;
}
and this way the function executes normally.
Does anyone know what could be wrong?
The most likely explanation is that pCellTower isn't set either. It could contain random bits, and end up pointing outside the memory allocated to your app. The OS cannot allow your program to write outside the space allocated to it, so it sends the program some kind of message (Windows:exception, Unix/Linux:signal) that the write was rejected.
If you trace backwards where the cbData value originates from, you'll probably find it is an uninitialized, random value.