vector pop_back causing heap-buffer-overflow error - c++

I'm trying to make a function to validate the parenthesis problem, this function runs well on my machine, but it causing "heap-buffer-overflow" error on leetcode machine when I call vector.pop_back(). Here's the code:
int isValid(string s){
vector<char> st;
for(int i = 0; i < s.length(); i++){
if(s[i] == '(') st.push_back(s[i]);
else{
if(st.back() == '(') st.pop_back(); //this line triggered the error
else return 0;
}
}
return (st.size() == 0);
}
I already solved this by changing the vector into string, but I'm still wondering how can this happened, any explanation anyone?

Calling std::vector::back() on an empty vector is undefined behavior.
Calling back on an empty container causes undefined behavior.
(The same holds for std::vector::pop(), but at that point your program is already in an invalid state if the container was empty).
Therefore, the expression st.back() == '(' on your code might lead to an invalid program state because the container st is not sure being not empty.
Your code path needs to check the emptiness of the container before calling std::vector::back(); something like:
if (!st.empty() && st.back() == '(')
st.pop_back();
else
return 0;
Bonus Note: the code above exploits logical operators short circuit evaluation. It means that the second operand (i.e., the expression st.back()) will not be invoked if the container is empty.

maybe because you didn't assign any element in the vector before checking on the if condition. Try putting :
if(st.size()!=0)
{
if(st.back() == '(') st.pop_back();
else return 0;
}
on that piece of code

Related

C++ vector iterator not incremental

