ИУП: интенсив 7 дней + диагностический пакет (32 вопроса, 9 задач с автопроверкой)
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
Задача 09 — разбор падения.
|
||||
|
||||
1. Дефекты (сколько и какие):
|
||||
- ...
|
||||
- ...
|
||||
|
||||
2. Сборка и первые шаги:
|
||||
$ g++ -g -O0 -fsanitize=address,undefined crash.c -o crash
|
||||
$ ./crash world
|
||||
<что вывел ASAN — своими словами>
|
||||
|
||||
3. Команды gdb по шагам и что они показали:
|
||||
(gdb) ...
|
||||
...
|
||||
|
||||
4. Почему программа падала именно так (механизм):
|
||||
...
|
||||
|
||||
5. Что изменено в crash.c (минимальные правки):
|
||||
...
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Задача 09: программа с дефектами. Починить минимально. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *word = argc > 1 ? argv[1] : "hello";
|
||||
size_t n = strlen(word);
|
||||
|
||||
char *buf = malloc(n);
|
||||
if (!buf) {
|
||||
return 2;
|
||||
}
|
||||
strcpy(buf, word);
|
||||
|
||||
printf("len=%zu\n", strlen(buf));
|
||||
|
||||
free(buf);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Задача 09 — отладка: найти и исправить дефекты (gdb)
|
||||
|
||||
В `crash.c` лежит программа, которая падает на части входов и портит память.
|
||||
Задача — не переписать её с нуля, а **найти дефекты отладчиком и починить минимально**.
|
||||
|
||||
Ожидаемое поведение после починки:
|
||||
- `./crash` (без аргумента) печатает `len=5` и завершается с кодом 0;
|
||||
- `./crash <слово>` печатает `len=<длина слова>` и завершается с кодом 0;
|
||||
- `./crash ""` печатает `len=0` и завершается с кодом 0;
|
||||
- сборка с `-fsanitize=address,undefined` не даёт ни одного сообщения об ошибке.
|
||||
|
||||
Что сделать:
|
||||
1. Собрать с отладочной информацией и санитайзерами:
|
||||
`gcc -g -O0 -fsanitize=address,undefined crash.c -o crash`
|
||||
2. Разобраться, что именно портит память, а что приводит к падению при выходе.
|
||||
Полезно: `gdb ./crash`, `run`, `bt`, `frame`, `info locals`, `watch`.
|
||||
3. Исправить `crash.c` (минимальные правки, стиль сохранить).
|
||||
4. Заполнить `answer.txt`: сколько дефектов нашёл, какие именно, какими командами
|
||||
отладчика это подтвердил (по шагам), почему падало именно так.
|
||||
|
||||
Проверка: `python3 grade.py 09` — компилирует `crash.c` (компилятор C, gcc) с ASAN/UBSAN
|
||||
и прогоняет 5 входов.
|
||||
`answer.txt` проверяется ревью (это часть оценки: важен ход разбора, а не только результат).
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Тест задачи 09: сборка crash.c с ASAN/UBSAN и прогон входов."""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
SRC = os.path.join(HERE, "crash.c")
|
||||
BIN = os.path.join(HERE, "crash_checked")
|
||||
failures = 0
|
||||
|
||||
|
||||
def check(cond, name, extra=""):
|
||||
global failures
|
||||
if cond:
|
||||
print(f"ok {name}")
|
||||
else:
|
||||
print(f"FAIL {name} {extra}")
|
||||
failures += 1
|
||||
|
||||
|
||||
def main():
|
||||
r = subprocess.run(["gcc", "-g", "-O1", "-Wall", "-Wextra",
|
||||
"-fsanitize=address,undefined", "-fno-omit-frame-pointer",
|
||||
SRC, "-o", BIN], capture_output=True, text=True, timeout=180)
|
||||
check(r.returncode == 0, "сборка с ASAN/UBSAN прошла", r.stderr[:800])
|
||||
if r.returncode != 0:
|
||||
print("\nFAILURES: 1")
|
||||
sys.exit(1)
|
||||
|
||||
cases = [
|
||||
([], "len=5"),
|
||||
(["world"], "len=5"),
|
||||
(["a"], "len=1"),
|
||||
([""], "len=0"),
|
||||
(["x" * 300], "len=300"),
|
||||
]
|
||||
for args, expect in cases:
|
||||
try:
|
||||
run = subprocess.run([BIN] + args, capture_output=True, text=True, timeout=60,
|
||||
env={**os.environ, "ASAN_OPTIONS": "detect_leaks=1"})
|
||||
except subprocess.TimeoutExpired:
|
||||
check(False, f"вход {args or '<нет>'}: завершился за 60 c")
|
||||
continue
|
||||
out = run.stdout.strip()
|
||||
err = run.stderr
|
||||
label = f"вход {args[0][:12]!r}" if args else "вход без аргумента"
|
||||
check(run.returncode == 0, f"{label}: код возврата 0 (получен {run.returncode})")
|
||||
check(out == expect, f"{label}: вывод {expect!r} (получено {out!r})")
|
||||
check("AddressSanitizer" not in err and "runtime error" not in err,
|
||||
f"{label}: санитайзеры молчат", err[:400].replace("\n", " | "))
|
||||
|
||||
# answer.txt заполнен (проверка на «не оставил заготовку»)
|
||||
apath = os.path.join(HERE, "answer.txt")
|
||||
if os.path.exists(apath):
|
||||
txt = open(apath, encoding="utf-8").read()
|
||||
check("..." not in txt and len(txt) > 400, "answer.txt заполнен разбором (ревью отдельно)")
|
||||
else:
|
||||
check(False, "answer.txt: файл с разбором не найден")
|
||||
|
||||
print(f"\n{'FAILURES: %d' % failures if failures else 'ALL PASS'}")
|
||||
sys.exit(1 if failures else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user