Hello,

I feel like this is probably something silly, but for some reason if I declare a variable at a certain point in my code, then never use it... it crashes. This is literally what happens:

//... code here
int isBuf=0;//one of my variables
int zeroAddr=0;//<-- another variable I want, but never ever use (yet)
while (!file.eof())//code continues
//...

The above crashes while

//... code here
int isBuf=0;//one of myvariables
//int zeroAddr=0;//<-- another variable I want, but never ever use (yet)
while (!file.eof())//code continues
//...

Works perfectly. I have checked and zeroAddr is used absolutely nowhere else in my code.

From my understanding of C++ this should not be possible... yet its happening. Any insight as to a possible cause?

For reference here is the entire code, its purpose to emulate a custom machine language:

#include "LABASM.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;
string getInstructionString(int32_t x)
{
    string ret="";
    int imm=x&0xFFF;
    int type=(x>>20)&0xF;
    int a=(x>>16)&0xF;
    int b=(x>>12)&0xF;
    switch (type)
    {
        case 0:ret+="BEQ ";break;
        case 1:ret+="BNE ";break;
        case 2:ret+="BLT ";break;
        case 3:ret+="JMP ";break;
        case 4:ret+="MOV ";break;
        case 5:ret+="LDA ";break;
        case 6:ret+="STA ";break;
        case 7:ret+="STR ";break;
        case 8:ret+="INR ";break;
        case 9:ret+="OUT ";break;
        case 10:ret+="JBY ";break;
        case 11:ret+="NAN ";break;
        case 12:ret+="ADD ";break;
        case 13:ret+="MUL ";break;
        case 14:ret+="DIV ";break;
        case 15:ret+="MOD ";break;
        default:ret+="ERR ";
    }
    switch (a)
    {
        case 0:ret+="R0";break;
        case 1:ret+="R1";break;
        case 2:ret+="R2";break;
        case 3:ret+="R3";break;
        case 4:ret+="R4";break;
        case 5:ret+="R5";break;
        case 6:ret+="R6";break;
        case 7:ret+="R7";break;
        case 8:ret+="R8";break;
        case 9:ret+="R9";break;
        case 10:ret+="RA";break;
        case 11:ret+="RB";break;
        case 12:ret+="PC";break;
        case 13:ret+="IR";break;
        case 14:ret+="SP";break;
        case 15:ret+="FP";break;
        default:ret+="ER";
    }
    ret+=",";
    switch (b)
    {
        case 0:ret+="R0";break;
        case 1:ret+="R1";break;
        case 2:ret+="R2";break;
        case 3:ret+="R3";break;
        case 4:ret+="R4";break;
        case 5:ret+="R5";break;
        case 6:ret+="R6";break;
        case 7:ret+="R7";break;
        case 8:ret+="R8";break;
        case 9:ret+="R9";break;
        case 10:ret+="RA";break;
        case 11:ret+="RB";break;
        case 12:ret+="PC";break;
        case 13:ret+="IR";break;
        case 14:ret+="SP";break;
        case 15:ret+="FP";break;
        default:ret+="ER";
    }
    ret+="(";
    char buf[5];//we don't know how big our nums are... but imm<4096
    sprintf(buf,"%d",imm);
    ret+=buf;
    ret+=")";
    return ret;
}
int main(int argc, char *argv[])
{
    if (argc!=2)
    {
        cout<<"Please specify a .lab file for processing..."<<endl;
        return 0;
    }
    fstream ifile(argv[1]);
    if (!ifile.is_open())
    {
        cout<<"Could not open file!"<<endl;
        return 0;
    }
    vector<int32_t> data;
    char buf[4];
    int isBuf=0;
    //int zeroAddr=0;
    while (!ifile.eof())
    {
        ifile.get(buf[isBuf]);
        isBuf++;
        if (isBuf==4)
        {
            int32_t tmp=ASCIITOLABASM(buf[0]);
            tmp<<=6;
            tmp|=ASCIITOLABASM(buf[1]);
            tmp<<=6;
            tmp|=ASCIITOLABASM(buf[2]);
            tmp<<=6;
            tmp|=ASCIITOLABASM(buf[3]);
            data.push_back(tmp);
            isBuf=0;
        }
    }
    LABASMEmulator<int32_t> e;
    e.load(data,0);
    int32_t ret;
    int framecount=0;
    do
    {
        cout<<endl<<getInstructionString(e[e.reg(12)])<<" @"<<e.reg(12)<<
        " after "<<framecount++<<"u."<<endl;
    }while (e.step(&ret));

    cout<<"\nReturn value: "<<ret<<" after "<<framecount<<"u."<<endl;
    return 0;
}

While the LABASM.h file defines the LABASMEmulator class as:

template <typename ASMType>
class LABASMEmulator
{// private:
    size_t ASMSize;
    std::map<ASMType,ASMType> mem;
    ASMType *regs;
    int *busy;
    std::fstream vdisk;
public:
    LABASMEmulator();
    ~LABASMEmulator();
    bool step(ASMType *);//returns false on halt
    void load(std::vector<ASMType>,ASMType);
    ASMType &reg(int);//reg access
    ASMType &operator[](ASMType);//mem access
};

Of course it has guards, a few preprocessors, and a source cpp file with it, but I do not believe any of these could be causing the issue.

At this point my best guess is http://xkcd.com/1316/

EDIT: I thought I would add why I want that variable, it is to allow for specifying the second argument of LABASMEmulator::load based on input. When that wasn't working I removed 1 statement of code at a time until all that was left was the declaration itself... thus I isolated my issue, however I still don't know why it causes it to fail in the first place.

Edited 2 Years Ago by Labdabeta

I saw something similar once; a value was being cached locally, and then the memory storing it was being trashed. Because the value had been cached, it didn't matter that the memory had been trashed - the cached version was used.

Inserting another variable meant that the cache was being used for the other variable, so the original variable had to be refetched from memory, so suddenly the trashing of the memory mattered. We identified this by looking at the assembly, which showed when the cached value was being used.

First, though, run it under valgrind.

You have a buffer overflow on your buf array. The array can store 4 values, and you address it with buf[isBuf] where isBuf can be 4. This will write to memory one character passed the end of the buf array. When you have the zeroAddr present on the function's stack frame, it is probably sitting right after the buf array, meaning that writing beyond the end of buf is harmless because it just writes on the memory occupied by zeroAddr. But when the variable is not there, you write passed buf which either writes in invalid memory (beyond function's stack frame) or it overwrites the value of isBuf to a much higher value (a character) which then leads to a crash (accessing invalid memory).

I think that you should just change your condition on isBuf to:

    if (isBuf==3)
    {
      ..
    }

instead of 4. That should fix it.

Whenever you have this kind of behavior (adding a variable fixes the problem), it almost certainly means that you have memory corruption, i.e., reading or writing passed the end of an array or something like that.

Ah, thank you both. Memory corruption was indeed the error (although isBuf==4 is the correct check condition because it is preceded by isBuf++ each time). However my ASCIITOLABASM macro caused a bit of overflow on buf.

Thanks again!

This question has already been answered. Start a new discussion instead.