0

Hello, i was solving this -> kata on CodeWars.

I am using a VusialStudio 2019 to write code. When i start this project in VS no erros is presented to me. The program even works correctly for the first test case. But when i am testing it on problem's page it gives me an error:

  • UndefinedBehaviorSanitizer:DEADLYSIGNAL
  • ==1==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000429d24 bp 0x7ffc2f3f72b0 sp 0x7ffc2f3f7150 T1)

  • ==1==The signal is caused by a READ memory access.

  • ==1==Hint: address points to the zero page.

  • ==1==WARNING: invalid path to external symbolizer!

  • ==1==WARNING: Failed to use and restart external symbolizer!

  • #0 0x429d23 (/workspace/test+0x429d23)

  • #1 0x42ab1d (/workspace/test+0x42ab1d)

  • #2 0x429fa3 (/workspace/test+0x429fa3)

  • #3 0x42e2f2 (/workspace/test+0x42e2f2)

  • #4 0x42c9ce (/workspace/test+0x42c9ce)

  • #5 0x42c529 (/workspace/test+0x42c529)

  • #6 0x42c11b (/workspace/test+0x42c11b)

  • #7 0x431425 (/workspace/test+0x431425)

  • #8 0x42a08d (/workspace/test+0x42a08d)

  • #9 0x7f1b94116bf6 (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)

  • #10 0x4053e9 (/workspace/test+0x4053e9)

  • UndefinedBehaviorSanitizer can not provide additional info. ==1==ABORTING

For a while i was turning on and off parts of program to determen where the problem is. I nereved it down to this line

Program::Status_enum Program::ExecuteComand(Comand_Class* ComandToExe)
{
    else if (ComandToExe->name == "div")
    {

        this->Registers[ComandToExe->args[0]] /= GetValue(ComandToExe->args[1]); // error here
    }

    
}

Leter i found out that error was showing up even if i chage line to

this->Registers.begin()->second = 3; // same error
this->Registers["a"] = 2; // same error

It looks to me that any change of value causes it to throw an error. But reaading for example was ok

int a = Registers["a"];
std::cout << a; // will print a right value

So this basikly all i was able to find out by my self. Here is structer of my code.

Basikly my goal is to write a Asmbler intorpritator

// All Comands saved as this class
class Comand_Class
{
public:
    std::string name; // for example mov, div, etc.
    std::vector<std::string> args; // data for the comand

    Comand_Class(std::string Name, std::string  arg1 = "", std::string arg2 = "")
    {
      //..
    }

    Comand_Class(std::string Name, std::vector<std::string> Args)
    {
      //..
    }

};

// I use this class to store functions cod as a small program itself

class Function_Class
{
public:

    std::vector<Comand_Class*> FunctionProgram;

};

// the main class
class Program
{
    
    std::string MSG = "-1"; // for outout

    std::unordered_map <std::string, int> Registers; // map in which the problem exsist

    std::vector<Comand_Class*> ProgramLines; // Starting code

    std::map<std::string,Function_Class*> CallList; // Name of Function and Her code to exe

// .exe is giving me back the status, after executing a Comand_Class line, this how i know what to do next.
    enum Status_enum
    {
        END = 0,
        CALL = 1,
        JUMP = 2,
        RET = 3,
        CONTINUE = 10,
        ERROR = -1,

    };
    

public:
    
    std::string Start()
    {
        exe(this -> ProgramLines );
        return MSG;
    }

    int GetValue(std::string arg)
    {
        if ('a' <= arg[0] && arg[0] <= 'z')
        {
            //register
            return this->Registers[arg];
        }
        else
        {
            int a = std::stoi(arg);
            return a;
        }

    }

// not related to the problem,
    void preprocesing(std::string program); 

    Status_enum ExecuteComand(Comand_Class* ComandToExe);

    void exe(std::vector<Comand_Class*> ProgramLinesToExe);

    ~Program()
    {
        for (unsigned long i = 0; i < ProgramLines.size(); i++)
        {
            Comand_Class* del = ProgramLines.at(i);
            delete del;
        }

        

        for (auto it = CallList.begin(); it != CallList.end(); it++)
        {
            
            for (unsigned long i = 0; i < it->second->FunctionProgram.size(); i++)
            {
                Comand_Class* del = it->second->FunctionProgram.at(i);
                delete del;
            }
        }

        // add CallList to clear

    }

};

