Home > Net >  Read .csv into `map<vector<uint>>`
Read .csv into `map<vector<uint>>`

Time:11-16

I am trying to read a .csv file into a map<vector<uint>>.

The .csv file represents a modbus register map, in the form name,register,register,register.... eg.

address,1
position,10,11
status,20,21,22

I have tried this (based on https://stackoverflow.com/a/24930415/15655948), and get a segmentation fault. register_map is declared as a class attribute in the header file.

int SomeClass::readCSV(std::string fileName)
{   
    const uint MAX_LINE_LENGTH = 1024;
    const char* DELIMS = ",";

    std::fstream fin(fileName);

    if (!fin.is_open()) { 
        spdlog::get("runtime_log")->error("Could not open file {0}.", fileName);
        return -1;
    }

    char buffer[MAX_LINE_LENGTH] = {};
    char* pch;
    std::vector<uint> values;

    while (fin.getline(buffer, MAX_LINE_LENGTH)){

        const char* row = strtok(buffer, DELIMS);
        pch = strtok(NULL, DELIMS);
        values.push_back(strtoul(pch,NULL,10));

        while (pch != NULL){
            pch = strtok(NULL, DELIMS);
            values.push_back(strtoul(pch,NULL,10));
        }

        register_map[std::string(row)] = values;
        values.clear();
    }

    return 1;
}

Why am I getting the segmentation fault above?

CodePudding user response:

Among other assumptions, the critical one is this:

while (pch != NULL) {
    pch = strtok(NULL, DELIMS);                 //<-- pch can be NULL
    values.push_back(strtoul(pch, NULL, 10));   //<-- BOOM!
}

Here, you're calling strtok, which might return NULL. But you still go ahead and convert the string anyway. This guarantees undefined behavior.

To fix it, you should reverse the logic so that you only convert pointers that you have already NULL-tested.

const char* row = strtok(buffer, DELIMS);

pch = strtok(NULL, DELIMS);
while (pch != NULL) {
    values.push_back(strtoul(pch, NULL, 10));
    pch = strtok(NULL, DELIMS);
}

This type of error can easily be detected by running your program in a debugger and stepping through execution one line of code at a time. The debugger is also likely to break execution on an error like this, and show you the call stack at the point of crash. So you'd take one look and think "oh, it crashed here because pch is NULL".

I recommend Right Now (TM) as a good time to learn how debug small programs. Most IDEs come with an integrated debugger, which makes it even easier.

  •  Tags:  
  • c
  • Related