I've been having a headache with this problem. I've challenged myself to make a CLI space shooter, where you have you spaceship, lasers and meteors to shoot. The problem is this: whenever a laser or a meteor reaches the boundaries of our arena, I want to erase from the vector so that it wouldn't cluster it up. Here's how my working code looks now:
std::vector<Meteoras>::iterator itMet = meteorai.begin();
std::vector<Lazeris>::iterator itLaz = lazeriai.begin();
while (itMet != meteorai.end() || itLaz != lazeriai.end())
{
if (itLaz != lazeriai.end())
{
if (itLaz->getCoord()->x == j && itLaz->getCoord()->y == i)
{
itLaz->move();
++j;
if (itLaz->getCoord()->x >= ILGIS - 1) continue;
else std::cout << itLaz->getIcon();
}
++itLaz;
}
if (itMet != meteorai.end())
{
if (itMet->getCoord()->x - 1 == j && itMet->getCoord()->y == i)
{
itMet->move();
++j;
if (itMet->getCoord()->x <= 0) continue;
else std::cout << itMet->getIcon();
}
++itMet;
}
}
So there are two "continues" in there. Instead of them I tried placing iterator removals (as in itLaz = lazeriai.erase(itLaz) but that the program seemed to crash during runtime giving the error that I stated before. I tried doing other logical checks but that didn't seem to work either. I would appreciate if someone could explain a proper way of removing a useless object (in this case a meteor/laser) from a vector.
The comment about erase() invalidating an iterator is true. The part about needing to restart at the beginning is wrong. (You could do, but you certainly don't need to.)
erase() returns a still-valid iterator which points to the element after the erased item.
if( test for erasing )
{
itLaz = lazeriai.erase(itLaz);
}
else
{
++itlaz;
}
You might be able to refactor your code to use std::remove_if() instead.

Mysterious segmentation fault on function return with no pointers or allocation involved

I am currently writing some C++ code that does a lot of text parsing. One feature pushes chars into a string after checking if the char is a visible char (as opposed to whitespace). However, when I run the code below:
void myWords::pushChar(char c){
myChar cc;
std::cout<< "before if" <<std::endl;
if(!(cc.isWS(c))){
std::cout<< "after if" <<std::endl;
myList.back();
}
else if((myList.back()).size()>0){
myList.push_back("");
}
}
Which calls the following code block:
bool myChar::isWS(char c){ // returns true if char is whitespace
std::cout<< "comparing" <<std::endl;
if((c >= '!') && (c <= '~')){
std::cout<< "compared" <<std::endl;
return false;
}
else {
std::cout<< "compared" <<std::endl;
return true;
}
}
When these functions run, I (sometimes) get a segmentation fault immediately after the "compared" is printed by myChar::isWS(). There are no pointers/dereferences in my code (although I assume C++ implements STL containers with some pointing behind the scenes), and there is no memory accessing at that point aside from the return call. I ran Valgrind with the code, which has told me that there is an invalid memory access taking place.
What types of things could cause this kind of issue with no pointers/dereferences? Is there some way I could have corrupted the stack with that code?
Thank you in advance for your help.
Your error looks like you are calling size on non-existent object returned when you have an empty list. I.e in the second if statement. You need to check for an empty list before you can use back () safely.
I am guessing you want to something like this
void myWords::pushChar(char c)
{
if( !isWhitespace (c) )
{
myList.push_back(c);
}
else
{
if( !myList.empty() && (myList.back().size()>0) ) // is last element a non-empty string ?
{
myList.push_back(""); // then push an empty string on to list
}
}
}
It would be helpful to know how myList is declared and what the intended logic is in pushChar.

Unexplained Behavior with std::vector

In Stepping through some weird segmentation fault causing code, I found that after the assignment of one vector to another, the receiving vector arbitrarily corrupts. The following is a code snippet from a copy constructor of a class which has a data member vector<Piece> *pieces which is a dynamically allocated array containing vectors of type Piece.
ClassName::ClassName(const Class &other) // copy constructor of class
{
...
for(SIDE_t s = 0; s < sides; s++)
{
pieces[s].reserve(other.pieces[s].size());
pieces[s] = other.pieces[s]; //vector is completely valid here
for(Uint8 p = 0; p < pieces[s].size(); p++)
{
//it continues validity throughout loop
if(other.pieces[s][p].getCell() != NULL)
pieces[s][p].setCell(cells + (other.pieces[s][p].getCell() - other.cells));
if(pieces[s][p].getCell() == NULL)
out.push_back(&pieces[s][p]);
}
if(other.flags[s] != NULL)
flags[s] = getPiece(other.flags[s]->getValue(), other.flags[s]->getSide());
// vector is invalid in scope of getPiece, which receives completely valid arguments
else
flags[s] = NULL;
}
}
Piece * const ClassName::getPiece(const Uint8 num, const SIDE_t s) const
{
return (num>nPieces || s>sides || num == 0)? NULL:&pieces[s][num-1];
// Right here during the member access function of pieces,
// it is clear that the vector was corrupted some how
}
Essentially during debugging, I would step into pieces[s] member access function. In the loop body, it is evident that m_start has a valid address, however when it exits the loop body and calls the index operator on pieces[s] in getPiece, m_start is NULL. There are no operations performed on pieces[s] between the last iteration of the loop when m_start is valid, and in getPiece when during the same call of the index operator as in the loop body, m_start is NULL. Any insight on my misuse of std::vector or bugs in std::vector would be appreciated.
It looks to me that you have an access violation here:
return (num>nPieces || s>sides || num == 0)? NULL:&pieces[s][num-1];
First (as pointed out by Petr), it should read s>=sides.
Second, s here is not the same as s in the caller. So pieces[s] may not have been assigned yet and is an empty vector. To test it use
return (num>nPieces || s>=sides || num == 0)? NULL : &(pieces[s].at(num-1));
Btw, all this would have been avoided had you simply used
std::vector<std::vector<Piece>>
and copied the whole thing.

C++ char-by-char comparison of a string

I'm trying to work on a string comparison check for an introductory C++ course; it's an online course and unfortunately the instructor is not very responsive. For a current lab, I need to perform a number of manipulations on string data.
Currently, I'm working on a step to check if a string has any repeated characters, and if a repetition is found, to delete the repeated characters at their present spot and move one copy of the letter to the beginning of the string. This is only to be done for the first double to be found.
I've set up a basic counter to move through the string looking for matches, checking a stored character (updated on each iteration) to the current position in the string.
I tried multiple string functions (comparing the current inputString[i] to the previous such, stored as a second string tempStore), but those always gave char conversion errors. I've tried the below instead, but this is now giving an error: "invalid conversion from 'char' to 'const char*'.
inputString is given by the user, testA and testB are defined as type char
Any ideas?
while (opComplete == false) {
if (i == 0) {
i++;
}
else if (i == inputString.size()) {
//Not Found
opComplete = true;
}
else if (i > 0) {
testA = inputString[i-1];
testB = inputString[i];
if (strcmp(testA,testB) != 0) {
i++;
}
else {
inputString.insert(0,inputString[i]);
inputString.erase(i,1);
inputString.erase(i-1,1);
opComplete = true;
}
}
}
Your problem is in this line:
inputString.insert(0,inputString[i]);
The std::string.insert() function the way you call it here has the following signature:
string& insert ( size_t pos1, const char* s );
so it expects a const char pointer. You, however, are giving it the inputString[i]. The return value of std::string.operator[] is a reference (as here), hence the error. However, by the time you reach your else, you already have the desired character in your testB variable, so you can just change the line to
inputString.insert(0, &testB);
You also can't pass normal chars into strcmp. You can use operator==, or, in your case, operator!= though.
You are using the insert method incorrectly, check its reference here for possible arguments.
while (opComplete == false)
{
if (i == 0)
i++;
else if (i == inputString.size())
opComplete = true;
else if (i > 0) {
char testA = inputString[i-1];
char testB = inputString[i];
if(testA!=testB)
i++;
else {
inputString.insert(0,&testB); //Problem Corrected here.
inputString.erase(i,1);
inputString.erase(i-1,1);
opComplete = true;
}
}
}

Valgrind detects invalid read error in simple Iterator class

Valgrind detects an invalid read error I don't know how to fix or to be more precise: I don't know what the problem is.
Invalid read of size 8
at 0x443212: std::vector<Tile*, std::allocator<Tile*> >::end() const
by 0x44296C: Collection<Tile*>::Iterator::operator++()
The Iterator class is very simple (and actually a somewhat bad piece of programming) but sufficient for my needs right now. I think there are three methods you should know to hopefully help find my problem:
Iterator(size_t x, size_t y, const TileCollection& tiles)
: mTiles(&tiles)
, mX(mTiles->begin())
, mY(mTiles->at(x).begin())
{
std::advance(mX, x);
std::advance(mY, y);
bool foundFirst = false;
while (!foundFirst)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundFirst = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
}
Iterator Iterator::operator++()
{
bool foundNext = false;
++mY;
while (!foundNext)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundNext = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
return *this;
}
void TileCollection::add(Tile* tile)
{
Point2D p(tile->getPosition());
std::vector<Tile*> tmp(1, (Tile*)0);
if ((size_t)p.x >= mTiles.size())
mTiles.resize(p.x + 1, tmp);
if ((size_t)p.y >= mTiles.at(p.x).size())
mTiles.at(p.x).resize(p.y + 1, (Tile*)0);
mTiles.at(p.x).at(p.y) = tile;
++mNumTiles;
}
The actual code that is causing the valgrind error is the line:
while (mY != mX->end() && *mY == 0) ++mY;
...of the Iterator::operator++ method.
It looks to me that, at the least, the following line in operator++
if (mX != mTiles->end()) mY = mX->begin();
is lacking a suitable else-clause.
Consider what happens when mX actually reaches mTiles->end(): You will enter a new iteration of the outer while loop; the first line in that loop (the line that causes the Valgrind error) will evaluate mX->end() and thus attempt to dereference mX -- but mX is mTiles->end(), and it's not correct to dereference the end iterator of a collection since it doesn't actually reference an element of the collection. It looks to me as if this may be the cause of your Valgrind error.
(Note that the constructor contains essentially the same code.)
More generally, I think you need to think about how you handle reaching the end of your two-dimensional array. How does the client of your Iterator check whether it has reached the end of the iteration? How do you expect your operator++ to handle the case when it reaches the end of the two-dimensional array? Should it protect itself against getting called too often?
You can try to split up the statement in order get find out where the error occurs:
while (mY != mX->end()) // maybe here
{
if (*mY != 0) // maybe here
{
break;
}
++mY; // maybe here
}
Compiling with GCC compiler option -fno-inline helps to get a nicer stack-trace, which can help you to trace the error. It will also make your program very slow, so don't forget to remove it later.