Почему компиляторы не предупреждают о за пределы статических индексах массива?

В Python 3.3 +:

from subprocess import STDOUT, check_output

output = check_output(cmd, stderr=STDOUT, timeout=seconds)

output представляет собой байтовую строку, содержащую объединенные stdout команды, данные stderr.

Этот код повышает значение CalledProcessError при ненулевом статусе выхода, как указано в тексте вопроса, в отличие от метода proc.communicate().

Я удалил shell=True, потому что он часто используется без необходимости. Вы всегда можете добавить его обратно, если cmd действительно требует его. Если вы добавите shell=True, то есть, если дочерний процесс порождает своих потомков; check_output() может вернуться намного позже, чем указывает таймаут, см. Ошибка тайм-аута подпроцесса .

Функция тайм-аута доступна на Python 2.x через subprocess32 backport модуля подпроцесса 3.2+.

20
задан Adam Rosenfield 20 December 2008 в 06:03
поделиться

10 ответов

GCC делает , предупреждают об этом. Но необходимо сделать две вещи:

  1. Включают оптимизацию. Без, по крайней мере-O2, GCC не делает достаточного анализа для знания то, что a, и что Вы убежали край.
  2. Изменение Ваш пример так, чтобы [] на самом деле использовался, иначе GCC, не генерирует никакую-op программу и полностью отбросил Ваше присвоение.

.

$ cat foo.c 
int main(void)
{
  int a[10];
  a[13] = 3;  // oops, overwrote the return address
  return a[1];
}
$ gcc -Wall -Wextra  -O2 -c foo.c 
foo.c: In function ‘main’:
foo.c:4: warning: array subscript is above array bounds

BTW: Если бы Вы возвратились [13] в Вашей тестовой программе, которая не работала бы также, поскольку GCC оптимизирует массив снова.

27
ответ дан 29 November 2019 в 22:53
поделиться

Вы правы, , поведение не определено . Указатели C99 должны указать в или всего один элемент вне заявленных или выделенных "куче" структур данных.

я никогда не мог выяснить, как эти gcc люди решают, когда предупредить. Я был потрясен узнать, что -Wall отдельно не предупредит о неинициализированных переменных; в минимуме Вам нужно -O, и даже затем предупреждение иногда опускается.

я предугадываю, что, потому что неограниченные массивы являются настолько общими в C, компилятор, вероятно, не имеет пути в своих деревьях выражений к , представляют массив, которому знали размер во время компиляции. Таким образом, хотя информация присутствует в объявлении, я предугадываю, что при использовании это уже потеряно.

я 1111-секундный рекомендация valgrind. , Если Вы программируете в C, Вы должны выполнять valgrind на каждой программе, все время , пока Вы больше не можете получать удар производительности.

7
ответ дан 29 November 2019 в 22:53
поделиться

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

-fmudflap -fmudflapth -fmudflapir Для фронтендов, которые поддерживают его (C и C++), инструмент все опасные операции разыменования указателя/массива, некоторая стандартная библиотека функции string/heap и некоторые другие связанные конструкции с тестами диапазона/законности. Модули, так оснащенные, должны быть неуязвимы для переполнения буфера, недопустимого использования "кучи" и некоторых других классов программных ошибок C/C++. instrumen ‐ tation полагается на отдельную библиотеку времени выполнения (libmudflap), который будет связан в программу, если-fmudflap будет дан во время ссылки. Поведением во время выполнения оснащенной программы управляет переменная среды MUDFLAP_OPTIONS. См. "огибающий MUDFLAP_OPTIONS =-help a.out" для его опций.

Используйте-fmudflapth вместо-fmudflap, чтобы скомпилировать и связаться, если Ваша программа является многопоточной. Используйте-fmudflapir, в дополнение к-fmudflap или-fmudflapth, если инструментарий должен проигнорировать чтения указателя. Это производит меньше инструментария (и там ‐ переднее более быстрое выполнение) и все еще обеспечивает некоторую защиту против прямых записей повреждения памяти, но позволяет ошибочно считанным данным распространять в рамках программы.

Вот то, что брызговик дает мне для Вашего примера:

[js@HOST2 cpp]$ gcc -fstack-protector-all -fmudflap -lmudflap mudf.c        
[js@HOST2 cpp]$ ./a.out
*******
mudflap violation 1 (check/write): time=1229801723.191441 ptr=0xbfdd9c04 size=56
pc=0xb7fb126d location=`mudf.c:4:3 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x3d) [0xb7fb126d]
      ./a.out(main+0xb9) [0x804887d]
      /usr/lib/libmudflap.so.0(__wrap_main+0x4f) [0xb7fb0a5f]
Nearby object 1: checked region begins 0B into and ends 16B after
mudflap object 0x8509cd8: name=`mudf.c:3:7 (main) a'
bounds=[0xbfdd9c04,0xbfdd9c2b] size=40 area=stack check=0r/3w liveness=3
alloc time=1229801723.191433 pc=0xb7fb09fd
number of nearby objects: 1
[js@HOST2 cpp]$

