程序删除自身,不启动

时间:2014-04-08 22:31:42

标签: c++ c++11 g++ cygwin g++4.8

我正在开发一个实现引用计数系统的库。在调试模式下,我在分配和删除值时打印出来。在编译测试程序并运行它之后,它并没有真正运行但实际上是自行删除并留下了一个stackdump文件。有趣的是,这只发生在我使用一个小的帮助器模板类时,它实现了类似于基于范围的引用管理器(当对象帮助器对象被销毁时减少引用计数)。

GDB甚至没有帮助我,因为当我指示它运行main.exe时,它说它无法打开这个过程。

描述

首先,我查看导致所描述行为的主程序。

// snippet 1
void test1() {
    Handle<String> v = String::New("Fooo!");
    std::cout << v->Get() << "\n";
}

将其更改为以下程序使程序再次运行:

// snippet 2
void test1() {
    String* v = String::New("Fooo!");
    std::cout << v->Get() << "\n";
    v->Decref();
}

但我知道Handle<T>类实际上工作得很好,因为以下函数再次运行正常,没有问题或未释放的值。 (@agbinfo)String类是Value的子类。 Handle模板旨在与Value类一起使用,因此当不再需要值时,无需手动调用Value::Decref()

// snippet 3
Value* test2() {
    Handle<HashMap> map = HashMap::New();
    Handle<Value> a = String::New("The Answer");
    Handle<Value> b = Int::New(42);
    map->Put(a, b);

    // It's easier to use the static getter functions when
    // using the Handle helper class because it makes headache
    // to cast them.
    a = map->AsString();
    std::cout << String::Get(a) << "\n";

    // Overwrite the existing entry in the map.
    a = String::New("The Answer");
    b = vv::null();
    map->Put(a, b);

    // But we could also get an actual pointer to the String. We
    // just have to make sure to decrease the reference count as
    // we don't have the Handle helper class that does that based
    // on the scope.
    String* str = map->AsString();
    std::cout << str->Get() << "\n";
    str->Decref();

    // The ownership of the returned Value* is transfered to the
    // caller with Handle<T>::Release()
    return a.Release();
}

有趣的是,当我使用return a.Release();替换test2()中的return nullptr;并调用test1()永远不会 test2()时,程序工作正常。

我又回到了程序崩溃的状态,并试图在代码更深处找到问题。我查看了创建或删除vv::Value个对象时完成的日志记录。从utils::typestr(Type())中删除vv::Value::Free()部分会使程序再次运行!

class Value {

protected:

    /**
     * Must be invoked when an object was allocated and
     * constructed.
     */
    virtual void Init()
    {
        #ifdef VV_DEBUG
        if (vv::GetFlag(SystemFlags_LogGeneration))
            logging::LogValue(this, "Created " + utils::typestr(Type()));
        #endif
    }

    /**
     * Is invoked when the object is about to be deallocated
     * from vv::Value::Decref().
     */
    virtual void Free()
    {
        #ifdef VV_DEBUG
        if (vv::GetFlag(SystemFlags_LogGeneration))
            logging::LogValue(this, "Deleted " /* + utils::typestr(Type()) */);
        #endif
    }

public:

    // ...

};

现在,在vv::utils::typestr()中,我通过将字节解释为字符将整数转换为字符串,因为可以从vv::Value::Type()返回的值被声明为

enum {
    Type_Null = 'null',
    Type_Bool = 'bool',
    Type_Int = 'intg',
    Type_Double = 'dble',
    Type_String = 'strn',
    Type_Array = 'arry',
    Type_List = 'list',
    Type_HashMap = 'hmap',
};

所以typestr()的代码是

inline std::string typestr(int id)
{
    const char* buffer = reinterpret_cast<const char*>(&id);
    std::string result = "";
    for (size_t i=0; i < sizeof(int); i++) {
        result.push_back(buffer[i]);
    }

    // Reverse the string if we are on a little-endian system.
    if (vv::utils::bigendian()) {
        std::reverse(result.begin(), result.end());
    }
    return result;
}

STACKDUMP

对于stackdump,遗憾的是它不是每次都生成的,我现在无法重现它以获得最近的stackdump。但是生成的其中一个文件看起来非常像这样:

Exception: STATUS_ACCESS_VIOLATION at eip=004022A8
eax=0028ABE4 ebx=0028AC6C ecx=00000001 edx=0000001C esi=00000000 edi=610071D0
ebp=0028AC48 esp=0028AC20 program=C:\Users\niklas\Desktop\cpp-vv\main.exe, pid 6412, thread main
cs=0023 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame     Function  Args
0028AC48  004022A8 (00000001, 0028AC6C, 80010100, 61007FDA)
0028ACF8  61008039 (00000000, 0028CD84, 610071D0, 00000000)
0028CD58  61005E84 (0028CD84, 00000000, 00000000, 00000000)
0028FF28  61005FF6 (610071D0, 00000000, 00000000, 00000000)
0028FF48  61006F54 (00402225, 00000000, 00000000, 00000000)
0028FF68  00402592 (00402225, 00000000, 00000000, 00000000)
0028FF88  00401015 (FFFDE000, 0028FFD4, 77C49F72, FFFDE000)
0028FF94  773F336A (FFFDE000, 76B6F19F, 00000000, 00000000)
0028FFD4  77C49F72 (00401000, FFFDE000, 00000000, 00000000)
0028FFEC  77C49F45 (00401000, FFFDE000, 00000000, 78746341)
End of stack trace

编译输出

g++ -std=c++11 -g -Wno-multichar -Iinclude/ -DVV_DEBUG src/main.cpp -c -oobj/src/main.o
g++ -std=c++11 -g -Wno-multichar -Iinclude/ -DVV_DEBUG src/vv/system.cpp -c -oobj/src/vv/system.o
g++ -std=c++11 -g -Wno-multichar -Iinclude/ -DVV_DEBUG src/vv/logging.cpp -c -oobj/src/vv/logging.o
g++ -std=c++11 -g -Wno-multichar -Iinclude/ -DVV_DEBUG src/vv/Types.cpp -c -oobj/src/vv/Types.o
g++ -std=c++11 -g -Wno-multichar -Iinclude/ -DVV_DEBUG src/vv/Value.cpp -c -oobj/src/vv/Value.o
g++ -Wno-multichar -Iinclude/ -DVV_DEBUG obj/src/main.o obj/src/vv/system.o obj/src/vv/logging.o obj/src/vv/Types.o obj/src/vv/Value.o -o main.exe

GCC详细信息

Windows 7 64Bit上的Cygwin

g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

到目前为止,这似乎使程序运行。但你知道这个问题可能来自哪里吗?就我而言,我无法在typestr()中发现问题。也许有一些模式,你作为一个有经验的开发人员可以识别和告诉我?

1 个答案:

答案 0 :(得分:4)

您的防病毒软件的检测启发式方法可能会在非常特殊,看似随意的情况下错误地将您的程序识别为病毒。尝试暂时禁用实时系统保护。