-2

I am currently implementing a rudimentary file load function. When using a std::stringstream the program crashes with a access violation in the stringstream destructor. Here is the function:

void macro_storage_t::load(std::string filename)
{
    std::ifstream file(filename);
    if (file.is_open())
    {
        clear();

        char line_c[4096];
        while (file.getline(line_c, 4096))
        {       

            std::string line(line_c);
            if (line.find("VERSION") == std::string::npos)
            {
                std::stringstream ss(std::stringstream::in | std::stringstream::out);
                int a, b, c, d;

                ss << line;
                ss >> a >> b >> c >> d;
                entry_t entry;
                entry.timestamp = a;
                entry.type = static_cast<entry_type_t>(b);
                entry.button = static_cast<button_t>(c);
                entry.key = static_cast<BYTE>(d);

            }
        }
    }
}

The file it loads looks like this (shortened for better readability):

VERSION 1
0 14 254 0

and is saved with this function:

void macro_storage_t::save(std::string filename)
{
    std::ofstream file(filename, std::ios::trunc);
    if (file.is_open())
    {
        file << "VERSION " << MACRO_VERSION << std::endl;
        for (std::vector<entry_t>::iterator it = entry_list_.begin(); it != entry_list_.end(); ++it)
        {
            entry_t entry = *it;
            file << (int)entry.timestamp << " " << (int)entry.type << " " << (int)entry.button << " " << (int)entry.key << std::endl;
        }
        file.close();
    }
}

The error is:

Unhandled exception at 0x0f99a9ee (msvcp100d.dll) in FLAP.exe: 0xC0000005: Access violation reading location 0x00000004.

The error happens as soon as the stringstream gets deleted implicitly...

I use Visual Studio 2010 on Windows 7.

Nidhoegger
  • 4,973
  • 4
  • 36
  • 81
  • Why don't you read into `line` directly and skip line_c, `std::getline(std::cin, line)`? – kfsone Sep 21 '16 at 19:56
  • What happens when you run it in the debugger? – kfsone Sep 21 '16 at 19:58
  • 2
    _"I am debugging this issue now for 15 minutes ..."_ I'm not so sure if this makes it valid to ask a question at Stack Overflow. Usually you're expected to put more efforts before you come here. – πάντα ῥεῖ Sep 21 '16 at 19:58
  • 15min to debug a problem is *nothing* - try hours, days, weeks or even months for really tricky issues. – Jesper Juhl Sep 21 '16 at 20:00
  • 1
    @πάνταῥεῖ Ah, then I think I go home. I thought coming to stackoverflow is OK if you have a problem, but thanks for clearing stuff up... I dont find a solution for this on my own. I googled and tried and never came across this error. In linux it runs fine tho... – Nidhoegger Sep 21 '16 at 20:01
  • When you get this error walk back the callstack to the line of you code causing the error. – drescherjm Sep 21 '16 at 20:02
  • that is the problem. I did, i have the stack right here, i stepped through it. it happens as soon as the `stringstream` gets implicitly deleted... The first line gets read correctly and even the values `a, b, c, d` are filled in correctly – Nidhoegger Sep 21 '16 at 20:03
  • Is it a possiblity that there is a multithreading issue? i made sure that this functions only gets called once (outside of it is a mutex), but ive read now multiple times that STL + multithreading might be an issue – Nidhoegger Sep 21 '16 at 20:09
  • The `load()` function you have shown is self-contained, everything is local and thus there is no multi-threading issue with it. However, if you are storing each read `entry_t` into your `entry_list` (which you did not show), and multiple threads are accessing `entry_list` at the same time, then you have a concurrency issue. But that should not be causing the `std::stringstream` destructor to crash, unless you are corrupting memory along the way. Which I don't see this code doing. As for the actual error, "*reading location 0x00000004*" implies a NULL pointer is being dereferenced. – Remy Lebeau Sep 21 '16 at 20:13
  • Okay, but switching from /MDd to /MTd in Visual Studio fixes the issue o_O – Nidhoegger Sep 21 '16 at 20:16
  • @Nidhoegger Does not repro: http://rextester.com/LQMO95021. The problem lies in code you are not showing us, for instance we have no clue what the definition of macro_storage_t is, etc. What you need to do - for yourself - is boil this down to an [MVCE](http://stackoverflow.com/help/mcve). – kfsone Sep 21 '16 at 20:59
  • @Nidhoegger Also here's a simpler version of the code: http://rextester.com/UPWY7366 – kfsone Sep 21 '16 at 21:10

1 Answers1

0

Try this instead:

void macro_storage_t::load(std::string filename)
{
    std::ifstream file(filename);
    if (file.is_open())
    {
        clear();

        std::string line;
        if (std::getline(file, line))
        {       
            if (line.substr(0, 8) == "VERSION ")
            {
                // optional: read the actual version number from the line,
                // if it affects how the following values must be read...

                while (std::getline(file, line))
                {
                    std::istringstream ss(line);
                    int a, b, c, d;

                    if (ss >> a >> b >> c >> d)
                    {
                        entry_t entry;

                        entry.timestamp = a;
                        entry.type = static_cast<entry_type_t>(b);
                        entry.button = static_cast<button_t>(c);
                        entry.key = static_cast<BYTE>(d);

                        entry_list_.push_back(entry);
                    }
                }
            }
        }
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Then you likely either have a bad installation, or the compiler is producing bad codegen. – Remy Lebeau Sep 21 '16 at 20:06
  • Do you have an idea what I can do about it? – Nidhoegger Sep 21 '16 at 20:06
  • @RemyLebeau In the original code he has written `if (line.find("VERSION") == std::string::npos)` but your code looks for lines beginning with VERSION rather than not including it. – kfsone Sep 21 '16 at 20:43
  • 1
    @Nidhoegger You probably have undefined behavior somewhere else in the program. Use a memory debugging tool like `valgrind`. – Barmar Sep 21 '16 at 20:44
  • @kfsone: the original code looks for `"VERSION"` on *every line that is read*. If it is not found on a line, that line is assumed to be (but is not validated as) a 4-int line. But only the first line will ever have `"VERSION"` on it, so my code checks only the first line. If `"VERSION"` is found on the first line, all subsequent lines are assumed (and validated) to be 4-int lines, otherwise they are not read. This way, there is less overhead used as `"VERSION"` is not being checked over and over. – Remy Lebeau Sep 21 '16 at 20:52