samedi 9 mai 2015

Segfault in class destructor

Have a segfault in generated by gcc destructor of my Token class (code below and first screenshot). Almostly code works well but sometimes falls randomly

            Function: _ZNSsD2Ev
0xf77161af  <+0x003f>         lock xadd %ecx,-0x4(%eax)
0xf77161b4  <+0x0044>         mov    %ecx,%eax
0xf77161b6  <+0x0046>         test   %eax,%eax
0xf77161b8  <+0x0048>         jg     0xf7716191 <_ZNSsD2Ev+33>
0xf77161ba  <+0x004a>         sub    $0xc,%esp
0xf77161bd  <+0x004d>         push   %edx
0xf77161be  <+0x004e>         call   0xf76a9c70 <_ZdlPv@plt>
0xf77161c3  <+0x0053>         add    $0x10,%esp                //HERE
0xf77161c6  <+0x0056>         jmp    0xf7716191 <_ZNSsD2Ev+33>
0xf77161c8  <+0x0058>         nop
0xf77161c9  <+0x0059>         lea    0x0(%esi,%eiz,1),%esi
0xf77161d0  <+0x0060>         mov    -0x4(%eax),%ecx
0xf77161d3  <+0x0063>         lea    -0x1(%ecx),%esi
0xf77161d6  <+0x0066>         mov    %esi,-0x4(%eax)
0xf77161d9  <+0x0069>         mov    %ecx,%eax
0xf77161db  <+0x006b>         jmp    0xf77161b6 <_ZNSsD2Ev+70>
0xf77161dd                    xchg   %ax,%ax

Token class:

#ifndef TOKEN_H
#define TOKEN_H
#include <string>
#include <cstring>
#include <iostream>
#include "common.h"
using namespace std;

#define ICUR (inc(cur_pos))

class Token //Qt Creator's debugger shows segfault HERE
{
    static const int EOL_REACHED = 0;
    static const int UNKNOWN_ESCAPE = 1;
    bool firstTime = true;
    string src, last, cur;
    uint cur_pos, last_pos; //I wanted to use string::iterator but it was a bug
                            //that was modifing all iterators after adding *cur_pos to result string after some chars

public:
    enum TokenType {
        String, Digit, Delim, Bool, Identifier, EOL, UNKNOWN
    };

    Token(string src) {
        this->src = src + " ";

        cur_pos = 0;

        last = cur = Next();
        last_pos = 0;
    }

    bool operator ==(string str) {
        return this->ToString() == str;
    }

    bool operator !=(string str) {
        return this->ToString() != str;
    }

    Token& operator>>(string& str) {
        str = this->Next();
        return *this;
    }

    string PushBack() {
        cur_pos = last_pos;
        cur = last;
        return cur;
    }

    string ToString() {
        return cur;
    }

    string Last() {
        return last;
    }

    string Next() {
        string res = "";
        try {
            last_pos = cur_pos;
            last = cur;
            res = cur = next();
        } catch (int ex) {
            switch(ex) {
            case EOL_REACHED:
                type = EOL;
                res = "";
                break;
            case UNKNOWN_ESCAPE:
                type = UNKNOWN;
                res = "";
                break;
            }
        }
        firstTime = false;
        return res;
    }

    string NextWhileNot(char ch, bool skip=false) {
        string res = "";
        res.reserve(src.length()+1);
        try {
            last_pos = cur_pos;
            last = cur;
            while(src[cur_pos] != ch  && cur_pos != src.length()) {
                res += src[cur_pos]; //sometimes falls with segfault HERE
                ICUR;
            }
            if(skip) ICUR;
            cur = res;
        } catch (int ex) {
            if(ex == EOL_REACHED) {
                type = EOL;
                res = "";
            }
        }
        return res;
    }

    Token &NextToken() {
        this->Next();
        return *this;
    }

    TokenType Type() {
        return type;
    }

private:
    TokenType type;

    string next() {
        //auto temp_pos = cur_pos;
        //const auto temp_last = last_pos;
        string result = "";
        bool isCyr = false;

        if(src[cur_pos] == '/' && src[cur_pos + 1] == '/') {
            ICUR;
            ICUR;
            while(src[cur_pos] != '\n') ICUR;
        }

        while(strchr(" \t\r\n", src[cur_pos])) ICUR;

        //cout << src[cur_pos] << endl;
        if(firstTime && src[cur_pos] == '.') {
            result += src[cur_pos];
            ICUR;
            while(isalpha(src[cur_pos]) || isdigit(src[cur_pos]) || src[cur_pos] == '-') {
                result += src[cur_pos];
                ICUR;
            }
        }
        else if(isalpha(src[cur_pos]) || src[cur_pos] == '_' || (isCyr = isCyrillicAlpha())) {
            result += src[cur_pos];
            if(isCyr)
            {
                ICUR;
                result += src[cur_pos];
            }
            ICUR;
            while(isalpha(src[cur_pos]) || isdigit(src[cur_pos])
                  || (strchr("_@$", src[cur_pos]) != NULL) || (isCyr = isCyrillicAlpha())) {
                if(src[cur_pos] == '\0') break;
                result.push_back(src[cur_pos]);
                if(isCyr)
                {
                    ICUR;
                    result.push_back(src[cur_pos]);
                }
                ICUR;
            }
            if(result == "true" || result == "false")
                type = Bool;
            else
                type = Identifier;
        }
        else if(isdigit(src[cur_pos])) {
            type = Digit;
            result += src[cur_pos];
            ICUR;

            bool hasDot = false;
            while ([&](){
                   if(src[cur_pos] == '.' && !hasDot) {
                        hasDot = true;
                        return true;
                   }
                   else if(isdigit(src[cur_pos])) return true;
                   return false;
                }()) {
                result += src[cur_pos];
                ICUR;
            }
        }
        else if(src[cur_pos] == '"') {
            type = String;
            ICUR;
            while(src[cur_pos] != '"') {
                if(src[cur_pos] == '\\') {
                    ICUR;
                    switch (src[cur_pos]) {
                        case '\\':
                            result += '\\';
                            break;
                        case 'a':
                            result += '\a';
                            break;
                        case 'b':
                            result += '\b';
                            break;
                        case 'v':
                            result += '\v';
                            break;
                        case 'n':
                            result += '\n';
                            break;
                        case 'r':
                            result += '\r';
                            break;
                        case 't':
                            result += '\t';
                            break;
                        case '0':
                            result += '\0';
                            break;
                        default:
                            throw UNKNOWN_ESCAPE;
                    }
                }
                else result += src[cur_pos];
                ICUR;
            }
            ICUR;
        }
        else if(src[cur_pos] == '-' && src[cur_pos + 1] == '>') {
            ICUR;
            ICUR;
            type = Delim;
            result = "->";
        }
        else if(strchr(".,+-=(){}[]|\!@#%^*&~`<>:", src[cur_pos])) {
            result = src[cur_pos];
            type = Delim;
            ICUR;
        }
        //cur_pos = temp_pos;
        //last_pos = temp_last;
        return result;
    }

    void inc(uint& iter) {
        ++iter;
        if(iter >= src.length()) throw EOL_REACHED;
    }

    bool isCyrillicAlpha()
    {
        //int i = (byte)src[cur_pos];
        //cout << i;
        if((byte)src[cur_pos] != 208 && (byte)src[cur_pos] != 209)
            return false;
        byte ch = (byte)src[cur_pos + 1];
        if(ch >= (byte)'а' && ch <= (byte)'п')
            return true;
        if(ch >= (byte)'р' && ch <= (byte)'я')
            return true;
        if(ch >= (byte)'А' && ch <= (byte)'Я')
            return true;
        return false;
    }
};

#undef ICUR

#endif // TOKEN_H

Valgrind shows something like thah, but it doesn't refers to Token class but refers to vector:

