Я нашел фрагмент, похожий на этот, в каком-то (C ++) коде, который я готовлю для 64-битного порта.
int n;
size_t pos, npos;
/* ... initialization ... */
while((pos = find(ch, start)) != npos)
{
/* ... advance start position ... */
n++; // this will overflow if the loop iterates too many times
}
Хотя я серьезно сомневаюсь, что это может вызвать проблемы даже в приложениях, интенсивно использующих память, стоит взглянуть с теоретической точки зрения, поскольку подобные ошибки могут привести к тому, что вызовет проблемы. (Измените n
на short
в приведенном выше примере, и даже небольшие файлы могут переполнить счетчик.)
Инструменты статического анализа полезны, но они не могут напрямую обнаруживать подобные ошибки. (Во всяком случае, пока.) Счетчик n
вообще не участвует в выражении while
, так что это не так просто, как в других циклах (где ошибки при типизации отдают ошибку). Любой инструмент должен был бы определить, что цикл будет выполняться более 2 31 раз, но это означает, что он должен быть в состоянии оценить, сколько раз выражение (pos = find(ch, start)) != npos
будет оценивать как истинное - не маленький подвиг! Даже если инструмент может определить, что цикл может выполнить более 2 31 раз (скажем, потому что он распознает, что функция find
работает со строкой), как он мог узнать что цикл не будет выполняться более 2 64 раз, переполняя тоже значение size_t
?
Кажется очевидным, что для окончательного выявления и исправления такого рода ошибки требуется человеческий глаз, но существуют ли шаблоны, которые выдают такую ошибку, чтобы ее можно было проверить вручную? Какие подобные ошибки существуют, за которыми я должен следить?
РЕДАКТИРОВАТЬ 1: Поскольку типы short
, int
и long
по своей сути проблематичны, такого рода ошибки можно обнаружить, изучив каждый экземпляр этих типов. Однако, учитывая их повсеместное распространение в унаследованном коде C ++, я не уверен, что это практично для большого программного обеспечения. Что еще выдает эту ошибку? Может ли каждый цикл while
выдавать какую-то ошибку, подобную этой? (for
циклы определенно не застрахованы от этого!) Насколько ужасна такая ошибка, если мы не имеем дело с 16-битными типами, такими как short
?
EDIT 2: Вот еще один пример, показывающий, как эта ошибка появляется в цикле for
.
int i = 0;
for (iter = c.begin(); iter != c.end(); iter++, i++)
{
/* ... */
}
По сути, это та же проблема: циклы рассчитывают на некоторую переменную, которая никогда напрямую не взаимодействует с более широким типом. Переменная может все еще переполняться, но ни один компилятор или инструмент не обнаружит ошибку приведения. (Строго говоря, нет.)
РЕДАКТИРОВАТЬ 3: Код, с которым я работаю, очень большой. (10-15 миллионов строк кода только для C ++.) Все это невозможно проверить, поэтому я особенно заинтересован в способах автоматического выявления такого рода проблем (даже если это приводит к высокой вероятности ложных срабатываний).