std::list.splice() causes program to crash - c++

I looked at a few examples and as far as I can tell I'm using the splice method correctly. However, when I run the program in debug mode under Visual C++, the call stack shows my call to splice eventually reaches this line where it crashes:
_Mynextiter = _Parent_proxy->_Myfirstiter;
The code:
for(std::list<Rect>::iterator i = rects.begin(); i != rects.end();)
{
if(i->isOverlapping(newRect))
{
Rect oldRect = (*i);
i = rects.erase(i);
std::list<Rect> & lr = oldRect.split(newRect);
//doesn't work either
//rects.splice(rects.begin(), lr, lr.begin(), lr.end());
rects.splice(rects.begin(), lr);
}
else i++;
}

It seems you are using std::list<T>::splice() the right way, if I refer to any manual pages on the internet.
At the contrary, I don't really like the reference in the line:
std::list<Rect> & lr = oldRect.split(newRect);
I don't know what is doing Rect::split() but you should try to copy its result. Does that help?

Related

stack overflow on stepping into a function

I'm getting a stack overflow error when I step into a function in debug mode using VS 2015. Here's the exact message, in case that helps:
Unhandled exception at 0x0000000140D9F018 in TestProgram.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000000213000).
The function I'm entering looks like this:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
Here's what's confusing me:
I'm stepping into the function, so I don't think there can be any recursion going on. When I get the stack overflow error, it's on the opening bracket of the function - none of the lines of the function are even getting called.
When I comment out this line in the 'else if' section:
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
then not only does the stack overflow error go away, but the function runs as expected, executing the `if' block successfully (so it successfully creates a 'cereal::XMLInputArchive', loads it from the stringstream, etc).
In both cases (when the function runs, and when it causes a stack overflow), it's getting called with the same input parameter (about 300 chars of base64 encoded xml).
So, somehow, when I compile with all the code uncommented, I cause something to go wrong with the function's execution/memory allocation, but I don't understand what.
Oh yeah, in case this helps, the call stack has this on top when I get the stack overflow error:
TestProgram.exe!__chkstk()
Other than that, it looks the same as when the function runs successfully (that also leads me to think there's no recursion).
[Edit]
After searching for __chkstk(), I just found/read this SO article:
What is the purpose of the _chkstk() function?
That's making me think that this is not a traditional stack overflow error, where I'm asking for too much memory, rather that something in the function is trying to reference an illegal place in memory, which is causing VS to report a stack overflow. But, I'm still not sure why/how that could happen if the function isn't even executing, since that block won't run.
Thanks in advance for any insight as to what could cause this type of behavior.
I have a bad feeling that I'm missing something fundamental about function calling.
Turns out that _chkstk() throws a stack overflow when you have exceeded the declared maximum stack size declared in an .exe build. Your solution then? Increase it. Though also consider removing the bit of redundancy in your code:
First, consider that upon entering the function, we need to ensure that there is enough space for all local variables of your function on the stack. Let's look at what those are:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
/* two variables here */
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
/* two more variables here */
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
/* and a final pair */
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
Now consider that you find the _chkstk() variable on the call stack to begin with. This implies that this function allocates a lot of memory! That commenting out a single declaration resolves the problem points to the greedy memory culprit. But wait, you have two of these, and that you can get away with one implies that consolidating your duplicated declaration might pay dividends:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
/* single declaration*/
cereal::XMLInputArchive arSettingsObject;
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
Although this changes the scope on arSettingsObject, it isn't a problem because the function terminates after the if/else statement and all return paths from where it is declared require it.

C++ VS Debugger diverting behaviour?

I'm currently struggling to debug the following code part. I'm using VS2015 community edition on windows 10.
[(BR)] is a breakpoint
The following is a (slimmed down) version of my code. I basically have nested for loops that extract all points (X&Y coordinates) from all gameObjects.
As you can see I set two breakpoints.
I hit the debug button and it stops at the first breakpoint - success. Important local variable counterVertices is zero. Great as well.
Then I hit continue. It goes TO THE SAME BREAKPOINT THREE TIMES.
Then I get to the second breakpoint. counterVertices shows zero. Why?
int counterVertices = 0;
int counterIndices = 0;
int beginningOfPolygon = 0;
//GetData
for (auto& it : this->gameObjects) { //Iterate over all gameObjects
beginningOfPolygon = counterIndices;
for (int i = 0; i < it->getOutline().getNumber(); i++) { //Iterate over all points of the gameObject
[(BR)]this->vertices[counterVertices] = it->getRenderPoint(i).x;
counterVertices++;
this->vertices[counterVertices] = it->getRenderPoint(i).y;
counterVertices++;
[(BR)]if (this->vertices[counterVertices-2] == this->vertices[counterVertices-1] && this->vertices[counterVertices-1] == 0.0f) {
cout << "A point on 0/0." << endl;
}
this->vertices[counterVertices] = 0.0f;
counterVertices++;
//Add Line to draw
this->indices[counterIndices * 2] = counterIndices;
this->indices[(counterIndices * 2) + 1] = counterIndices + 1;
counterIndices++;
}
this->indices[(counterIndices * 2) - 1] = beginningOfPolygon;
}
I'm completely lost as this isn't even the problem I wanted to solve in the first place but rather got stuck on trying to figure on my original issue.
Thanks already for your time
PS: I have screenshots of the whole thing and the process is recreatable. I can clean and rebuild the solution, restart and do a backflip. Debugging behaviour doesn't change.
PPS: The program behaves/works in a way that suggest that counterVertices is increased correctly but the debugger information contradicts that.
Make sure you have optimizations turned off. Optimizations can really make it hard to debug, as values will be held in registers and not stored until it needs to. And code flow can be very unintuitive.

Random' crashes when using delete

I'm trying to write my first simple game using C++ and Allegro 4.2.3, but I'm getting crashes that sometimes occur when I change the game-state. When a state is started it uses the 'new' operator to make it, and then uses 'delete' before switching to the next one. I'm not sure if I fully understand using the new and delete operators, though! Here's a selection of code:
enum //Game state
{
TITLE_SCREEN, CUTSCENE_1
};
int main(void)
{
const int screenwidth = 800;
const int screenheight = 600;
bool quit = false;
int state = TITLE_SCREEN;
int oldstate = -1;
int oldoldstate;
init(screenwidth, screenheight);
install_int(counter, (1000/FPS));
TitleState *Title;
Cutscene *Scene1;
srand (time(NULL));
while (!quit)
{
while(tick == 0)
{
rest(1);
}
while(tick > 0)
{
oldoldstate = oldstate;
oldstate = state;
switch(state)
{
case TITLE_SCREEN:
//If the last state is different to this one, create the state
if(oldoldstate != TITLE_SCREEN)
{
Title = new TitleState();
}
//Run the program in the state
Title->Play();
//Check the state to see if it has changed
state = Title->CheckState();
//If the state has changed, delete the current state
if(oldstate != state)
{
delete Title;
}
break;
case CUTSCENE_1:
if(oldoldstate != CUTSCENE_1)
{
Scene1 = new Cutscene(); //SOMETIMES CRASHES BEFORE HERE
}
Scene1->Play();
state = Scene1->CheckState();
if(oldstate != state)
{
delete Scene1;
}
break;
case EXIT:
quit = true;
break;
default:
allegro_message("Game state not found!");
exit(-1);
}
int oldtick = tick;
tick--;
if(oldtick <= tick)
break;
}
}
deinit();
return 0;
}
When the program crashes, VS2010 opens up thread.c to show where the error was:
static void _callthreadstart(void)
{
_ptiddata ptd; /* pointer to thread's _tiddata struct */
/* must always exist at this point */
ptd = _getptd();
/*
* Guard call to user code with a _try - _except statement to
* implement runtime errors and signal support
*/
__try
{
( (void(__CLRCALL_OR_CDECL *)(void *))(((_ptiddata)ptd)->_initaddr) )
( ((_ptiddata)ptd)->_initarg ); //ERROR HERE (Next statement to be executed)
_endthread();
}
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
/*
* Should never reach here
*/
_exit( GetExceptionCode() );
} /* end of _try - _except */
}
I would greatly appreciate any help, because I'm not sure at all what the problem is.
Thanks for the help and suggestions, they are interesting and useful to know! However, I think the solution to my problem was to use a newer version of the Allegro library - I was told to use 4.2.3 for this but moving to 4.4.2 has removed this problem as far as I can tell!
Well new is to allocate memory from the heap, and delete is to release it.
You can not delete (release) the same memory twice. You can go through some tutorial about new/delete.
Though I have not gone through your code, but here are few things you can do,
1) run your code in gdb (to get a stacktrace of your crash, it will tell most of the things to you).
2) If it is because of new/delete, then may be it is because of double free, there are other reasons why new/delete may fail.
3) You can keep a count of number of times new/delete gets called, you can override new/delete and write your own new/delete routine.
4) If you can not do anything of the above, then simply write printf statements to get to know where it is failing. printf may not be always reliable, you can use fflush().
This is a tiny fraction of the code of the program and it's hard to tell what it could be wrong.
This happens because C++ has the concept of "undefined behavior" and when you do something wrong (like for example deleting the same object twice) you cannot rely on the fact that an error will be raised immediately, but what happens is instead that something else, even unrelated, may behave strangely later (even millions of instructions executed later).
One of the basic assumptions of the language is that programmer don't do this kind of error (go figure!).
It's perfectly possible that you made a mistake in other parts of the code and you see the error in that delete call, that is however just the "victim" of what happened, not the point where the problem is.
There are some general rules that can help preventing allocation/deallocation errors (like using standard containers instead of naked pointers and follow the rule of the "big three").
Every time you write an instruction in a C++ program you should think a lot, because if you let a logical bug in it will be very very hard to remove it later. This is less of an issue in languages where "undefined behavior" is not present at language level.

OpenCL Out of Resources - Crash at code line which is not reached at that moment

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.

Why the functions doesn't execute completely?

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.