Как я могу сохранить переменную стека от перезаписи статического массива в C ++ с GCC? - PullRequest
0 голосов
/ 19 декабря 2011

У меня проблема в том, что массив, объявленный в стеке как автоматическая переменная, перезаписывает массив, объявленный статически. Я не могу процитировать точный код как по причине размера, так и по интеллектуальной собственности, но набросок следующий.

У меня есть следующая структура:

struct mystruct_type {
    const int list_size;
    const int* list;
};

У меня есть глобальный статический массив этих структур:

struct mystruct_type mystruct_ar[] = {
    {3, (int[]){1, 2, 3}},
    {2, (int[]){1, 3}},
    {5, (int[]){4, 2, 3, 4, 5}}
};

Этот массив находится в исходном файле, который скомпилирован в библиотеку.

У меня есть другой исходный файл, который скомпилирован в другую библиотеку с автоматическим массивом:

void my_func(void) 
{
    char my_string[1000];

    // etc...
}

Когда все это связано вместе, я вижу, что адрес один из list s в mystruct_ar перекрывается с my_string, и когда я копирую что-то в my_string, он переопределяет элементы в этом list, вызывая множество проблем.

Мое понимание того, как работают компилятор и компоновщик, заключается в том, что статический массив и все его подмассивы принадлежат одной области памяти, а стек (для которого объявлено my_string) находится в отдельной неперекрывающейся области , Что может быть причиной этого совпадения? Что я могу проверить?

Я использую GCC 4.3.2 в SuSE10 Linux (x86-64_linux26). Все связано статически.

РЕДАКТИРОВАТЬ: несколько комментариев ниже сказал, что это не компилируется. Они правы. В процессе очистки моего фрагмента для презентации я не стал приводить массив list к int[]. Это исправлено выше.

Ответы [ 3 ]

1 голос
/ 19 декабря 2011

Не думаю, что этот код скомпилируется.В частности, вы не можете передать {list, of, ints} в mystruct_ar для указателя списка.Вы должны были бы объявить каждый массив целых чисел отдельно выше.

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

0 голосов
/ 19 декабря 2011

Что может быть причиной этого совпадения?

Вы не сказали, используете ли вы несколько потоков. Если это так, очень вероятно, что my_string переполняет (ограниченный) стек и, таким образом, неумышленно перекрывает глобальные данные.

Типичный стек в Linux составляет 8 МБ, а область защиты по умолчанию составляет 1 страницу (== 4 КБ). Это делает маловероятным, что вы фактически переполняете стек (8 МБ довольно велико) и что 1000-элементный my_string может «перешагнуть» защитную область, не касаясь ее (касание защитной области приводит к SIGSEGV).

Однако вполне вероятно, что вы не сообщили нам все соответствующие детали. Если вы создаете потоки с атрибутами не по умолчанию, возможно, вы создаете их с небольшим стеком и отключаете защитную область?

Хуже того, вы можете создавать поток с фиксированной областью стека (через pthread_attr_setstackaddr), и эта область фиксированного стека может быть глобальным массивом. Если вы (или какой-либо сторонний код, который вы вызываете) выполните , что , нет ничего, что могло бы отделить глобалы от других глобалов (которые теперь используются в качестве стека), а также столкновение (а также отсутствие охранный регион) вполне вероятно.

Переполнение также возможно без потоков, если вы используете сопрограммный стиль программирования (в основном потоки пользовательского уровня), например, через. makecontext / swapcontext или аналогичный механизм.

0 голосов
/ 19 декабря 2011

Размер стека определяется во время выполнения, а не во время компиляции. Запустите ulimit -s, чтобы узнать текущий максимальный размер стека, и передайте аргумент (например, ulimit -s 16384), чтобы увеличить его. Обе мои машины с Linux показывали 8192 как текущий размер стека, попробуйте увеличить его и посмотреть, работает ли ваше приложение лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...