Про помилки й налагодженні UNIX

Кожному, хто хоч раз намагався написати програму, знайоме поняття

«Баг» (помилка) Єдине, що можна зробити, щоб написати програму без помилок, – це вибрати просту, без надмірностей конструкцію, акуратно її реалізувати і зберігати її простий по ходу будь-яких змін

Деякі засоби UNIX можуть допомогти у виявленні помилок, але треба сказати, що жодне з них не можна назвати першокласним Однак щоб показати це на прикладі, потрібна помилка, а всі програми в цій книзі досконалі Так що створимо типову помилку Розглянемо функцію pick, представлену вище Ось ще одна її версія, на цей раз з помилкою (чур, що не підглядати в оригінал)

pick (s) / * можливість вибору s * / char * s

{

fprintf(stderr,  &quot%s  &quot,  s) if  (ttyin()  ==  y)

printf(&quot%s\n&quot, s)

}

Що відбудеться, якщо скомпілювати і запустити програму

$ cc  pickc -o  pick

$ pick * c Пробуємо

Memory  fault  – core  dumped                     Катастрофа

$

«Memory fault» означає, що програма намагається послатися на область памяті, доступ до якої їй не дозволений Зазвичай так буває, коли покажчик посилається «в нікуди» Ще одне діагностичне повідомлення схожого змісту – це «bus error», воно часто виникає при скануванні незакінченої рядка

«Core dumped» означає, що ядро ​​зберегло стан виконуваної програми у файлі core в поточному каталозі Можна змусити програму записати дамп оперативної памяті, натиснувши ctl– \ (Якщо це інтерактивна програма) або ввівши команду kill -3 (якщо програма виконується у фоновому режимі)

«Розтин» виробляють дві програми – adb і sdb Як і більшість отладчиков, вони оповиті таємницею, складні і незамінні Програма adb входить до складу сьомої версії а sdb доступна в пізніших версіях системи Одна з них напевно є в кожній сістеме1

У цій книзі є можливість представити тільки мінімальна опис кожного з отладчиков: вивести трасування стека, тобто функцію, яка виконувалася в момент аварійного завершення програми, функцію, яка викликала її, і т д Функція, чиє імя стоїть першим у трасуванні, – це та функція, на якій програма перервалася

Щоб отримати трасування стека за допомогою adb, використовуємо команду $ C:

$ adb pick core Виклик adb

$C Запит трасування стека

~_strout(0175722,011,0,011200) adjust:         0

fillch:         060542

   doprnt(0177345,0176176,011200)

~fprintf(011200,0177345)

iop:

011200

fmt:

0177345

args:

0

~pick(0177345)

s:             0177345

1 Користувачі вільно розповсюджуваних ОС, таких як FreeBSD або Linux, можуть звернутися до отладчику gdb – Прямуючи науч ред

~main(035,0177234)

argc:

035

argv:

0177234

i:

01

buf:

0

ctld

Вихід

$

Це означає, що main викликала pick, яка викликала fprintf, вона, в свою чергу, викликала _doprnt, яка викликала _strout Так як

_doprnt не згадується ніде в pickc, проблема повинна бути десь у

fprintf або вище (Рядки після кожної підпрограми представляють значення локальних змінних Команда $ c пригнічує висновок такої інформації, а в деяких версіях adb це відбувається і при використанні самої команди $ C)

Перш ніж остаточно виявити помилку, спробуємо зробити те ж саме з допомогою sdb:

$ sdb  pick  core

Warning: `aout not  compiled  with  –g

lseek:  address 0xa64         Функція, на якій програма обірвалася

*t Запит трасування стека

lseek() fprintf(6154,2147479154) pick(2147479154) main(30,2147478988,2147479112)

*q Вихід

$

Інформація має різний формат, але суть одна і та ж: fprintf (Трас сіровкі виглядає по-іншому, тому що програма була запущена на іншій машині – VAX-11/750, на якій інакше реалізована стан дротяні бібліотека вводу-виводу) І дійсно, якщо подивитися на виклик fprintf в зіпсованої версії pick, то видно, що він хибний:

fprintf(&quot%s &quot,  s)

Відсутня stderr, тому що форматує рядок % s використовується як покажчик FILE, що, природно, викликає хаос

Ця помилка була обрана тому, що вона є досить поширеною, швидше за недогляд, а не через неправильне проектування

Можна виявити помилки виклику функції з неправильними аргументами, використовуючи верифікатор Сі lint (1) Програма lint обстежує програми, написані на Сі, на предмет можливих помилок, проблем з переносимістю і сумнівних конструкцій Якщо запустити lint для всього файлу pickc, помилка буде ідентифікована:

$ lint pickc

fprintf,  arg 1 used  inconsistently &quotllib–lc&quot(69) ::  &quotpickc&quot(28)

$

У перекладі це означає, що опис першого аргументу fprintf в стандартній бібліотеці відрізняється від способу його використання в 28-й рядку програми Це корисну вказівку на щось неправильне

Правда треба сказати, що lint застосовують з перемінним успіхом Верифікатор точно вказує, що ж у програмі невірно, але при цьому видає безліч не відносяться до справи повідомлень (у вищенаведеному прикладі вони опущені), так що необхідно володіти деякою кваліфікацією, щоб зрозуміти, на що варто звернути увагу, а що можна проігнорувати Зусилля винагороджуються, так як lint може знаходити такі помилки, які людина просто не в змозі помітити Варто запустити lint після довгого редагування і переконатися, що вам зрозумілі всі видавані попередження

Джерело: Керниган Б, Пайк Р, UNIX Програмне оточення – Пер з англ – СПб: Символ-Плюс, 2003 – 416 с, Мул

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*