【问题标题】:Stack overflow (SIGSEGV) when calling static c++ class method调用静态 C++ 类方法时的堆栈溢出(SIGSEGV)
【发布时间】:2011-09-13 00:55:09
【问题描述】:

我一直在研究这个问题几个小时并尝试了各种各样的事情,但所有结果都是一样的 - 一个 SIGSEGV(来自 gdb;根据 VC 调试,它是一个堆栈溢出......)静态类方法被调用。

罪魁祸首代码:

void LEHelper::copySinglePath (std::string from_path, std::string to_path)
{
    // first check if this path is a file or folder
    if (!folderExists(from_path)) // is a file
    {
        FILE *fp = fopen(from_path.c_str(), "rb");
        FILE *tp = fopen(to_path.c_str(), "wb");

        if (fp && tp)
        {
            // read 1MB chunks from the file and copy to the new destination until finished
            LEuchar bytes[1048576];

            while (!feof(fp))
            {
                size_t read_num = fread(bytes, sizeof(LEuchar), 1048576, fp);
                fwrite(bytes, sizeof(LEuchar), read_num, tp);
            }
        }

        if (fp)
            fclose(fp);
        if (tp)
            fclose(tp);
    }
    else // is a folder
    {
        // make a new directory at the "to" path to copy files into
    #if defined(LE_OS_OSX)
        mkdir(to_path.c_str(), S_IRWXO | S_IRWXG | S_IRWXU);
    #elif defined(LE_OS_WIN)
        mkdir(to_path.c_str());
    #endif

        // need to get all contents and recursively perform this method with correct pathing
        LEArray<std::string> contents = getContentsOfDirectoryUsingFilter(from_path, LEH_DIR_BOTH);
        std::string *current;

        contents.initEnumerator();
        while ((current = contents.nextObject()))
        {
            // first build the current file or folder path (and new path)
            std::string current_path = from_path;
            std::string new_path = to_path;

            if (current->length() > 0)
            {
                current_path += LE_PATH_SEPARATOR + *current;
                new_path += LE_PATH_SEPARATOR + *current;
            }

            // then copy as necessary --- this is where things go bad ---
            copySinglePath(current_path, new_path);
        }
    }
}

而调用栈是:

#0 00000000 0x0040db8a in _alloca() (??:??)
#1 00403888 LEHelper::copySinglePath(from_path=..., to_path=...) 
#2 00403AD1 LEHelper::copySinglePath(from_path=..., to_path=...) 
#3 00403C8C LEHelper::copyPath(existing_path=..., new_path=..., ow=true) 
#4 00402CD3 main(argc=1, argv=0x992c10) 

在我正在测试的程序中,一旦成功到达所有值正确的递归点,就会调用它(我一直在使用printf 检查字符串值),但在其中调用copySinglePath() 时会失败。由于调用堆栈是如此之小,我很难相信这实际上是由于太多递归造成的堆栈溢出......但我的理解可能是错误的。

在我研究答案时,我读到大多数分段错误是由指针问题引起的,所以我尝试将 copySinglePath() 的参数更改为指针,使用 new 分配传入的字符串在堆上(所以我可以控制分配等),但这没有任何区别。

同样奇怪的是,这个完全相同的代码在 OSX 上完美运行。因此,我认为我的 mingw 设置可能有什么问题,所以我用最新的 mingw-get 重新安装了它,但仍然没有什么不同。我什至认为我的 Visual Studio 安装文件可能会以某种方式被使用(包括在内),所以暂时更改了他们的文件夹以确保它仍然编译等,所以不应该是它......

我现在完全不知道为什么会发生这种情况。如果有人对我可能做错了什么有任何想法,请...

提前感谢大家

【问题讨论】:

  • 您需要使用调试器并找到出错的行。例如,您可能在 LEArray 中有十几个错误,而我们永远找不到它们。
  • 只是一个提示:由于 Windows 不使用 UTF8 进行 1 字节编码,因此您的代码无法处理名称包含无法以 1 字节编码表示的特殊字符的文件/目录。

标签: c++ stack overflow segmentation-fault


【解决方案1】:

您可能需要减小块的大小,或者将它们分配到堆上。 call 堆栈非常小,但 stack 包含局部变量。默认情况下,Windows 堆栈只有 1MB 的内存,而 Unix 堆栈是 8MB。从这个堆栈中分配一个 1MB 的数组会立即溢出。您需要更改链接器设置以允许更大的堆栈大小。

【讨论】:

  • 感谢您提供清晰明了的解释!这正是问题所在(正如 selalerer 所指出的那样)——我不知道这些尺寸默认值。此外,这促使我更好地理解堆栈的工作原理。谢谢!
【解决方案2】:

这个变量:

LEuchar bytes[1048576];

在堆栈上并且非常大,导致堆栈溢出。使用全局变量或动态分配的变量,问题就会消失。

【讨论】:

  • 很好的发现并感谢您提供可能的解决方案。如果我可以投票,我会:)
【解决方案3】:

Rob 的规则 #47:当你​​可以使用向量时,永远不要使用数组:

    // read 1MB chunks from the file and copy to the new destination until finished
    std::vector<LEuchar> bytes(1048576);

    while (!feof(fp))
    {
        size_t read_num = fread(&bytes[0], sizeof(LEuchar), bytes.size(), fp);
        fwrite(&bytes[0], sizeof(LEuchar), read_num, tp);
    }

正如其他人指出的那样,问题是 LEuchar 的 1M 分配了太多堆栈。使用向量将该分配转移到空闲存储区。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    • 2011-03-02
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多