Segmentation fault? - c++

I've got at some code that should be recursively covering all positions on a boggle board. But for some reason it throws a segmentation fault after finding only 2 words? Any ideas why that would happen?
The code probably throwing the fault:
//++++++++++++ Find Word ++++++++++++++//
void findword(vector<vector<tile> > board, unsigned int row, unsigned int col, set<string> &results, unsigned int board_width, string word, set<string> dictionary)
{
if(checkbound(row, col, board_width) == false) // If tile is outside of the boundary than do nothing
return;
if(board[row][col].getused() == true) // If tile has already been used than do nothing
return;
word = word + board[row][col].getvalue(); // Adds letter to word
//Check Prefixes
set<string>::iterator pos;
pos = dictionary.lower_bound(word); // Creates an iterator at position
if(pos== dictionary.end()) // If it reaches the end without finding word than do nothing
{
return;
}
else if(word == pos->substr(0,word.length()))
{
cout<<"word: " <<word<<endl;
cout<<"dict: " <<*pos<<endl;
if(word == *pos) // If word = word at prefix
{
cout<< word<<" word inserted"<<endl;
results.insert(word); // Add words to results set
}
}
else
return;
//set to used
board[row][col].setused(true); // set tile to used
findword(board, row-1, col-1, results, board_width, word, dictionary); // Checks all tiles around every tile
findword(board, row-1, col, results, board_width, word, dictionary);
findword(board, row-1, col+1, results, board_width, word, dictionary);
findword(board, row, col-1, results, board_width, word, dictionary);
findword(board, row, col+1, results, board_width, word, dictionary);
findword(board, row+1, col-1, results, board_width, word, dictionary);
findword(board, row+1, col, results, board_width, word, dictionary);
findword(board, row+1, col+1, results, board_width, word, dictionary);
board[row][col].setused(false); // set tile to not-used
}
Error given:
word: r
dict: riot
word: ro
dict: robot
word: rob
dict: robot
word: robo
dict: robot
word: robot
dict: robot
robot word inserted
word: roo
dict: root
word: root
dict: root
root word inserted
Segmentation fault (core dumped)
Valgrind's main error code:
==4629== Invalid read of size 1
==4629== at 0x407C2E: tile::getused() (tile.cpp:33)
==4629== by 0x401ACE: findword(std::vector<std::vector<tile, std::allocator<tile> >, std::allocator<std::vector<tile, std::allocator<tile> > > >, unsigned int, unsigned int, std::set<std::string, std::less<std::string>, std::allocator<std::string> >&, unsigned int, std::string, std::set<std::string, std::less<std::string>, std::allocator<std::string> >) (main.cpp:58)
==4629== by 0x4020EC: findword(std::vector<std::vector<tile, std::allocator<tile> >, std::allocator<std::vector<tile, std::allocator<tile> > > >, unsigned int, unsigned int, std::set<std::string, std::less<std::string>, std::allocator<std::string> >&, unsigned int, std::string, std::set<std::string, std::less<std::string>, std::allocator<std::string> >) (main.cpp:93)
==4629== by 0x4020EC: findword(std::vector<std::vector<tile, std::allocator<tile> >, std::allocator<std::vector<tile, std::allocator<tile> > > >, unsigned int, unsigned int, std::set<std::string, std::less<std::string>, std::allocator<std::string> >&, unsigned int, std::string, std::set<std::string, std::less<std::string>, std::allocator<std::string> >) (main.cpp:93)
==4629== by 0x401F78: findword(std::vector<std::vector<tile, std::allocator<tile> >, std::allocator<std::vector<tile, std::allocator<tile> > > >, unsigned int, unsigned int, std::set<std::string, std::less<std::string>, std::allocator<std::string> >&, unsigned int, std::string, std::set<std::string, std::less<std::string>, std::allocator<std::string> >) (main.cpp:91)
==4629== by 0x402264: findword(std::vector<std::vector<tile, std::allocator<tile> >, std::allocator<std::vector<tile, std::allocator<tile> > > >, unsigned int, unsigned int, std::set<std::string, std::less<std::string>, std::allocator<std::string> >&, unsigned int, std::string, std::set<std::string, std::less<std::string>, std::allocator<std::string> >) (main.cpp:95)
==4629== by 0x402BF0: main (main.cpp:185)
==4629== Address 0x4c3b178 is 8 bytes after a block of size 48 alloc'd
The Checkbound function:
//+++++++++++ Check Bounds ++++++++++++//
bool checkbound(unsigned int row, unsigned int col, unsigned int board_width)
{
if(row < 0 || row > board_width || col < 0 || col > board_width)
return false;
else
return true;
}
board:
r b o
o i t
r o h