==14463== Invalid read of size 4
==14463==    at 0x8056127: std::vector<unsigned char, std::allocator<unsigned char> >::push_back(unsigned char const&) (stl_vector.h:915)
==14463==    by 0x804FCF6: pushAddr(unsigned int, std::vector<unsigned char, std::allocator<unsigned char> >&) (assembler.cpp:741)
==14463==    by 0x804F14F: Assembler::pushAddr(unsigned int, std::vector<unsigned char, std::allocator<unsigned char> >&) (assembler.cpp:596)
==14463==    by 0x804D669: Assembler::compileFunc(Function&) (assembler.cpp:325)
==14463==    by 0x804CAD6: Assembler::Compile() (assembler.cpp:224)
==14463==    by 0x8049C82: main (main.cpp:21)
==14463==  Address 0x4391134 is 92 bytes inside a block of size 928 free'd
==14463==    at 0x402D7B8: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==14463==    by 0x8060D02: __gnu_cxx::new_allocator<Function>::deallocate(Function*, unsigned int) (new_allocator.h:110)
==14463==    by 0x805E603: std::allocator_traits<std::allocator<Function> >::deallocate(std::allocator<Function>&, Function*, unsigned int) (alloc_traits.h:383)
==14463==    by 0x805B075: std::_Vector_base<Function, std::allocator<Function> >::_M_deallocate(Function*, unsigned int) (stl_vector.h:178)
==14463==    by 0x805834B: void std::vector<Function, std::allocator<Function> >::_M_emplace_back_aux<Function const&>(Function const&) (vector.tcc:438)
==14463==    by 0x8055DD5: std::vector<Function, std::allocator<Function> >::push_back(Function const&) (stl_vector.h:923)
==14463==    by 0x804D639: Assembler::compileFunc(Function&) (assembler.cpp:322)
==14463==    by 0x804CAD6: Assembler::Compile() (assembler.cpp:224)
==14463==    by 0x8049C82: main (main.cpp:21)
==14463== 
==14463== Invalid read of size 4
==14463==    at 0x805612D: std::vector<unsigned char, std::allocator<unsigned char> >::push_back(unsigned char const&) (stl_vector.h:915)
==14463==    by 0x804FCF6: pushAddr(unsigned int, std::vector<unsigned char, std::allocator<unsigned char> >&) (assembler.cpp:741)
==14463==    by 0x804F14F: Assembler::pushAddr(unsigned int, std::vector<unsigned char, std::allocator<unsigned char> >&) (assembler.cpp:596)
==14463==    by 0x804D669: Assembler::compileFunc(Function&) (assembler.cpp:325)
==14463==    by 0x804CAD6: Assembler::Compile() (assembler.cpp:224)
==14463==    by 0x8049C82: main (main.cpp:21)
==14463==  Address 0x4391138 is 96 bytes inside a block of size 928 free'd
==14463==    at 0x402D7B8: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==14463==    by 0x8060D02: __gnu_cxx::new_allocator<Function>::deallocate(Function*, unsigned int) (new_allocator.h:110)
==14463==    by 0x805E603: std::allocator_traits<std::allocator<Function> >::deallocate(std::allocator<Function>&, Function*, unsigned int) (alloc_traits.h:383)
==14463==    by 0x805B075: std::_Vector_base<Function, std::allocator<Function> >::_M_deallocate(Function*, unsigned int) (stl_vector.h:178)
==14463==    by 0x805834B: void std::vector<Function, std::allocator<Function> >::_M_emplace_back_aux<Function const&>(Function const&) (vector.tcc:438)
==14463==    by 0x8055DD5: std::vector<Function, std::allocator<Function> >::push_back(Function const&) (stl_vector.h:923)
==14463==    by 0x804D639: Assembler::compileFunc(Function&) (assembler.cpp:322)
==14463==    by 0x804CAD6: Assembler::Compile() (assembler.cpp:224)
==14463==    by 0x8049C82: main (main.cpp:21)

Aucun commentaire:

Enregistrer un commentaire