Это имеет набор опций. Например, это может разветвиться от процесса gdb после нарушений, может показать Вам где Ваша пропущенная программа (использование -print-leaks) или обнаружьте чтения неинициализированной переменной. Использовать MUDFLAP_OPTIONS=-help ./a.out получить список опций. Начиная с брызговика только выходные адреса и не имена файлов и строки источника, я записал немного сценария простофили:

/^ / {
    file = gensub(/([^(]*).*/, "\\1", 1);
    addr = gensub(/.*\[([x[:xdigit:]]*)\]$/, "\\1", 1);
    if(file && addr) {
        cmd = "addr2line -e " file " " addr
        cmd | getline laddr
        print $0 " (" laddr ")"
        close (cmd)
        next;
    }
}

1 # print all other lines

Передайте вывод по каналу брызговика в него, и он отобразит исходный файл и строку каждой записи следа.

Также -fstack-protector[-all] :

-fstack-protector Испустите дополнительный код для проверки на переполнение буфера, такое как нападения разрушения стека. Это сделано путем добавления защитной переменной к функциям с уязвимыми объектами. Это включает функции, которые называют alloca и функции с буферами больше, чем 8 байтов. Защита инициализируется, когда функция вводится и затем проверяется, когда функция выходит. Если защитная проверка перестала работать, сообщение об ошибке печатается и выходы программы.

-fstack-protector-all Как - fstack-средство-защиты за исключением того, что все функции защищены.

10
ответ дан 29 November 2019 в 22:53
поделиться

Это не статический массив.

Неопределенное поведение или нет, это пишет в адрес 13 целых чисел с начала массива. Что существует Ваша ответственность. Существует несколько методов C, которые намеренно нерационально размещают массивы по разумным причинам. И эта ситуация весьма обычна в неполных единицах компиляции.

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

Это - путь C. Это - Ваш массив, Ваша память, сделайте то, что Вы хотите с ним. :)

(Существует любое количество инструментов линта для помощи Вам найти этот вид вещи; и необходимо использовать их подробно. Они все не работают через компилятор хотя; Компиляция и соединение часто достаточно утомительны как есть)

5
ответ дан 29 November 2019 в 22:53
поделиться

Причина C не делает этого, то, что C не имеет информации. Оператор как

int a[10];

делает две вещи: это выделяет sizeof(int)*10 байты пространства (плюс, потенциально, немного мертвой зоны для выравнивания), и это помещает запись в таблицу символов, которая читает, концептуально,

a : address of a[0]

или в терминах C

a : &a[0]

, и это - все. На самом деле в C можно чередоваться *(a+i) с a[i] в (почти*) все случаи без эффекта ПО ОПРЕДЕЛЕНИЮ. Таким образом, Ваш вопрос эквивалентен выяснению, "почему я могу добавить какое-либо целое число к этому (адрес) значение?"

* тест Pop: каков один случай в этом, это не верно?

4
ответ дан 29 November 2019 в 22:53
поделиться

Философия C - то, что программист всегда прав . Таким образом, это тихо позволит Вам получать доступ безотносительно адреса памяти, Вы даете там, предполагая, что Вы всегда знаете то, что Вы делаете и не побеспокоите Вас предупреждением.

4
ответ дан 29 November 2019 в 22:53
поделиться

Я полагаю, что некоторые компиляторы делают в определенных случаях. Например, если моя память служит мне правильно, более новые компиляторы Microsoft имеют опцию "Buffer Security Check", которая обнаружит тривиальные случаи переполнения буфера.

, Почему все компиляторы не делают этого? Любой (как ранее упомянуто) внутреннее представление, используемое компилятором, не предоставляет себя этому типу статического анализа, или это просто не достаточно высоко из списка приоритетов устройств записи. Который честно говоря, позор так или иначе.

2
ответ дан 29 November 2019 в 22:53
поделиться

разве компилятор не должен испускать предупреждение по крайней мере?

Нет; компиляторы C обычно не формуют граничные проверки массива. Очевидный отрицательный эффект этого, как Вы упоминаете, ошибка с неопределенным поведением, которое может быть очень трудно найти.

положительная сторона этого является возможным небольшим преимуществом производительности в определенных случаях.

2
ответ дан 29 November 2019 в 22:53
поделиться

Существует некоторое расширение в gcc для того (со стороны компилятора) http://www.doc.ic.ac.uk/~awl03/projects/miro/

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

также можно использовать valgrind на коде и видеть вывод. http://valgrind.org/

другая библиотека, которой широко пользуются, кажется, libefence

, Это - просто проектное решение сделанные. Который теперь приводит к этому вещи.

Friedrich

Отношений
0
ответ дан 29 November 2019 в 22:53
поделиться

- fbounds-проверка опции доступна с gcc.

стоящий прохождения через эту статью http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html

'le dorfier' дал способный ответ на Ваш вопрос, хотя, его Ваша программа и это являются путем C, ведет себя.

0
ответ дан 29 November 2019 в 22:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: