2009-05-26 35 views
5

Tôi có đoạn mã C sau đây và phải xác định lỗi và gợi ý một cách để viết nó một cách an toàn hơn:Làm thế nào đoạn C này có thể được viết một cách an toàn hơn?

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strcpy(copy, somestring); 
printf(copy); 

Vì vậy, lỗi là strlen mà bỏ qua các dấu '\0' của một chuỗi và do đó nó không phải là sẽ được phân bổ đủ bộ nhớ cho bản sao nhưng tôi không chắc chắn những gì họ đang nhận được về viết nó an toàn hơn?

Tôi chỉ có thể sử dụng malloc(strlen(somestring)+1)) Tôi giả sử nhưng tôi nghĩ rằng phải có một cách tốt hơn?


EDIT: OK, tôi đã chấp nhận một câu trả lời, tôi nghi ngờ rằng giải pháp strdup sẽ không được mong đợi từ chúng tôi vì nó không phải là một phần của ANSI C. Nó có vẻ là khá một câu hỏi chủ quan vì vậy tôi 'không chắc chắn nếu những gì tôi đã chấp nhận thực sự là tốt nhất. Cảm ơn anyway cho tất cả các câu trả lời.

Trả lời

4
char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

strncpy(copy, somestring, copysize); 
printf("%s", copy); 

khác biệt đã nêu ở trên:

  • Kết quả malloc() phải được kiểm tra!
  • Tính toán và lưu trữ kích thước bộ nhớ!
  • Sử dụng strncpy()strcpy() là nghịch ngợm. Trong ví dụ giả tạo này, nó sẽ không bị tổn thương, nhưng không đi vào thói quen sử dụng nó.

EDIT:

Đối với những suy nghĩ tôi nên sử dụng strdup() ... mà chỉ hoạt động nếu bạn có quan điểm rất hẹp nhất của câu hỏi. Đó không chỉ là ngớ ngẩn, nó còn nhìn ra một câu trả lời hay hơn nữa:

char somestring[] = "Send money!\n"; 
char *copy = somestring; 
printf(copy); 

Nếu bạn sắp bị nguyền rủa, ít nhất là tốt.

+3

+1 để sử dụng strncpy. Đó là nguồn của rất nhiều lỗ hổng bảo mật, nó không phải là buồn cười. –

+8

Sử dụng strncpy() tệ hơn là sử dụng strcpy() kém. Nếu bạn sử dụng strncpy(), bạn * NOT * được bảo đảm kết thúc đầu ra null (ví dụ này là OK, nhưng không nói chung). Ngoài ra, nếu bạn sử dụng bộ đệm quá khổ và sizeof (bộ đệm) cho tham số thứ ba tới strncpy(), bạn có một thảm họa hiệu suất nhỏ trên tay; strncpy() zealously zero-miếng đệm dữ liệu sao chép đến chiều dài đầy đủ. * CÓ * để biết độ dài của chuỗi nguồn và đích; nếu bạn làm điều đó một cách chính xác, sử dụng strcpy() là an toàn và an toàn hơn so với sử dụng mù của strncpy(). (Nếu nó là bất kỳ giúp đỡ, strncat() là xa, đến nay tồi tệ hơn so với strncpy(); không bao giờ sử dụng nó!) –

+1

Jonathan, strlcpy() là nhiều hơn nữa sane. Tôi sử dụng nó bất cứ khi nào nó có sẵn, và đôi khi tôi mang theo một phiên bản khi nó không. Drepper quá tệ là một dork. – dwc

6
char somestring[] = "Send money!\n"; 
char *copy = strdup(something); 

if (copy == NULL) { 
    // error 
} 

hoặc chỉ cần đặt logic này trong một chức năng riêng biệt xstrdup:

char * xstrdup(const char *src) 
{ 
    char *copy = strdup(src); 

    if (copy == NULL) { 
     abort(); 
    } 

    return copy; 
} 
+5

Cần lưu ý rằng strdup() là không phải là một phần của ANSI C. –

+1

