An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình

• Lỗ hổng tràn bộ đệm (Buffer Overflow)

• Lỗ hổng tràn số nguyên

• Lỗ hổng xâu định dạng

• Cơ bản về lập trình an toàn

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 1

Trang 1

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 2

Trang 2

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 3

Trang 3

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 4

Trang 4

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 5

Trang 5

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 6

Trang 6

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 7

Trang 7

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 8

Trang 8

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 9

Trang 9

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình trang 10

Trang 10

Tải về để xem bản đầy đủ

pdf 29 trang minhkhanh 9680
Bạn đang xem 10 trang mẫu của tài liệu "An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình

An ninh mạng máy tính - Bài 10: An toàn vùng nhớ tiến trình
1BÀI 10.
AN TOÀN VÙNG NHỚ TIẾN TRÌNH
Bùi Trọng Tùng,
Viện Công nghệ thông tin và Truyền thông,
Đại học Bách khoa Hà Nội
1
Nội dung
• Lỗ hổng tràn bộ đệm (Buffer Overflow)
• Lỗ hổng tràn số nguyên
• Lỗ hổng xâu định dạng
• Cơ bản về lập trình an toàn
2
1
2
22020 CWE Top 25
• Danh sách 25 lỗ hổng phần mềm nguy hiểm nhất: 4 trong 
số Top 10 là dạng lỗ hổng truy cập bộ nhớ
+1 lỗ hổng liên quan: CWE-20
3
1. TỔNG QUAN VỀ TIẾN TRÌNH (NHẮC LẠI)
Bùi Trọng Tùng,
Viện Công nghệ thông tin và Truyền thông,
Đại học Bách khoa Hà Nội
4
3
4
3Tiến trình là gì?
• Là chương trình đang được thực hiện
• Các tài nguyên tối thiểu của tiến trình:
Vùng nhớ được cấp phát
Con trỏ lệnh(Program Counter)
Các thanh ghi của CPU
• Khối điều khiển tiến trình(Process Control Block-PCB): 
Cấu trúc chứa thông tin của tiến trình
5
Bộ nhớ của tiến trình(Linux 32-bit)
6
0xffffffff
0x00000000
Thực tế đây là bộ 
nhớ ảo với địa chỉ 
ảo, sẽ được 
HĐH/CPU ánh xạ 
sang địa chỉ vật lý
Tiến trình coi bộ 
nhớ thuộc toàn bộ 
sở hữu của nó
5
6
4Bộ nhớ của tiến trình(Linux 32-bit)
7
0xffffffff
0x00000000
Unused
0x08048000
Kernel 0xc0000000
Text
Data
BSS
Heap
Stack
Xác định ở thời 
điểm biên dịch
Thay đổi khi 
thực thi
Thiết lập khi tiến 
trình bắt đầu
Không gian địa chỉ 
của thiết bị vào-ra
cmdline & env
Vùng nhớ stack và heap
8
0xffffffff0x00000000
Heap Stack
Trình biên dịch cung cấp các hàm làm thay đổi kích 
thước vùng nhớ stack khi thực thi chương trình
push 1
push 2
push 3
return
123
Con trỏ 
stackĐược quản lý trong tiến 
trình bởi các hàm cấp 
phát bộ nhớ động 
(malloc, calloc)
7
8
5Stack - Thực hiện lời gọi hàm
9
caller’s dataarg2arg1
void func(char *arg1, int arg2)
{
char loc1[4];
int loc2;
}
loc1loc2
Các tham số đưa 
vào stack theo 
thứ tự ngược
Các cục bộ được 
đưa vào stack 
theo thứ tự
0xffffffff
8 byte giữa các 
tham số và các biến
??? ???
Stack frame
10
caller’s dataarg2arg1
void func(char *arg1, int arg2)
{
char loc1[4];
int loc2;
}
loc1loc2
0xffffffff
Stack frame: Một phần của vùng nhớ stack 
tương ứng với lời gọi của một hàm
??? ???
9
10
6Stack frame
11
main()countUp(3)
void main(){ countUp(3);}
void countUp(int n)
{
if(n > 1)
countUp(n-1);
printf(“%d\n”, n);
}
0xffffffff
countUp(2)countUp(1)
Con trỏ 
stack
Stack frame
12
caller’s dataarg2arg1
void func(char *arg1, int arg2)
{
char loc1[4];
int loc2;
loc2++;
}
loc1loc2
0xffffffff
???
Không thể đoán 
được ở thời 
điểm dịch
???
%ebp
Q: loc2 nằm ở đâu?
A: -8(%ebp)
• %ebp: con trỏ frame.
• (%ebp): nội dung vùng nhớ trỏ bởi %ebp
11
12
7Stack – Trả về từ hàm
13
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1loc1loc2
0xffffffff
??? ???
%ebp %ebp
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
?
Stack – Trả về từ hàm
14
int main()
{
...
func(“Hey”, 10);
...
}
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
caller’s dataarg2arg1???
%ebp
%esp
13
14
8Stack – Trả về từ hàm
15
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1
0xffffffff
%ebp ???
%ebp
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
1. Đưa %ebp vào stack trước biến cục bộ (pushl %ebp)
%esp
Stack – Trả về từ hàm
16
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1
0xffffffff
%ebp ???
%ebp
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
1. Đưa %ebp vào stack trước biến cục bộ (pushl %ebp)
2. Thiết lập %ebp bằng với %esp (movl %esp %ebp)
loc1loc2
15
16
9Stack – Trả về từ hàm
17
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1
0xffffffff
%ebp ???
Q: Làm cách nào để thực thi 
tiếp lệnh sau khi hàm trả về
1. Đưa %ebp vào stack trước biến cục bộ (pushl %ebp)
2. Thiết lập %ebp bằng với %esp (movl %esp %ebp)
3. Khi hàm trả về, thiết lập %ebp bằng (%ebp) (movl (%ebp) %ebp)
loc1loc2
%ebp
Con trỏ lệnh - %eip
18
Text
...
0x4a7 mov $0x0,%eax
0x4a2 call 
0x49b movl $0x804..,(%esp)
0x493 movl $0xa,0x4(%esp)
...
...
0x5bf mov %esp,%ebp
0x5be push %ebp
...
%eip
17
18
10
Stack – Trả về từ hàm
19
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1
0xffffffff
%ebp %eip
%ebp
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
Đưa %eip của 
lệnh tiếp theo 
vào stack trước 
khi gọi hàm
loc1loc2
Stack – Trả về từ hàm
20
int main()
{
...
func(“Hey”, 10);
...
}
caller’s dataarg2arg1
0xffffffff
%ebp %eip
%ebp
Q: Làm cách nào để khôi 
phục %ebp của hàm gọi
Đưa %eip của 
lệnh tiếp theo 
vào stack trước 
khi gọi hàm
loc1loc2
Thiết lập %eip bằng 
4(%ebp) khi trả về
19
20
11
Stack – Trả về từ hàm
21
return;
arg2arg1%ebp %eip
%ebp
Trong C
Con trỏ frame cũ
loc1text
leave: mov %ebp %esp
pop %ebp
ret: pop %eip
Mã assembly sau khi dịch
Caller’s 
stack frame
%esp
Caller’s 
code
loc2
%eip
Callee’s 
stack frame
Stack – Trả về từ hàm
22
return;
arg2arg1%ebp %eip
%ebp
Trong C
Con trỏ frame cũ
loc1text
leave: mov %ebp %esp
pop %ebp
ret: pop %eip
Mã assembly sau khi dịch
Caller’s 
stack frame
%esp
Caller’s 
code
loc2
%eip
Callee’s 
stack frame
21
22
12
Stack – Trả về từ hàm
23
return;
arg2arg1%ebp %eip
%ebp
Trong C
loc1text
leave: mov %ebp %esp
pop %ebp
ret: pop %eip
Mã assembly sau khi dịch
Caller’s 
stack frame
%esp
Caller’s 
code
loc2
%eip
Callee’s 
stack frame
Stack – Trả về từ hàm
24
return;
arg2arg1%ebp %eip
%ebp
Trong C
loc1text
leave: mov %ebp %esp
pop %ebp
ret: pop %eip
Mã assembly sau khi dịch
Caller’s 
stack frame
%esp
Caller’s 
code
loc2
%eip
Callee’s 
stack frame
23
24
13
Stack – Trả về từ hàm
25
return;
arg2arg1%ebp %eip
%ebp
Trong C
loc1text
leave: mov %ebp %esp
pop %ebp
ret: pop %eip
Mã assembly sau khi dịch
Caller’s 
stack frame
%esp
Caller’s 
code
loc2
%eip
Callee’s 
stack frame
Các lệnh tiếp theo xóa tham số khỏi stack
Tổng kết
Hàm gọi(trước khi gọi):
1. Đẩy các tham số vào stack theo thứ tự ngược
2. Đẩy địa chỉ trả về vào stack, ví dụ %eip + 2
3. Nhảy tới địa chỉ của hàm được gọi
Hàm được gọi:
4. Đẩy %ebp cũ vào stack
5. Thiết lập %ebp tới đỉnh của stack
6. Đẩy các biến cục bộ vào stack truy cập theo độ lệch từ %ebp
Hàm được gọi trả về:
7. Thiết lập lại %ebp cũ
8. Nhảy tới địa chỉ trả về
Hàm gọi:
9. Xóa các tham số khỏi stack
26
25
26
14
2. TẤN CÔNG TRÀN BỘ ĐỆM
Bùi Trọng Tùng,
Viện Công nghệ thông tin và Truyền thông,
Đại học Bách khoa Hà Nội
27
Khái niệm
• Bộ đệm (Buffer): tập hợp liên tiếp các phần tử có kiểu dữ 
liệu xác định
Ví dụ: Trong ngôn ngữ C/C++, xâu là bộ đệm của các ký tự
Có thể hiểu theo nghĩa rộng: bộ đệm = vùng nhớ chứa dữ liệu
• Tràn bộ đệm (Buffer Overflow): Đưa dữ liệu vào bộ đệm 
nhiều hơn khả năng chứa của nó
• Lỗ hổng tràn bộ đệm: Không kiểm soát kích thước dữ liệu 
đầu vào.
• Tấn công tràn bộ đệm: Phần dữ liệu tràn ra khỏi bộ đệm 
làm thay đổi luồng thực thi của tiến trình.
Dẫn tới một kết quả ngoài mong đợi
• Ngôn ngữ bị ảnh hưởng: C/C++
28
27
28
15
C/C++ vẫn rất phổ biến(2020)
29
Sự phổ biến của lỗ hổng BoF
910
880
704
841
287
6.21
5.33
4.07
4.58
5.25
0
1
2
3
4
5
6
7
0
100
200
300
400
500
600
700
800
900
1000
2017 2018 2019 2020 2021
S
ố
 lỗ
 h
ổ
n
g
Sự phổ biến của lỗ hổng Buffer Overflow
Số lỗ hổng Tỉ lệ (%)
30
29
30
16
Ví dụ về tràn bộ đệm
31
void func(char *arg1)
{
char buffer[4];
strcpy(buffer, arg1);
return;
}
int main()
{
char *mystr = “AuthMe!”;
func(mystr);
...
}
&arg100 00 00 00
buffer
%ebp %eip
Ví dụ về tràn bộ đệm
32
void func(char *arg1)
{
char buffer[4];
strcpy(buffer, arg1);
return;
}
int main()
{
char *mystr = “AuthMe!”;
func(mystr);
...
}
&arg1A u t h
buffer
4d 65 21 00 %eip
M e ! \0
31
32
17
Ví dụ về tràn bộ đệm
33
void func(char *arg1)
{
char buffer[4];
strcpy(buffer, arg1);
return;
}
int main()
{
char *mystr = “AuthMe!”;
func(mystr);
...
}
&arg1A u t h
buffer
4d 65 21 00 %eip
M e ! \0
pop %ebp %ebp = 0x0021654d
 SEGMENTATION FAULT
Tràn bộ đệm – Ví dụ khác
34
void func(char *arg1)
{
int authenticated = 0
char buffer[4];
strcpy(buffer, arg1);
if(authenticated){//privileged execution}
}
int main()
{
char *mystr = “AuthMe!”;
func(mystr);
...
}
Hàm được thực 
thi như thế nào?
&arg1A u t h
buffer
4d 65 21 00 %eip
M e ! \0
authenticated
%ebp
33
34
18
Tràn bộ đệm – Ví dụ khác
35
void func(char *arg1)
{
int authenticated = 0
char buffer[4];
strcpy(buffer, arg1);
if(authenticated){//privileged execution}
}
int main()
{
char *mystr = “AuthMe!”;
func(mystr);
...
}
Người dùng có thể ghi đè dữ liệu tùy ý tới các vùng nhớ khác
Khai thác lỗ hổng tràn bộ đệm
• Lỗ hổng tràn bộ đệm cho phép kẻ tấn công truy cập 
(read/write/execute) tùy ý vào vùng nhớ khác
• Phương thức khai thác phổ biến nhất: chèn mã nguồn 
thực thi (code injection)
• Ý tưởng
36
Malcode00 00 00 00
buffer
%ebp %eip &arg1 text
%eip %eipX
35
36
19
Code Injection
• Vấn đề 1: Nạp mã độc(malcode) vào stack
Phải là mã máy
Không chứa byte có giá trị 0
Không sử dụng bộ nạp (loader)
Không sử dụng vùng nhớ stack
• Vấn đề 2: Nạp đúng các địa chỉ lệnh thực thi sau khi kết 
thúc lời gọi hàm Xác định đúng %eip
Mức độ khó khi xác định giá trị %eip phụ thuộc vị trí của malcode 
• Vấn đề 3: Nạp đúng địa chỉ trả về Xác định đúng %ebp
37
Buffer Overflow – Phòng chống
• Secure Coding: sử dụng các hàm an toàn có kiểm soát 
kích thước dữ liệu đầu vào.
fgets(), strlcpy(), strlcat()
• Stack Shield:
Lưu trữ địa chỉ trả về vào vùng nhớ bảo vệ không thể bị ghi đè
Sao chép địa chỉ trả về từ vùng nhớ bảo vệ
• Stack Guard: sử dụng các giá trị canh giữ (canary) để 
phát hiện mã nguồn bị chèn
• Non-executable stack: Không cho phép thực thi mã 
nguồn trong stack
Linux: sysctl -w kernel.exec-shield=0
Vẫn bị khai thác bởi kỹ thuật return-to-libc
38
37
38
20
Sử dụng giá trị canh giữ - Ví dụ 
39
callee()
{
int canary = random;
char buffer[];
...
if(canary!=random)
//detect attack
else return;
}
static int random;
caller()
{
random = rand();
callee();
}
&arg100 00 00 00
buffer
4d 65 21 00 %eip
canary
&arg1
buffer
4d 65 21 00 %eip
canary
Buffer Overflow attack
Buffer Overflow – Phòng chống
• Address Space Layout Randomization
40
0xffffffff
0x00000000
0x08048000
0xc0000000
Xác định ở thời 
điểm biên dịch
Thay đổi khi thực 
thi
Thiết lập khi tiến trình 
bắt đầu
Không gian địa chỉ 
của thiết bị vào-ra Unused
Kernel
Text
Data
BSS
Heap
Stack
cmdline & env
Nạp vào với địa chỉ 
bắt đầu của mỗi 
vùng là ngẫu nhiên
39
40
21
3. MỘT SỐ LỖ HỔNG TRUY CẬP BỘ NHỚ KHÁC
Bùi Trọng Tùng,
Viện Công nghệ thông tin và Truyền thông,
Đại học Bách khoa Hà Nội
41
Lỗ hổng xâu định dạng
• Format String: Xâu định dạng vào ra dữ liệu
• Lỗ hổng Format String: xâu định dạng không phù hợp với 
danh sách tham số
• Ví dụ
42
void func()
{
char buf[32];
if(fgets(buf, sizeof(buf),stdin) == NULL)
return;
printf(buf);
}
&fmt%ebp %eip
printf’s stack frame Caller’s stack 
frame
41
42
22
Lỗ hổng xâu định dạng
• printf(“%d”);
Hiển thị 4 byte phía trước địa chỉ đầu tiên của stack frame của hàm 
printf
• printf(“%s”);
Hiển thị các byte cho tới khi gặp ký tự kết thúc xâu
• printf(“%d%d%d”)
Hiển thị chuỗi byte dưới dạng số nguyên
• printf(“%x%x%x”)
Hiển thị chuỗi byte dưới dạng hexa
• printf(“%n”):
Ghi số byte đã hiển thị vào vùng nhớ
43
Lỗ hổng tràn số nguyên
• Trong máy tính, số nguyên được biểu diễn bằng trục số 
tròn. Dải biểu diễn:
Số nguyên có dấu: [–2n – 1, 2n–1 – 1]
Số nguyên không dấu: [0, 2n – 1]
• Integer Overflow: Biến số nguyên của chương trình nhận 
một giá trị nằm ngoài dải biểu diễn. Ví dụ
Số nguyên có dấu: 0x7ff..f + 1 = 0x80..0, 0xff..f + 1 = 0x0
Số nguyên không dấu: 0xff..f + 1 = 0x0, 0x0 – 1 = 0xff...f
• Ngôn ngữ bị ảnh hưởng: Tất cả
• Việc không kiểm soát hiện tượng tràn số nguyên có thể 
dẫn đến các truy cập các vùng nhớ mà không thể kiểm 
soát.
44
43
44
23
Lỗ hổng tràn số nguyên – Ví dụ 1
• Lỗ hổng nằm ở đâu?
45
#define MAX 1024
void vul_func1()
{
char buff[1024];
int len = recv_len_from_client();
char *mess = recv_mess_from_client();
if (len > 1024)
printf (“Too large”);
else
memcpy(buf, mess, len);
}
Lỗ hổng tràn số nguyên – Ví dụ 2
46
int main()
{
int *arr;
int len;
printf(“Number of items: ”); scanf(“%d”, &len);
arr = malloc(len * sizeof(int));
for(int i = 0; i < len; i++)
scanf(“%d”, arr[i]);
return 0;
}
• Lỗ hổng nằm ở đâu?
45
46
24
4. LẬP TRÌNH AN TOÀN
Bùi Trọng Tùng,
Viện Công nghệ thông tin và Truyền thông,
Đại học Bách khoa Hà Nội
47
Lập trình an toàn
• Yêu cầu: Viết mã nguồn chương trình để đạt được các 
mục tiêu an toàn bảo mật
• Bao gồm nhiều kỹ thuật khác nhau:
Kiểm soát giá trị đầu vào
Kiểm soát truy cập bộ nhớ chính
Che giấu mã nguồn
Chống dịch ngược
Kiểm soát kết quả đầu ra
Kiểm soát quyền truy cập

• Bài này chỉ đề cập đến một số quy tắc và nhấn mạnh vào 
vấn đề truy cập bộ nhớ một cách an toàn
48
47
48
25
An toàn truy cập bộ nhớ
• An toàn không gian(Spatial safety): thao tác chỉ nên truy 
cập vào đúng vùng nhớ đã xác định
• Nếu gọi:
b: địa chỉ ô nhớ đầu tiên của vùng nhớ được chỉ ra
p: địa chỉ cần truy cập tới
e: địa chỉ ô nhớ cuối cùng của vùng nhớ được chỉ ra
s: kích thước vùng nhớ cần truy cập
• Thao tác truy cập bộ nhớ chỉ an toàn khi và chỉ khi:
b ≤ p ≤ e – s
• Lưu ý: Các toán tử tác động trên p không làm thay đổi b
và e.
49
An toàn không gian – Ví dụ
• Lỗi truy cập không an toàn về không gian gây ra các lỗ 
hổng như đã biết
50
int x = 0;
int *y = &x; // b = &x, e = &x + 4, s = 4
int *z = y + 1; // b = &x, e = &x + 4, s = 4
*y = 10; //OK: &x ≤ p = &x ≤ (&x + 4) - 4
*z = 10; //Fail: &x ≤ p = &x + 4 ≤ (&x + 4) - 4
char str[10]; //b = &str, e = &str + 10
str[5] = 'A'; //OK: &str ≤ p = &str + 5 ≤ (&str + 10) - 1
str[10] = 'F'; //Fail: &str ≤ p = &str + 10 ≤ (&str + 10) - 1/
/
49
50
26
An toàn truy cập bộ nhớ
• An toàn thời gian(): thao tác chỉ truy cập vào vùng nhớ 
mà đã được khởi tạo:
Đã cấp phát bộ nhớ
Đã được khởi tạo giá trị
• Ví dụ: Vi phạm an toàn về thời gian
51
int n;
printf("%d", n); // Fail
int *p;
*p = 0; // Fail
p = (int *) malloc(sizeof(int));
*P = 0; // OK
free(p);
*p = 10; // Fail
Điều kiện truy cập bộ nhớ
• Tiền điều kiện(precondition): điều kiện để câu lệnh/hàm 
được thực thi đúng đắn
• Hậu điều kiện(postcondition): khẳng định trạng thái đúng 
đắn của các đối tượng khi lệnh/hàm kết thúc
• Ví dụ: Xác định các điều kiện truy cập bộ nhớ
52
void displayArr(int a[], size_t n)
{
for(size_t i = 0; i < n, i++)
printf(“%d”, a[i]);
}
51
52
27
Các nguyên tắc lập trình an toàn
• Không tin cậy những thứ mà không do bạn tạo ra
• Người dùng chỉ là những kẻ ngốc nghếch
Hàm gọi (Caller) = Người dùng
• Hạn chế cho kẻ khác tiếp cận những gì quan trọng. Ví dụ: 
thành phần bên trong của một cấu trúc/đối tượng
Ngôn ngữ OOP: nguyên lý đóng gói
Ngôn ngữ non-OOP: sử dụng token
• Không bao giờ nói “không bao giờ”
• Sau đây sẽ đề cập đến một số quy tắc trong C/C++
• Về chủ đề lập trình an toàn, tham khảo tại đây:
https://security.berkeley.edu/secure-coding-practice-
guidelines
53
Kiểm tra mọi dữ liệu đầu vào
• Các giá trị do người dùng nhập
• File được mở
• Các gói tin nhận được từ mạng
• Các dữ liệu thu nhận từ thiết bị cảm biến (Ví dụ: 
QR code, âm thanh, hình ảnh,)
• Thư viện của bên thứ 3
• Mã nguồn được cập nhật
• Khác
54
53
54
28
Sử dụng các hàm xử lý xâu an toàn
• Sử dụng các hàm xử lý xâu an toàn thay cho các 
hàm thông dụng
strcat, strncat strlcat
strcpy, strncpy strlcpy
gets fgets, fprintf
• Luôn đảm bảo xâu được kết thúc bằng ‘\0’
• Nếu có thể, hãy sử dụng các thư viện an toàn 
hơn
Ví dụ: std::string trong C++
55
Sử dụng con trỏ một cách an toàn
• Hiểu biết về các toán tử con trỏ: +, -, sizeof
• Cần xóa con trỏ về NULL sau khi giải phóng bộ nhớ
56
int x = 5;
int *p = (int *)malloc(sizeof(int));
free(p);
p = NULL;
int **q = (int **)malloc(sizeof(int*));
*q = &x;
*p = 5; //Crash OK
**q = 3;
55
56
29
Cẩn trọng khi sử dụng lệnh goto
57
• Ví dụ:
Sử dụng các thư viện an toàn hơn
• Nên sử dụng chuẩn C/C++11 thay cho các chuẩn cũ
• Sử dụng std::string trong C++ để xử lý xâu
• Truyền dữ liệu: sử dụng Goolge Protocol Buffers hoặc 
Apache Thrift
58
57
58

File đính kèm:

  • pdfan_ninh_mang_may_tinh_bai_10_an_toan_vung_nho_tien_trinh.pdf