// this function is recurseve, Can this be a reson why it brakes?

void Program::exe(std::vector<Comand_Class*> ProgramLinesToExe)
{
    Status_enum Status;
    unsigned long int SubPC = 0; // Comand to exe

    while (SubPC < ProgramLinesToExe.size())
    {
        Status = ExecuteComand(ProgramLinesToExe[SubPC]);

        if (Status != CONTINUE)
        {
            if(Status == JUMP)
            {
                exe(CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram);
            }
            else if (Status == CALL)
            {
                auto test = CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram;
                exe(CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram);
            }
            else if (Status == RET)
            {
                return;
            }
            else if (Status == END)
            {
                break;
            }
            else if (Status == ERROR)
            {
                std::cout << "Unknown comand! " << ProgramLinesToExe[SubPC]->name;
            }
            
            
        }

       


        SubPC++;
    } 

}

// Untill this function called second time (recursively) all works good

Program::Status_enum Program::ExecuteComand(Comand_Class* ComandToExe)
{

    if (ComandToExe->name == "mov")
    {
        this->Registers[ComandToExe->args[0]] = GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "inc")
    {
        this->Registers[ComandToExe->args[0]]++;
    }
    else if (ComandToExe->name == "dec")
    {
        this->Registers[ComandToExe->args[0]]--;
    }
    else if (ComandToExe->name == "add")
    {
        this->Registers[ComandToExe->args[0]] += GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "sub")
    {
        this->Registers[ComandToExe->args[0]] -= GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "mil")
    {
        this->Registers[ComandToExe->args[0]] *= GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "div")
    {
        
        //this->Registers[ComandToExe->args[0]] /= GetValue(ComandToExe->args[1]); error
    }
    else if (ComandToExe->name == "cmp")
    {
        int x = GetValue(ComandToExe->args[0]);
        int y = GetValue(ComandToExe->args[1]);

        this->CompareFlugs.Equal = (x == y);
        this->CompareFlugs.Less = (x < y);
    }
    else if (ComandToExe->name == "jne") // if the values of the previous cmp command were not equal.
    {
        if (this->CompareFlugs.Equal == false)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "je") // if the values of the previous cmp command were equal.
    {
        if (this->CompareFlugs.Equal == true)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jge") //  if x was greater or equal than y in the previous cmp command.
    {
        if (this->CompareFlugs.Less == false)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jg") // f x was greater than y in the previous cmp command.
    {
        if ((this->CompareFlugs.Less == false) && (this->CompareFlugs.Equal == false))
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jle") // if x was less or equal than y in the previous cmp command.
    {
        if ((this->CompareFlugs.Less == true) || (this->CompareFlugs.Equal == true))
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jl") // if x was less than y in the previous cmp command.
    {
        if (this->CompareFlugs.Less == true)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "call")
    {
        return CALL;
    }
    else if (ComandToExe->name == "ret")
    {
        return RET;
    }
    else if (ComandToExe->name == "end")
    {
        return END;
    }
    else if (ComandToExe->name == "msg")
    {
        MSG = "";

        for (unsigned long int i = 0; i < ComandToExe->args.size(); i++)
        {
            if (ComandToExe->args[i][0] == '\'')
            {
                MSG += ComandToExe->args[i].substr(1);
            }
            else
            {
                MSG += std::to_string(GetValue(ComandToExe->args[i]));
            }
        }
    }
    else
    {
        
        return ERROR;

    }

    return CONTINUE;

}

That's all. Also i am new to stackoverflow, so if i did somting very bad, do not judge strictly. And Here all the code, becase i cut parts i think was usless:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>

#include <map>
#include <unordered_map>

#include <regex>

class Comand_Class
{
public:
    std::string name;
    std::vector<std::string> args;

    Comand_Class(std::string Name, std::string  arg1 = "", std::string arg2 = "")
    {
        name = Name;
        args.push_back(arg1);

        if (!arg2.empty())
        {
            args.push_back(arg2);

        }
    }

    Comand_Class(std::string Name, std::vector<std::string> Args)
    {
        name = Name;
        args = Args;
    }

};

class Function_Class
{
public:

    //Comand_Class* ReturnControlTo = NULL;
    std::vector<Comand_Class*> FunctionProgram;

};

class Program
{
    

    //int PC = 0;

    std::string MSG = "-1";

    std::unordered_map <std::string, int> Registers;

    std::vector<Comand_Class*> ProgramLines;

    std::map<std::string,Function_Class*> CallList;

    class CompareFlugs_Class
    {
    public:
        bool Less = false;
        bool Equal = false;
    }CompareFlugs;

    enum Status_enum
    {
        END = 0,
        CALL = 1,
        JUMP = 2,
        RET = 3,
        CONTINUE = 10,
        ERROR = -1,

    };
    
    const std::string AllowedCommands = "mov inc dev add sub mul div cmp";

public:
    
    std::string Start()
    {
        exe(this -> ProgramLines );
        return MSG;
    }

    int GetValue(std::string arg)
    {
        if ('a' <= arg[0] && arg[0] <= 'z')
        {
            //register
            return this->Registers[arg];
        }
        else
        {
            int a = std::stoi(arg);
            return a;
        }

    }

    void preprocesing(std::string program);

    Status_enum ExecuteComand(Comand_Class* ComandToExe);

    void exe(std::vector<Comand_Class*> ProgramLinesToExe);

    ~Program()
    {
        for (unsigned long i = 0; i < ProgramLines.size(); i++)
        {
            Comand_Class* del = ProgramLines.at(i);
            delete del;
        }

        

        for (auto it = CallList.begin(); it != CallList.end(); it++)
        {
            
            for (unsigned long i = 0; i < it->second->FunctionProgram.size(); i++)
            {
                Comand_Class* del = it->second->FunctionProgram.at(i);
                delete del;
            }
        }

        // add CallList to clear

    }

};

void Program::preprocesing(std::string program)
{
    std::string read;
    Comand_Class*NewProgramLine;
    std::istringstream iss(program);

    std::smatch matches;
    std::regex Comand(";(.*)|call\\s(.*)|(end|ret)|msg(.*)[;]?|(\\w+):|(j\\w{1,2})\\s+(\\w+)|(\\w+)\\s+(\\w),?\\s?(\\d+|\\w)?");

    bool WtireToFunction = false;
    std::string ActiveLabel;
    Function_Class* NewFunction = nullptr;// = new Function_Class;

    while (!iss.eof())
    {
        std::getline(iss, read);
        std::regex_search(read, matches, Comand);

        /*
        if (matches.size() != 0)
            std::cout << "Comand is " << matches[0] << "\n";
        */

        // parcing

        std::string Coment = matches[1];
        std::string CallLabel = matches[2];
        std::string End = matches[3];
        std::string Message = matches[4]; // may contain a comment in the end
        std::string Label = matches[5];

        std::string JumpComand = matches[6];
        std::string JumpLabel = matches[7];

        std::string ComandName = matches[8];
        std::string arg1 = matches[9];
        std::string arg2 = matches[10];

        

        if ((!ComandName.empty()) && (AllowedCommands.find(ComandName) != std::string::npos))
        {
            //std::cout << "Comand is " << matches[0] << "\n";
            std::cout << "Comand is " << ComandName << " " << arg1 << " " << arg2 << "\n";

            NewProgramLine = new Comand_Class (ComandName,arg1,arg2);
            //NewProgramLine->name = ComandName;
            //NewProgramLine->args.push_back(arg1);
            if (WtireToFunction == false)
            {
                this->ProgramLines.push_back(NewProgramLine);
            }
            else
            {
                NewFunction->FunctionProgram.push_back(NewProgramLine);
            }
            
        }
        else if (!JumpComand.empty()) // && (AllowedJumpComands.find(JumpComand) != std::string::npos))
        {
            std::cout << "Comand is " << JumpComand << " " << JumpLabel << "\n";

            NewProgramLine = new Comand_Class(JumpComand, JumpLabel);

        }
        else if (!CallLabel.empty()) // on call
        {
            NewProgramLine = new Comand_Class("call", CallLabel);
            this->ProgramLines.push_back(NewProgramLine); // add Call to the ProgramLines
        }
        else if (!Label.empty()) // Generate New SubProgram
        {
            WtireToFunction = true;
            ActiveLabel = Label;

            NewFunction = new Function_Class;
            this->CallList[ActiveLabel] = NewFunction;
        }
        else if (!Message.empty())
        {
            std::regex MessageParcing("('.*)'|,\\s(\\w)");
            std::smatch matches;
            std::sregex_iterator it(Message.begin(), Message.end(), MessageParcing), end;

            std::vector<std::string> args;
            
            while (it!= end)
            {
                matches = *it;

                if (!matches[1].str().empty())
                {
                    args.push_back(matches[1].str());
                }
                else if (!matches[2].str().empty())
                {
                    args.push_back(matches[2].str());
                }
                else
                {
                    std::cout << "Error: cannot format msg\n";
                }

                it++;
                
            }

            NewProgramLine = new Comand_Class("msg",args);
            this->ProgramLines.push_back(NewProgramLine);
        }
        else if (!End.empty())
        {
            if (End == "end")
            {
                NewProgramLine = new Comand_Class("end");
                this->ProgramLines.push_back(NewProgramLine); // add Call to the ProgramLines
            }

            if (End == "ret")
            {
                if (NewFunction == nullptr)
                    std::cout << "No Call Detected, but ret is found\n";
                else
                {
                    NewProgramLine = new Comand_Class("ret");
                    NewFunction->FunctionProgram.push_back(NewProgramLine);
                }
                   
                
            }
            
        }

    }

}

Program::Status_enum Program::ExecuteComand(Comand_Class* ComandToExe)
{

    if (ComandToExe->name == "mov")
    {
        this->Registers[ComandToExe->args[0]] = GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "inc")
    {
        this->Registers[ComandToExe->args[0]]++;
    }
    else if (ComandToExe->name == "dec")
    {
        this->Registers[ComandToExe->args[0]]--;
    }
    else if (ComandToExe->name == "add")
    {
        this->Registers[ComandToExe->args[0]] += GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "sub")
    {
        this->Registers[ComandToExe->args[0]] -= GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "mil")
    {
        this->Registers[ComandToExe->args[0]] *= GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "div")
    {
        
        int a = GetValue(ComandToExe->args[1]);
        auto t = ComandToExe->args[0];
        int b = 6 / 2;
        this->MSG = "Hi";
        this->Registers[t] = b;

        this->Registers.begin()->second = 3;

        //this->Registers[ComandToExe->args[0]] /= GetValue(ComandToExe->args[1]);
    }
    else if (ComandToExe->name == "cmp")
    {
        int x = GetValue(ComandToExe->args[0]);
        int y = GetValue(ComandToExe->args[1]);

        this->CompareFlugs.Equal = (x == y);
        this->CompareFlugs.Less = (x < y);
    }
    else if (ComandToExe->name == "jne") // if the values of the previous cmp command were not equal.
    {
        if (this->CompareFlugs.Equal == false)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "je") // if the values of the previous cmp command were equal.
    {
        if (this->CompareFlugs.Equal == true)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jge") //  if x was greater or equal than y in the previous cmp command.
    {
        if (this->CompareFlugs.Less == false)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jg") // f x was greater than y in the previous cmp command.
    {
        if ((this->CompareFlugs.Less == false) && (this->CompareFlugs.Equal == false))
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jle") // if x was less or equal than y in the previous cmp command.
    {
        if ((this->CompareFlugs.Less == true) || (this->CompareFlugs.Equal == true))
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "jl") // if x was less than y in the previous cmp command.
    {
        if (this->CompareFlugs.Less == true)
        {
            return JUMP;

        }
    }
    else if (ComandToExe->name == "call")
    {
        // написать адресс для возврата в структуру с функциями
        return CALL;
    }
    else if (ComandToExe->name == "ret")
    {
        return RET;
    }
    else if (ComandToExe->name == "end")
    {
        return END;
    }
    else if (ComandToExe->name == "msg")
    {
        MSG = "";

        for (unsigned long int i = 0; i < ComandToExe->args.size(); i++)
        {
            if (ComandToExe->args[i][0] == '\'')
            {
                MSG += ComandToExe->args[i].substr(1);
            }
            else
            {
                MSG += std::to_string(GetValue(ComandToExe->args[i]));
            }
        }
    }
    else
    {
        
        return ERROR;

    }

    return CONTINUE;

}

void Program::exe(std::vector<Comand_Class*> ProgramLinesToExe)
{
    Status_enum Status;
    unsigned long int SubPC = 0;

    while (SubPC < ProgramLinesToExe.size())
    {
        Status = ExecuteComand(ProgramLinesToExe[SubPC]);

        if (Status != CONTINUE)
        {
            if(Status == JUMP)
            {
                exe(CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram);
            }
            else if (Status == CALL)
            {
                auto test = CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram;
                exe(CallList[ProgramLinesToExe[SubPC]->args[0]]->FunctionProgram);
            }
            else if (Status == RET)
            {
                return;
            }
            else if (Status == END)
            {
                break;
            }
            else if (Status == ERROR)
            {
                std::cout << "Unknown comand! " << ProgramLinesToExe[SubPC]->name;
            }
            
            
        }

       


        SubPC++;
    } 

}

std::string assembler_interpreter(std::string program) 
{
    Program Main;
    Main.preprocesing(program);
    return Main.Start();
}

  • constructor of `Comand_Class` pushes either one or two elements to `args` but the rest of the code assumes that there are two elements without any checking. Not sure, but I think it would be better to push the second anyways, also when it is an empty string – 463035818_is_not_an_ai Jul 01 '21 at 09:10
  • replacing any `args[i]` with `args.at(i)` can tell you if thats the issue – 463035818_is_not_an_ai Jul 01 '21 at 09:13
  • 2
    You misspelled "mul" twice, and you need to read [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons). – molbdnilo Jul 01 '21 at 09:19
  • @463035818_is_not_a_number Thanks for suggestion, i know how many args are there based of Comand_Classs.name a.k.a comand to execute. – Doctor smail Jul 01 '21 at 09:31
  • 1
    "I know ..." is the source of soo many bugs. You should write code that is explicit about what assumption it makes. `if (args.size() == 2) ...use args[1]...` wont hurt performance too much, but it will make the code much less suspectible to evil bugs – 463035818_is_not_an_ai Jul 01 '21 at 09:33
  • @molbdnilo Found misspelled mul, And thanks for this qwestion about eof. I will be more carefuly from now. – Doctor smail Jul 01 '21 at 09:38
  • @463035818_is_not_a_number If i understend you correctly cosider this example: User typed wrong comand let's say move a (vithout second arg). In my current state this will cause error when reading data. But i always read second arg with `GetValue()`, should i just implement cheking there instead of adding cheks to each `else if ( == "comand")?` – Doctor smail Jul 01 '21 at 09:54
  • frankly, this is too much code and I dont understand it all. I am not talking about `GetValue(std::string arg)` but the member `std::vector args;` of `Command_class` that you use as parameter to `GetValue`. In `Execute_Commands` (the very line where the runtime error happens) you access `args[1]` but that element may not exists. And honestly, I don't believe you when you say "I know the element exists", because if all your assumptions were right there would be no runtime error. – 463035818_is_not_an_ai Jul 01 '21 at 10:00
  • @463035818_is_not_a_number While answering your comment, i tested a little bit more. And i tkink i have a good idea now. It's look like when i write wrong answer no runtime eror hepends, but i hava a runtime error with a right answer. To be honest i don't undestand how thouse tests on sites works. They executing my program multiple times, but data inside is never reseted. This is probably liding to reading null pointer on second executing. And this explain why i don't have any erors in VS. And i probably should close the question. – Doctor smail Jul 01 '21 at 10:23
  • the problem is that what you posted is nothing to execute, there is no `main`. Whatever tests you or some online checker was running is not reproducible with only the code you posted – 463035818_is_not_an_ai Jul 01 '21 at 12:13
  • Just take clang or gcc use it to build your code. Remember to use sanitizers. Then run first test from task description. This finds your issue. I've change tests to use `catch2` and try [run in on godbolt](https://godbolt.org/z/W1nP9ncPz). Now without sanitizers your code crashes. With sanitizer enabled code is to slow for godbolt time quota so I can't show you exactly what is the problem. – Marek R Jul 01 '21 at 12:52

0 Answers0