What value of board_width? If this is 3, then you forgot that indexing starting from 0 and maximum available index is 2, so condition in checkbound function must be:
if(row < 0 || row >= board_width || col < 0 || col >= board_width)

My guess is that your problem is in your checkbound function. You do the following:
row > board_width
I'm not sure how you're counting the width, but I believe your problem is here. A vector with a size of 3 will be the indices:
myVec[0], myVec[1], myVec[2].
If in this example, you are saying the board_width is 3, this will cause your segfault.

Related

C++ "Segmentation fault" or "free(): invalid pointer" depending on input (reproducible)

This program gives a "Segmentation fault" or a "free(): invalid pointer" based on the input file used. The bug is reproducible.
This is very strange especially because free is not called.
Here is the complete program.
// Open a file, read line by line,
// and for each (loooong) line, fraction it into
// small, justified lines.
// Justification done by adding spaces to existing spaces.
#include <iostream>
#include <iterator>
#include <sstream>
#include <fstream>
#include <list>
#include <vector>
#include <math.h>
#include <random>
#include <functional>
const int pageWidth = 50; // max width for a (justified) line
typedef std::vector<std::string> WordList;
typedef std::vector<int> SpaceList;
// ========
// HELPERS
// ========
// Helper to return "cccccc...ccc"
std::string repeat (const int n, char c) {
std::string ret;
for (int i{0}; i < n; ++i) {
ret += c;
}
return ret;
}
// "Random" int between min and max (pseudo-random: reproducible)
unsigned int random_pred(std::size_t salt, unsigned int min, unsigned int max) {
unsigned int output = min + (salt % static_cast<int>(max - min + 1));
return output;
}
// alpha is greater at center
float alpha_weight(float z) { return std::max(100*(sin(z))*(sin(z)), float(1)); }
// Weight of a space, ie probability to add here blank space
int weight(int x, unsigned int l)
{
float z = 3.141 * x / l;
return alpha_weight(z);
}
// line -> vector of words
WordList splitTextIntoWords( const std::string &text )
{
WordList words;
std::istringstream in(text);
std::copy(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(words));
return words;
}
// ======
// CORE
// ======
// Give each space a weight, a 'probability' to be expanded
SpaceList charge_spaces ( int l, const WordList & words, SpaceList spp)
{
SpaceList sp_weights;
std::string p{ words[0] }, h;
int wg;
for (size_t i = 0; i < words.size()-1; ++i) {
wg = weight(spp[i], l);
sp_weights.push_back(wg);
}
return sp_weights;
}
// Given weighted list of spaces positions, 'randomly' pick one
int random_sp( const SpaceList& spw, std::size_t salt ) {
std::string m;
unsigned int i{48}, total{0}; // ASCII 48 = ' '
for (const int & n : spw) {
char ch = static_cast<char>(i); // '1'; '2'; '3' ...
std::string segment = repeat(n, ch); // "11"; "2222"; "3333333333333" ....
m += segment;
total += n;
++i;
} // now, m like "11112222222222333333333333333333334444444455555", of length <total>
int mqrh = random_pred(salt, 0, total); // Get 0 <= random <= total
char iss = m[mqrh]; // Read the char at this position (for example, more likely '3' here)
int ret = static_cast<int>(iss) - 48; // Example: '3' -> 3
return ret; // Example: return 3
}
// Add spaces to a (small) line, to justify it.
// We need to expand it by <excess> spaces.
std::string justifyLine( std::string line, WordList ww, SpaceList space_positions, int excess )
{
SpaceList spwg = charge_spaces(line.size(), ww, space_positions);
SpaceList spadd{spwg.begin(), spwg.end()}; // number of spaces to add after word <i>
for (size_t k = 0; k < ww.size()-1; ++k) {
spadd[k] = 1; // By default, 1 space after each word
}
int winner; // Which space will win additional space ?
std::size_t str_hash = std::hash<std::string>{}(line) / 1000; // 'random' seed, reproducible
for (int i{0}; i < excess; ++i) { // Where to add these <excess> needed spaces ?
std::size_t salt = str_hash + 37*i;
winner = random_sp(spwg, salt);
spadd[winner] = spadd[winner] + 1; // space after <winner> word is incremented !
spwg[winner] = std::max( spwg[winner] / 10, 1); // Weight of winner is decreased
}
// Build up the justified line
std::string justified;
for (size_t j = 0; j < ww.size()-1; ++j) {
justified.append(ww[j]); // Add next word
justified.append(spadd[j], ' '); // Add few spaces
}
justified.append(ww.back()); // Add last word
std::cout << justified << std::endl;
return justified;
}
// Fraction a long line in several justified small lines
void justifyText( const std::string& text )
{
WordList words = splitTextIntoWords(text);
std::string line;
WordList ww;
SpaceList space_positions;
int position{0};
int nwords_in_line{0};
for (const std::string& word : words) {
size_t s = word.size();
if (line.size() + s + 1 <= pageWidth) { // next word fit into the line.
if (!line.empty()) {
line.append(" ");
space_positions.push_back(position++);
}
line.append(word);
nwords_in_line++;
ww.push_back(word); // append this word to the list
position += s;
} else { // build a justified small line from the words added up
justifyLine(line, ww, space_positions, pageWidth - position);
line.clear(); // Cleaning for next chunk
ww.clear();
space_positions.clear();
line = word;
position = s;
nwords_in_line = 1;
ww.push_back(word); // don't forget the last word (that overflowed)
}
}
std::cout << line << std::endl; // Remaining of the long line
}
// =====
// main
// =====
int main () {
std::string line;
std::ifstream myfile ("candle.txt");
if (myfile.is_open())
{
while ( getline(myfile,line) )
{
justifyText(line);
}
myfile.close();
}
else std::cerr << "Unable to open file";
return 0;
}
File "candle.txt" is an ASCII text file, here is a copy.
The whole file gives free(): invalid pointer, always at same position -- see below (1)
If cutting between the two markups in the PREFACE (deleting the chunk between the two CUT HEREmarks), program gives a Segmentation fault.
Running with Valgrind gives this (very strange because repeat function does not seem problematic)
Thread 1: status = VgTs_Runnable (lwpid 4487)
==4487== at 0x4838DEF: operator new(unsigned long) (vg_replace_malloc.c:342)
==4487== by 0x4990859: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==4487== by 0x4990F34: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator+=(char) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==4487== by 0x10A406: repeat[abi:cxx11](int, char) (in /home/fig/Documents/cpp/cil)
==4487== by 0x10A8DD: random_sp(std::vector<int, std::allocator<int> > const&, unsigned long) (in /home/fig/Documents/cpp/cil)
==4487== by 0x10AB34: justifyLine(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::vector<int, std::allocator<int> >, int) (in /home/fig/Documents/cpp/cil)
==4487== by 0x10AF71: justifyText(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /home/fig/Documents/cpp/cil)
==4487== by 0x10B195: main (in /home/xxx/Documents/cpp/cil)
Any idea welcome
(1) End of output:
We have several tests for oxygen besides the mere
burning of bodies. You have seen a candle burnt in
oxygen, or in the air; you have seen phosphorus
burnt in the air, or in oxygen; and you have seen
iron-filings burnt in oxygen. But we have other
tests besides these, and I am about to refer to
one or two of them for he purpose of carrying
The crash occurs as a result of a consequence from an earlier bug. There's nothing (directly) wrong with any of the code in your backtrace. Although the bug effectively was traced to one of the function the actual crash was triggered from an earlier invocation of the same code, and the actual bug would be triggered later, after returning from the point of the crash.
One of my stock comments starts with: "Just because this is where the program crashes or reports an error doesn't mean this is where the problem is. C++ does not work this way." This is followed by explanation that a minimal reproduce example must be provided, which you mostly did. This allowed the problem to be reproduced trivially. The first instance of undefined behavior occured elsewhere, on line 109:
spadd[winner] = spadd[winner] + 1;
valgrind has a very useful option: --vgdb-error=1. This stops execution immediately when valgrind detects memory corruption, on this line, in this case. valgrind then gives instruction for attaching to the current process, with gdb. Doing so immediately led to the observation that this value of winner was -48. Modifying spadd[-48] will only result in tears.
At this point it wasn't too difficult to backtrack to line 91, where -48 came from, which led to the actual bug, an off by 1:
int mqrh = random_pred(salt, 0, total);
total here was always the same as m.size(), and this duplicate logic resulted in the bug, since this parameter should be the last value in the range for random_pred, and not one past it. The expected results here is to pick a random character from m, so the valid range is 0 to m.size()-1. If it wasn't for the duplicated logic, being mindful of how random_pred()'s parameters must be defined, the last parameter would've naturally be m.size()-1. But the duplicated logic resulted in an indirect reference to the underlying value, total, and this detail was forgot.
Another contributing factor to common kinds of bugs is going against the natural flow of how C++ defines ranges and sequences: not by the minimum and the maximum value, but the minimum and one past the maximum value. std::string::size(), std::vector::size, et. al., is one past the last valid index of the underlying container, and not the last valid index of the container. Similarly, end(), the ending iterator is not the iterator for the last value in the sequence, but the iterator to the next, non-existent value in the sequence, "one past it".
If random_pred was designed in harmony with the rest of the C++ library, its formula would simply involve min + salt % (max-min) instead of min + salt % (max-min+1). Then it wouldn't matter if its third parameter was total or m.size(), it would've naturally worked either way.

