Переполнение стека (SIGSEGV) при вызове статического метода класса c ++ - PullRequest
1 голос
/ 11 июня 2011

Я часами изучал эту проблему и перепробовал разные вещи, но все приводит к одному и тому же - 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 могут быть каким-то образом использованы (включая те, что есть), поэтому временно изменили их папку, чтобы убедиться в этом, и она все еще скомпилирована и т. Д., Чтобы этого не было ...

Я сейчас в полном недоумении, почему это происходит.Если у кого-то есть мысли о том, что я могу делать неправильно, пожалуйста ...

Спасибо всем заранее

Ответы [ 3 ]

3 голосов
/ 11 июня 2011

Эта переменная:

LEuchar bytes[1048576];

находится в стеке и является очень большим, что вызывает переполнение стека. Используйте глобальную или динамически распределенную переменную, и проблема исчезнет.

2 голосов
/ 11 июня 2011

Возможно, вам понадобится уменьшить размер ваших кусков или разместить их в куче.Стек call очень мал, но стек включает локальные переменные.По умолчанию размер стека Windows составляет всего 1 МБ, тогда как размер стека Unix составляет 8 МБ.Выделение массива 1 МБ из этого стека - это мгновенное переполнение.Вам нужно изменить настройки компоновщика, чтобы увеличить размер стека.

1 голос
/ 11 июня 2011

Правило Роба № 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);
    }

Как указывалось другими, проблема в том, что 1M LEuchar выделяет слишком много стека.Использование вектора переносит это распределение в свободный магазин.

...