destrovel destrovel - 13 days ago 7
C++ Question

Segfault from std::getline with delimiter

For hours, I have been trying to fix this segfault. This code always sends SIGSEGV after the 500th iteration. Here's the TEST.csv I've been using. Once the while loop hits the second set of AMU values, getline immediately crashes the program. I've combed over this and cannot find the issue to save my life.

WORTH NOTING: I can't reproduce this error on every machine! Definitely some memory getting mangled somewhere but I just can't figure it out!

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <climits>
using namespace std;
int main(int argc, char **argv)
{
ifstream data;
data.open("TEST.csv", ifstream::in);
float amudata[505];
//initialize amudata
for (int x = 0; x < 505; x++) amudata[x] = INT_MIN;
std::string line;
//toss out the first 137 lines of config data
for (int x = 0; x < 137; x++)
{
std::getline(data, line);
}
//debug iteration counter
int x = 0;
//toss out the first part of the timestamp
//this is where SEGV happens
while (std::getline(data, line, ' '))
{
x++;
//toss out second part of timestamp
getline(data, line, ',');
//read and store the index, which is amu times 10
std::getline(data, line, ',');
int index = std::atof(line.c_str()) * 10;
//read and store the amu intensity
std::getline(data, line, ',');
float intensity = std::atof(line.c_str());
//some debug output
cout << index << " " << intensity << " ";
cout << line << " " << x << endl;
//keep track of only the maximum intensities
if (amudata[index] < intensity)
{
amudata[index] = intensity;
}
}
for (int x = 0; x < 505; x++)
{
printf("%f\n", amudata[x]);
}
data.close();
return 0;
}

Answer

Your amudata array is too small.

Your program crashes after you process this line:

2016/11/23 16:49:06.146,   50.500, -3.6263e-010,

When you do:

int index = std::atof(line.c_str()) * 10;

line is "50.500", so this sets index = 505. Then you do:

amudata[index] = intensity;

But the allowable indexes of amudata are from 0 to 504, so you're writing outside the array bounds, which causes undefined behavior.

You need:

float amudata[506];
//initialize amudata
for (int x = 0; x < 506; x++) amudata[x] = INT_MIN;

And it's best not to spread magic numbers like that around in the program, use a constant or macro.