nó phải là: if (copy == NULL) { – hiena

+2

Nếu strdup() không tồn tại cho thư viện C của bạn, thì bạn nên viết nó. Điều đó có nghĩa là bạn có một điểm mà một lỗi có thể xảy ra thay vì hàng trăm. –

-2

Cách an toàn hơn sẽ được sử dụng thay vì strncpystrcpy. Hàm đó nhận một đối số thứ ba: độ dài của chuỗi cần sao chép. Giải pháp này không vượt quá ANSI C, do đó, điều này sẽ làm việc trong tất cả các môi trường (trong khi các phương pháp khác chỉ có thể hoạt động trong các hệ thống tuân thủ POSIX).

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strncpy(copy, somestring, strlen(somestring)); 
printf(copy); 
+0

+1 cho strncpy; hơn bất kỳ thứ gì khác, điều đó làm cho mã này an toàn hơn. Ít nhất trong trường hợp thất bại malloc, bạn sẽ segfault; strcpy() cho phép các lỗ hổng bảo mật điên rồ được tìm thấy. –

+1

-1 cho lỗi một lần và tham nhũng bộ nhớ –

+0

@McWafflestix: không, trong trường hợp này, strncpy() bị lạm dụng và kết quả là một mớ hỗn độn. Như Aaron Digulla chỉ ra, cuộc gọi đến strncpy() cần độ dài 'strlen (somestring) +1'; vì nó được viết, bản sao được đảm bảo không bị vô hiệu. Printf() là nguy hiểm nói chung - bằng cách sử dụng một chuỗi ngẫu nhiên như là định dạng printf() là xấu (puts() có lẽ là lựa chọn gần nhất để lành mạnh ở đây). (Hãy tưởng tượng "Gửi thêm 20% tiền!" Thay vào đó!) –

3
  1. strlen + 1, cho \ 0 terminator
  2. malloc có thể thất bại; luôn luôn kiểm tra giá trị trả về malloc
0

Cách tốt nhất để viết nó an toàn hơn, nếu người ta thực sự quan tâm đến điều như vậy, sẽ viết nó trong Ada.

somestring : constant string := "Send money!"; 
declare 
    copy : constant string := somestring; 
begin 
    put_line (somestring); 
end; 

Kết quả tương tự, vậy sự khác biệt là gì?

  • Toàn bộ việc được thực hiện trên ngăn xếp (không có con trỏ). Deallocation là tự động và an toàn.
  • Mọi thứ đều được automaticly phạm vi kiểm tra để không có cơ hội tràn bộ đệm khai thác
  • Cả hai chuỗi là hằng số, vì vậy không có cơ hội điều chỉnh các và sửa đổi chúng.
  • Nó có thể là cách nhanh hơn so với C, không chỉ vì thiếu phân bổ động, nhưng vì không có quét thêm thông qua chuỗi được yêu cầu bởi strlen().

Lưu ý rằng trong chuỗi Ada "" không phải là một số cấu trúc động đặc biệt. Đó là mảng ký tự được tích hợp sẵn. Tuy nhiên, mảng Ada có thể được khai báo bằng mảng mà bạn gán cho chúng.

3

Ick ... sử dụng strdup() như mọi người khác đã nói và tự viết nếu bạn phải làm như vậy. Vì bạn có thời gian để suy nghĩ về điều này ngay bây giờ ... hãy xem 25 Most Dangerous Programming Errors at Mitre, sau đó xem xét lý do tại sao cụm từ printf(copy) nên không bao giờ xuất hiện trong mã. Đó là quyền lên đó với malloc(strlen(str)) về mặt xấu hoàn toàn chưa kể đến nỗi đau đầu theo dõi lý do tại sao nó gây ra rất nhiều đau buồn khi sao chép giống như "%s%n" ...

7

Tôi không thể nhận xét về câu trả lời ở trên, nhưng ngoài việc kiểm tra mã trở lại và sử dụng strncpy, bạn không bao giờ nên làm:

printf(string) 

Nhưng sử dụng:

printf("%s", string); 

ref: http://en.wikipedia.org/wiki/Format_string_attack

+2

+1 cho lỗ hổng bảo mật không mong muốn trong mã phổ biến nhất –

1

Tôi sẽ nhận xét về các giải pháp trước đây nhưng tôi không có đủ đại diện. Sử dụng strncpy đây là sai khi sử dụng strcpy (Vì hoàn toàn không có nguy cơ tràn). Có một chức năng được gọi là memcpy trong < string.h> và điều đó có nghĩa là chính xác cho việc này. Nó không phải là chỉ nhanh hơn đáng kể, mà còn là chức năng chính xác để sử dụng để sao chép các chuỗi có độ dài được biết đến trong tiêu chuẩn C.

Từ câu trả lời được chấp nhận:

char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

memcpy(copy, somestring, copysize); /* You don't use str* functions for this! */ 
printf("%s", copy); 
+0

-1 để sử dụng malloc() vào trong một bản sao chuỗi khi bạn có strdup(). Không phát minh lại bánh xe khi bạn có chức năng thư viện. –

+0

@Aaron Như đã đề cập trước đây, strdup() không phải là ANSI, nó sẽ không tồn tại trên tất cả các hệ thống. Điểm của câu trả lời này có thể được áp dụng khi bạn viết phiên bản strdup() của riêng bạn. – Trent

1

cách để làm cho đoạn code an toàn hơn (và chính xác hơn).

  1. Đừng tạo bản sao không cần thiết. Từ ví dụ này, không có yêu cầu rõ ràng rằng bạn thực sự cần phải sao chép somestring. Bạn có thể xuất trực tiếp.
  2. Nếu bạn phải tạo một bản sao của một chuỗi, hãy viết một hàm để thực hiện nó (hoặc sử dụng strdup nếu bạn có nó). Sau đó, bạn chỉ phải làm cho nó ở một nơi.
  3. Bất cứ khi nào có thể, hãy khởi chạy con trỏ đến bản sao ngay lập tức khi bạn khai báo.
  4. Hãy nhớ phân bổ không gian cho trình kết thúc null.
  5. Hãy nhớ kiểm tra giá trị trả lại từ malloc.
  6. Hãy nhớ giải phóng bộ nhớ đã chỉnh sửa malloc '.
  7. Không gọi printf bằng chuỗi định dạng không đáng tin cậy. Sử dụng printf("%s", copy) hoặc puts(copy).
  8. Sử dụng ngôn ngữ hướng đối tượng có lớp chuỗi hoặc bất kỳ ngôn ngữ nào có hỗ trợ chuỗi được tích hợp sẵn để tránh hầu hết các sự cố này.
1

thêm nhiều hơn để cách Adrian McCarthy để làm cho mã an toàn hơn,

Sử dụng một mã số phân tích tĩnh, họ rất giỏi trong việc tìm kiếm loại lỗi

Các vấn đề liên quan