Книга: Основы программирования в Linux

Lint удаление ошибок из ваших программ

Lint удаление ошибок из ваших программ

Первые системы UNIX предоставляли утилиту lint. Эта программа по существу — препроцессор компилятора С со вставленными тестами, обеспечивающими некоторые проверки с точки зрения здравого смысла и вывод предупреждений. Среди прочего она обнаруживает случаи применения переменных до того, как им было присвоено значение, или случаи неиспользования аргументов функций.

Более современные компиляторы C могут ценой производительности времени компиляции формировать аналогичные предупреждения. Утилиту lint, как таковую, обогнала стандартизация языка С. Поскольку средство основывалось на раннем компиляторе С, оно совсем не справляется с синтаксисом ANSI. Есть несколько коммерческих версий lint для UNIX и одна версия в Интернете для Linux, названная splint. Она известна под именем LClint, как часть проекта MIT (Massachusetts Institute of Technology, Массачусетский технологический институт), занимающегося разработкой средств формального описания. splint, средство подобное lint, может предоставлять полезные обзорные комментарии к программному коду. Найти splint можно по адресу http://www.splint.org.

Далее приведена первоначальная версия (debug0.c) программы-примера, которую вы уже отладили.

/*  1 */ typedef struct {
/*  2 */  char *data;
/*  3 */  int key;
/*  4 */ } item;
/*  5 */
/*  6 */ item array[j] = {
/*  7 */  {"bill", 3},
/*  8 */  {"neil", 4},
/*  9 */  {"john", 2},
/* 10 */  {"rick", 5},
/* 11 */  {"alex", 1},
/* 12 */ };
/* 13 */
/* 14 */ sort(a, n)
/* 15 */ item *a;
/* 16 */ {
/* 17 */  int i = 0, j = 0;
/* 18 */  int s;
/* 19 */
/* 20 */  for(; i < n & s != 0; i++) {
/* 21 */   s = 0;
/* 22 */   for(j = 0; j < n; j++) {
/* 23 */    if(a[j].key > a[j+1].key) {
/* 24 */     item t = a[j];
/* 25 */     a[j] = a[j+1];
/* 26 */     a[j+1] = t;
/* 27 */     s++;
/* 28 */    }
/* 29 */   }
/* 30 */   n--;
/* 31 */  }
/* 32 */ }
/* 33 */
/* 34 */ main()
/* 35 */ {
/* 36 */  sort(array,5);
/* 37 */ }

В этой версии есть проблема в строке 20, где вместо предполагаемого оператора && применяется оператор &. Далее приведен отредактированный пример вывода splint, выполненной с этой версией программы. Обратите внимание на то, как она обнаруживает проблемы в строке 20 — тот факт, что вы не инициализировали переменную s и что возможны проблемы с условием из-за некорректного оператора.

neil@susel03:~/BLP4e/chapter10> splint -strict debug0.c
Splint 3.1.1 --- 19 Mar 2005
debug0.c:7:18: Read-only string literal storage used as initial value for
               unqualified storage: array[0].data = "bill"
A read-only string literal is assigned to a non-observer reference. (Use -readonlytrans to inhibit warning)
debug0.c:8:18: Read-only string literal storage used as initial value for
               unqualified storage: array[1].data = "neil"
debug0.c:9:18: Read-only string literal storage used as initial value for
               unqualified storage: array[2].data = "john"
debug0.с:10:18: Read-only string literal storage used as initial value for
               unqualified storage: array[3].data = "rick"
debug0.c:11:18: Read-only string literal storage used as initial value for
               unqualified storage: array[4].data = "alex"
debug0.с:14:22: Old style function declaration
 Function definition is in old style syntax. Standard prototype syntax is
 preferred. (Use -oldstyle to inhibit warning)
debug0.с: (in function sort)
debug0.c:20:31: Variable s used before definition
 An rvalue is used that may not be initialized to a value on some execution
 path. (Use -usedef to inhibit warning)
debug0.с:20:23: Left operand of & is not unsigned value (boolean):
               i < n & s != 0
 An operand to a bitwise operator is not an unsigned values. This may have
 unexpected results depending on the signed representations. (Use
 -bitwisesigned to inhibit warning).
debug0.c:20:23: Test expression for for not boolean, type unsigned int:
               i < n & s != 0
 Test expression type is not boolean or int. (Use -predboolint to inhibit
 warning);
debug0.с:25:41: Undocumented modification of a[]: a[j] = a[j + 1]
 An externally-visible object is modified by a function with no /*@modifies@*/
 comment. The /*@modifies ... @*/ control comment can be used to give a
 modifies list for an unspecified function. (Use -modnomods to inhibit
 warning)
debug0.c:26:41: Undocumented modification of a[]: a[j + 1] = t
debug0.c:20:23: Operands of & are non-integer (boolean) (in post loop test):
               i < n & s != 0
 A primitive operation does not type check strictly. (Use -strictops to
 inhibit warning)
debug0.с:32:14: Path with no return in function declared to return int
 There is a path through a function declared to return a value on which there
 is no return statement. This means the execution may fall through without
 returning a meaningful result to the caller. (Use -noret to inhibit
 warning)
debug0.с:34:13: Function main declared without parameter list
 A function declaration does not have a parameter list. (Use -noparams
 to inhibit warning)
debug0.с: (in function main)
debug0.с:36:22: Undocumented use of global array
 A checked global variable is used in the function, but not listed in its
 globals clause. By default, only globals specified in .lcl files are
 checked.
 To check all globals, use +allglobals. To check globals selectively use
 /*@checked@*/ in the global declaration. (Use -globs to inhibit warning)
debug0.с:36:17: Undetected modification possible from call to unconstrained
               function sort: sort
 An unconstrained function is called in a function body where
 modifications are checked. Since the unconstrained function may modify
 anything, there may be undetected modifications in the checked function.
 (Use -modunconnomods to inhibit warning)
debug0.c:36:17: Return value (type int) ignored: sort(array, 5)
 Result returned by function call is not used. If this is intended, can
 cast result to (void) to eliminate message. (Use -retvalint to inhibit
 warning)
debug0.c:37:14: Path with no return in function declared to return int
debug0.c:6:18: Variable exported but not used outside debug0: array
 A declaration is exported, but not used outside this module. Declaration
 can use static qualifier. (Use -exportlocal to inhibit warning)
debug0.c:14:13: Function exported but not used outside debug0: sort
 debug0.c:15:17: Definition of sort
debug0.c:6:18: Variable array exported but not declared in header file
 A variable declaration is exported, but does not appear in a header
 file. (Used with exportheader.) (Use -exportheadervar to inhibit warning)
debug0.c:14:13: Function sort exported but not declared in header file
 A declaration is exported, but does not appear in a header file. (Use
 -exportheader to inhibit warning)
debug0.c:15:17: Definition of sort
Finished checking - 22 code warnings
$

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

Она также обнаружила две реальные ошибки в следующем фрагменте кода:

/* 18 */  int s;
/* 19 */
/* 20 */  for(; i < n & s != 0; i++) {
/* 21 */   s = 0;

Средство splint определило (выделенные цветом строки предыдущего вывода), что переменная s используется в строке 20, но не была при этом инициализирована, и что оператор & стоит на месте более обычного оператора &&. В данном случае старшинство оператора изменяет значение условия и создает проблему в программе.

Обе эти ошибки были исправлены при чтении исходного текста программы до запуска процесса отладки. Несмотря на то, что пример мало изобретателен и служит только для демонстрации, подобные ошибки регулярно возникают в реальных программах."

Оглавление книги


Генерация: 1.220. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз