-
Notifications
You must be signed in to change notification settings - Fork 4
/
linux.tex
96 lines (79 loc) · 4.51 KB
/
linux.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
\chapter{Linux Specific Q\&A} \label{chap:linux}
% Chapter 22: linux
이 chapter에서는 Linux 관련 질문/답변 그리고 여러 팁들을 다룹니다.
여기에서는 표준 C 언어 이외의 것도 다루며,
원 ``C Programming FAQs''와는 전혀 상관없이 역자가 만든 것임을 미리 밝힙니다.
아울러 이 chapter에 덧붙이고 싶은 것이 있으면 역자에게 알려 주시기 바랍니다.
역자의 연락처는 서문에 나와 있습니다.
\section{Memory Debugging} \label{sec:lmemdebug}
Linux에서는 메모리 관련 에러를 잡는 방법에 관한 내용입니다.
\begin{faq}
\q Linux에서 메모리 관련 버그를 쉽게 잡는 법이 있을까요?
\A 여러가지 메모리 디버깅 전용 툴들를 쓰면 됩니다. 역자가 주로 쓰는 툴들은 다음과 같습니다:
\begin{center}
\begin{tabular}{r|p{12cm}} \hline
이름 & 설명 \\ \hline
mtrace & GNU C 라이브러리(glibc)에 포함되어 있는 기능이며,
따로 설치할 필요가 없습니다. 기초적인 메모리 누수(leak)를 잡을 수 있습니다. \\
efence & ``Electric Fence''가 본명이며, 메모리 경계를 벗어나는 잘못된 read/write를
쉽게 잡을 수 있도록 도와줍니다. 소스를 컴파일할 때 제공하는 라이브러리를 같이
링크시켜서 씁니다. \\
valgrind & 위 두 기능을 모두 포함한 강력한 툴이며, 따로 소스를 다시 컴파일할 필요가
없습니다. 다만 x86 시스템에서만 동작하는 툴입니다. \\ \hline
\end{tabular}
\end{center}
각 툴에 대한 사용법은 XX를 참고하시기 바랍니다.
\end{faq}
\section{efence 쓰는법}
자신이 선언한 배열의 범위 밖의 메모리에 read/write를 하거나, 초기화되지 않은 포인터가
가리키는 메모리를 read/write하려 하면 (C 언어 정의에 따르면 `undefined behavior'가
일어나므로) 프로그램이 비정상적으로 동작할 수 있습니다. 경험상으로 이런 경우 크게 다음과 같은
현상이 일어날 수 있습니다:
\begin{enumerate}
\item 아무 문제없이 동작한다.
\item 정상적으로 동작하지만 프로그램이 끝날 때 segmentation fault가 일어난다.
\item 정상적으로 동작하지만 특정 조건이 만족되면 segmentation fault가 일어난다.
\item 전체적으로 프로그램 동작이 이상하다.
\item 프로그램이 제멋대로 동작하기 때문에 결과를 예측하기 어렵다.
\end{enumerate}
특정 조건이 만족될 때, segmentation fault\footnote{프로그램이 비정상적으로 끝나는 에러,
시스템에 따라서 bus error, general protection fault(GPF), 응용 프로그램 오류 등으로
나타날 수 있다.}가 일어나면 오히려 문제를 일으키는 코드를 찾기 쉽습니다. GDB와 같은 debugger를
실행해서 backtrace로 call stack을 추적해보면 바로 그 위치를 알 수 있기 때문입니다:
\begin{verbatim}
$ ./demo
Segmentation fault
$ gdb -q demo
(gdb) run
Starting program: /home/cinsk/src/sxml/demo
Program received signal SIGSEGV, Segmentation fault.
0x08050d87 in tree_add_child_tail (parent=0xbffa2730, child=0x10) at tree.h:166
166 child->parent = parent;
(gdb) backtrace
#0 0x08050d87 in tree_add_child_tail (parent=0xbffa2730, child=0x10)
at tree.h:166
#1 0x08050cd9 in xmlnode_add_child (parent=0xbffa2720, child=0x0)
at intrface.h:457
#2 0x08050523 in p_elements (xml=0x95c3008, parent=0xbffa2720,
preload=TK_STAG, save=1) at parse.c:1008
#3 0x0804f7e4 in p_document (xml=0x95c3008) at parse.c:93
#4 0x0804e1ef in sxml_load_file (xml=0x95c3008,
filename=0xbffbec68 "examples/large.xml") at intrface.c:243
#5 0x0804900b in main (argc=2, argv=0xbffa2824) at demo.c:95
(gdb) _
\end{verbatim}
즉, 위의 출력 결과를 보시면, 함수 \verb+tree_add_child_tail()+이며,
\verb+tree.h+의 166번째 줄에서 segmentation fault가 일어난 것을 알 수 있습니다.
그러나 이 상황은 매우 운이 좋았다고 말할 수 있습니다. 이런 식의 에러는 에러가 발생한 곳을 알면
바로 그 코드를 고쳐서 아주 쉽게 문제를 해결할 수 있지만, 문제는 어디에서 에러가 발생한 지 찾기가
힘든 경우가 대부분입니다.
Electric Fence를 쓰는 방법은 어렵지 않습니다. 단순히 컴파일할 때 `efence' 라이브러리와
함께 링크하면 됩니다.
\section{mtrace 사용법}
mtrace는 툴 이름이 아니고, 함수 이름입니다.
%
% Local Variables:
% coding: utf-8
% fill-column: 78
% End:
%