Can't find cause of Invalid free() / delete / delete[] / realloc()

I am writing HTTP client in C++. When I was testing my program he crashed with this error:
*** Error in `./isabot': free(): invalid pointer: 0x00007ffe7f8d2600 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x81299)[0x7fef1fd86299]
./isabot[0x408eca]
./isabot[0x409afe]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fef1fd27555]
./isabot[0x402d59]
======= Memory map: ========
.
.
.
I reran my program with valgrind -v and I got this error:
==20879== Invalid free() / delete / delete[] / realloc()
==20879== at 0x4C2B18A: operator delete(void*) (vg_replace_malloc.c:576)
==20879== by 0x408EC9: sendRequest(ssl_st*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /homes/eva/xm/xmimoc01/ISA/isabot)
==20879== by 0x409AFD: main (in /homes/eva/xm/xmimoc01/ISA/isabot)
==20879== Address 0x1ffeffee00 is on thread 1's stack
==20879== in frame #1, created by sendRequest(ssl_st*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (???:)
==20879==
When I started my program without valgrind, the program crashed on this. But, when I started my program with valgrind, it wrote to me an error and the program continued successfully without repetition this error.
My function sendRequest() looks like:
string sendRequest(SSL *ssl, int requestType, const string &botToken, const string &guildId, const string &channelId, const string &lastMessageId, const string &content)
{
const char *request;
string strRequest;
stringstream response;
string isChunked;
char buffer[BUFFER];
if (requestType == GET_CLIENT_ID) {
strRequest = createIDRequest(botToken);
}
else if (requestType == GET_GUILDS) {
strRequest = createGuildsRequest(botToken);
}
else if (requestType == GET_CHANNELS) {
strRequest = createChannelRequest(botToken, guildId);
}
else if (requestType == GET_MESSAGES) {
strRequest = createMessagesRequest(botToken, channelId);
}
else if (requestType == GET_ACTUAL_MESSAGES) {
strRequest = createActualMessagesRequest(botToken, channelId, lastMessageId);
}
else if(requestType == POST_SEND_MESSAGE) {
strRequest = createSendMessageRequest(botToken, channelId, content);
}
request = strRequest.c_str();
SSL_write(ssl, request, strlen(request));
while(true) {
memset(buffer, 0, sizeof(buffer));
int n = SSL_read(ssl, buffer, BUFFER);
if(n >= 0) {
buffer[n] = '\0';
}
if (n <= 5) {
break;
};
response << buffer;
if (isResponseChunked(response.str()) != true) {
break;
}
}
return response.str();
}
and I called it from main.cpp in part of code where it crashed like this:
string sendedMessage = sendRequest(conn.ssl, POST_SEND_MESSAGE, botToken, "", channelId, "", content);
buffer[n] = '\0'; will write past the end of buffer when n == BUFFER. This overwrites some part of the stack, likely snother local variable. If it is one of the string variables, the internal state is corrupted which could result in this error.
The simple fix is to allocate one additional character in buffer.
char buffer[BUFFER+1];
Alternatively, you could read one less byte in the call to SSL_read.

C++ Get length of const char* [ ] in vector [duplicate]

This question already has answers here:
How to get the real and total length of char * (char array)?
(15 answers)
Closed 4 years ago.
How do I get the length of const char* arrays indexes?
The vector:
std::vector<const char*> _infoBarText;
The const char* []:
const char* text[4] = {"Current T:", "Target T:", "Time elapsed:", "Time remaining:"};
Assigning the char array to the vector:
_infoBarText.assign(text, text+4);
How can I get the length of the individual strings, like "current T", from the vector?
Raw C strings (bare char*-s) are not a perfect fit for modern C++ code.
If you change it to std::vector<std::string_view> you get your problem solved without (virtually) any overhead (given you are initializing it with literals) and as a bonus you will potentially make it safer and more usable.
See the cppreference article for details.
Example (GodBolt):
#include <string_view>
#include <vector>
#include <iostream>
int main() {
using namespace std::literals;
std::vector<std::string_view> strs = { "hello"sv, "there"sv };
for (auto&& str: strs)
std::cout << str << str.size();
return 0;
}
GodBolt Code Insight Output (note the std::operator""sv("hello", 5ul)):
#include <string_view>
#include <vector>
#include <iostream>
int main()
{
using namespace std::literals;
std::vector<std::string_view> strs = std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > >{std::initializer_list<std::basic_string_view<char, std::char_traits<char> > >{std::operator""sv("hello", 5ul), std::operator""sv("there", 5ul)}, std::allocator<std::basic_string_view<char, std::char_traits<char> > >()};
{
std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > > & __range = strs;
__gnu_cxx::__normal_iterator<std::basic_string_view<char, std::char_traits<char> > *, std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > > > __begin = __range.begin();
__gnu_cxx::__normal_iterator<std::basic_string_view<char, std::char_traits<char> > *, std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > > > __end = __range.end();
for( ; __gnu_cxx::operator!=(__begin, __end); __begin.operator++() )
{
std::basic_string_view<char, std::char_traits<char> > & str = __begin.operator*();
std::operator<<(std::cout, std::basic_string_view<char, std::char_traits<char> >(str)).operator<<(str.size());
}
}
return 0;
}
The long way:
#include <vector>
#include <cstring> // for strlen
std::vector<const char*> _infoBarText;
char const *str = _infoBarText[0]; // or any other valid index
auto len = std::strlen(str);
Short:
auto len = std::strlen(_infoBarText[0]);

duplicate symbol error when compiling c++ code

I'm trying to compile some c++ code on os x using g++ in the terminal. However, I keep getting an error and I'm unsure of what it means. I have 3 files, main.cpp; comp_fns.cpp and comp_fns.h. Window and Gene are two different classes. Here is the error:
g++ -Wall main.cpp comp_fns.cpp
duplicate symbol Window::setValues(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)in:
/var/folders/jf/3y93rsfd1n55q2qd75y0w0r00000gn/T//cc51aFZg.o
/var/folders/jf/3y93rsfd1n55q2qd75y0w0r00000gn/T//cc2KNfcB.o
duplicate symbol Gene::setValues(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)in:
/var/folders/jf/3y93rsfd1n55q2qd75y0w0r00000gn/T//cc51aFZg.o
/var/folders/jf/3y93rsfd1n55q2qd75y0w0r00000gn/T//cc2KNfcB.o
ld: 2 duplicate symbols for architecture x86_64
collect2: ld returned 1 exit status
Any help would be much appreciated, and I can post the code if needed.
EDIT: I did not #include one cpp file into another. Here is my header file, where I think the issue may be at. This is my first cpp program so there might be some obvious mistakes. I originally wrote it in C and am changing it over to c++ so I can learn how to do both.
#ifndef __Compare_Data_C____comp_fns__
#define __Compare_Data_C____comp_fns__
#include <iostream>
#include <cstdlib>
#include <string>
#include <sstream>
using namespace std;
class Window {
public:
int start, stop, length;
double average;
string strandID, locations;
void setValues(string locs, string strand, string length, string avg);
};
class Gene {
public:
int start, stop;
string strandID, genes;
void setValues(string locs, string strand, string spcGene);
};
void Window::setValues(string locs, string strand, string a_length, string avg) {
locations = locs;
vector<string> token(3);
istringstream iss(locs);
for (int i=0; i<3; i++) {
getline(iss, token[i], '.');
}
start = atoi(token[0].c_str());
stop = atoi(token[2].c_str());
strandID = strand;
length = atoi(a_length.c_str());
average = atof(avg.c_str());
}
void Gene::setValues(string locs, string strand, string givenGene) {
vector<string> token(3);
istringstream iss(locs);
for (int i=0; i<3; i++) {
getline(iss, token[i], '.');
}
start = atoi(token[0].c_str());
stop = atoi(token[2].c_str());
strandID = strand;
genes = givenGene;
}
int getSize(string inputID, string strandID, const int header);
void getWindows(vector<Window> &win, string inputID, const int header);
void getGenes(vector<Gene> &posGene, vector<Gene> &negGene, string inputID, const int header);
void getSpecialWindows(vector<Window> &w, vector<Gene> &g, int wSize, int gSize, ofstream &output);
#endif /* defined(__Compare_Data_C____comp_fns__) */
Duplicate symbols means the linker faces the same function in both of your compilation units (main.cpp and comp_fns.cpp). Maybe you implemented the functions in the header without inline?

Valgrind debug log: Invalid read of size 8

recently I decide to debug my application with valgrind.
I've resolved a lot of errors, but can't this one.
==12205== Invalid read of size 8
==12205== at 0x37E1864C40: std::_Rb_tree_increment(std::_Rb_tree_node_base*) (in /usr/lib64/libstdc++.so.6.0.8)
==12205== by 0x40393C: readConfig(std::string) (stl_tree.h:257)
==12205== by 0x4058BE: main (application.cpp:42)
==12205== Address 0x5589b88 is 24 bytes inside a block of size 48 free'd
==12205== at 0x4A05A33: operator delete(void*) (vg_replace_malloc.c:346)
==12205== by 0x4067AD: std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::erase(std::_Rb_tree_iterator<std::pair<std::string const, std::string> >, std::_Rb_tree_iterator<std::pair<std::string const, std::string> >) (new_allocator.h:94)
==12205== by 0x406841: std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::erase(std::string const&) (stl_tree.h:1215)
==12205== by 0x403934: readConfig(std::string) (stl_map.h:461)
==12205== by 0x4058BE: main (application.cpp:42)
Part of my code:
string config_file;
if (strlen(getParam("config") . c_str()) > 0)
{
config_file = getParam("config");
}
else
config_file = string("default.conf");
if (access(config_file . c_str(), 0) == -1)
{
printf("Config file \"%s\" not exists\n", config_file . c_str());
exit(1);
}
if (!readConfig(config_file))
{
printf("Application error: read config file\n");
exit(1);
}
String #42:
if (!readConfig(config_file))
Please try to help me.
Thanks in advance!
Update #1:
I apologize for so large function :(
bool readConfig(string filename)
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
map<string,string> tmp_buff;
ifstream ifs( filename.c_str() );
string temp,tmp;
int i;
unsigned int MAX_MATCH = 40;
regex_t re;
char *pattern = "([^=]+)=(.+)";
const char* s;
map<int,string> matches_tmp;
map<string,string>::const_iterator it;
char s1[1024];
size_t rm;
regmatch_t pmatch[MAX_MATCH];
regcomp(&re, pattern, REG_ICASE|REG_EXTENDED|REG_NOSUB);
if ((rm = regcomp (&re, pattern, REG_EXTENDED)) != 0)
{
printf("Invalid expression:'%s'\n",pattern);
return false;
}
int start[2]={0},end[2]={0},current[2]={0};
char * b;
string substr;
bool start_time=false,inside_time=false,error=false;
while( getline( ifs, temp ) )
{
tmp=trim(temp);
tmp=temp;
if(strlen(tmp.c_str())==0) continue;
s=tmp.c_str();
if(!regexec(&re, s, MAX_MATCH, pmatch, 0))
{
for(i=1;i<=2;i++)
{
strncpy (s1, s + pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
s1[pmatch[i].rm_eo - pmatch[i].rm_so] = '\0';
matches_tmp[i]=trim((string)s1);
}
if(matches_tmp[1]==string("start-time"))
{
substr=matches_tmp[2].substr(0,2);
b=new char[substr.length()+1];
strcpy(b, substr.c_str() );
if(strlen(b)!=2) continue;
start[0]=atoi(b);
//free(b);
substr=matches_tmp[2].substr(3,2);
b=new char[substr.length()+1];
strcpy(b, substr.c_str() );
if(strlen(b)!=2) continue;
start[1]=atoi(b);
start_time=true;
continue;
}
if(matches_tmp[1]==string("end-time"))
{
start_time=false;
substr=matches_tmp[2].substr(0,2);
b=new char[substr.length()+1];
strcpy(b, substr.c_str() );
if(strlen(b)!=2) error=true;
end[0]=atoi(b);
substr=matches_tmp[2].substr(3,2);
b=new char[substr.length()+1];
strcpy(b, substr.c_str() );
if(strlen(b)!=2) error=true;
end[1]=atoi(b);
if(error)
{
printf("ERROR1\n");
error=false;
continue;
}
current[0]=timeinfo->tm_hour;
current[1]=timeinfo->tm_min;
if(end[0]<start[0])
{
if(
(current[0]<start[0] && current[0]>end[0]) ||
(current[0]==start[0] && current[1]<start[1]) ||
(current[0]==end[0] && current[1]>end[1])
)
{
error=true;
}
}else
{
if(
(current[0]<start[0]) ||
(current[0]>start[0] && current[0]>end[0]) ||
(current[0]==start[0] && current[1]<start[1]) ||
(current[0]==end[0] && current[1]>end[1])
)
{
error=true;
}
}
if(error)
{
error=false;
continue;
}
for (it = tmp_buff.begin(); it != tmp_buff.end(); ++it)
{
if(config.find( it->first ) != config.end()) config.erase(it->first);
config[it->first]=it->second;
tmp_buff.erase(it->first);
}
}
if(strlen(matches_tmp[1].c_str())==0) continue;
if(start_time)
{
tmp_buff[matches_tmp[1]]=matches_tmp[2];
}
else
config[matches_tmp[1]]=matches_tmp[2];
}
}
}
I suppose you are incrementing an invalid std::set or std::map iterator. This incorrect program produces a similar valgrind error:
#include <set>
int main () {
std::set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
for(std::set<int>::iterator it = s.begin(); it != s.end(); ++it) {
if(*it == 2) s.erase(it);
}
}
EDIT: Yep, you are doing exactly what I said:
for (it = tmp_buff.begin(); it != tmp_buff.end(); ++it)
{
if(config.find( it->first ) != config.end()) config.erase(it->first);
config[it->first]=it->second;
tmp_buff.erase(it->first);
}
The call to tmp_buff.erase(it->first) invalidates it. But, you subsequently increment it: ++it. This is not allowed.
Also, there is no reason to call config.erase. The entry in config will be implicity destroyed when it is overwritten in the next line. Try:
for (it = tmp_buff.begin(); it != tmp_buff.end(); ++it)
{
config[it->first]=it->second;
}
tmp_buff.clear();