2010-06-04 40 views
9

Tôi đang lập trình bằng C trong Unix, và tôi đang sử dụng gets để đọc các yếu tố đầu vào từ bàn phím. Tôi luôn nhận được cảnh báo này và chương trình ngừng chạy:lý do tại sao() không hoạt động?

warning: this program uses gets(), which is unsafe. 

Ai có thể cho tôi biết lý do tại sao điều này xảy ra?

+0

Đó là một chức năng không an toàn; các cuộc tấn công tràn bộ đệm có thể được phát hành nếu các chương trình sử dụng các chức năng không cung cấp khả năng kiểm tra kích thước bộ đệm – INS

+0

Nếu tôi sử dụng scanf() thay vì được() nó hoạt động, nhưng tôi phải đọc 2 đầu vào từ bàn phím và chương trình dừng lại sau khi tôi đọc cuốn thứ nhất. Tại sao? đây là mã: người dùng char; thẻ vượt qua; printf ("ID người dùng"); scanf ("% s", người dùng); printf ("Mã Pin:"); scanf ("% s", vượt qua); – Peiska

+1

@peiska: Chương trình dừng sau chương trình đầu tiên bởi vì nó đang chờ bạn nhập số thứ hai. Bản thân bạn đặt 'scanf' thứ hai vào đó. Tại sao nó làm bạn ngạc nhiên rằng chương trình "dừng" sau đó? – AnT

Trả lời

8

Như đã đề cập trong các câu trả lời trước, hãy sử dụng fgets thay vì gets.

Nhưng nó không giống như gets không hoạt động chút nào, nó chỉ rất rất không an toàn. Tôi đoán là bạn có một lỗi trong mã của bạn mà sẽ xuất hiện với fgets cũng như vậy xin vui lòng gửi nguồn của bạn.

EDIT Dựa trên thông tin cập nhật bạn đưa ra trong nhận xét của mình Tôi có một vài gợi ý.

  • Tôi khuyên bạn nên tìm kiếm hướng dẫn C tốt bằng ngôn ngữ mẹ đẻ của bạn, Google là bạn của bạn ở đây. Là một cuốn sách tôi muốn giới thiệu The C Programming Language

  • Nếu bạn có thông tin mới, bạn nên chỉnh sửa chúng vào bài đăng gốc, đặc biệt nếu là mã, nó sẽ giúp mọi người dễ hiểu ý của bạn hơn.

  • Bạn đang cố gắng đọc một chuỗi, về cơ bản là một mảng các ký tự, thành một ký tự đơn, tất nhiên sẽ không thành công. Những gì bạn muốn làm là một cái gì đó như sau.

    char username[256]; 
    char password[256]; 
    scanf("%s%s", username, password); 
    

    Hãy bình luận/chỉnh sửa, tôi rất gỉ ngay cả trong cơ bản C.

EDIT 2 Như jamesdlin cảnh báo, sử dụng scanf là nguy hiểm như gets.

+0

Cách sử dụng 'scanf' của bạn cũng tệ như' get'. (Tránh sử dụng 'scanf' quá: http://c-faq.com/stdio/scanfprobs.html) – jamesdlin

+0

@jamesdlin Cảm ơn những người đứng đầu, tôi không biết về vấn đề tràn bộ đệm, mặc dù tôi đã chạy vào các vấn đề khác với scanf trước đây. – ponzao

13

gets không an toàn vì bạn cung cấp cho bộ đệm, nhưng bạn không cho biết bộ đệm lớn như thế nào. Các đầu vào có thể viết qua phần cuối của bộ đệm, thổi lên chương trình của bạn khá ngoạn mục. Sử dụng fgets thay vào đó là một chút tốt hơn bởi vì bạn nói nó lớn như thế nào bộ đệm là, như thế này:

const int bufsize = 4096; /* Or a #define or whatever */ 
char buffer[bufsize]; 

fgets(buffer, bufsize, stdin); 

... do đó, miễn là bạn cung cấp cho nó thông tin chính xác, nó không viết quá khứ cuối của bộ đệm và thổi mọi thứ lên.

Hơi OT, nhưng:

Bạn không cần phải sử dụng một const int cho kích thước bộ đệm, nhưng tôi sẽ mạnh khuyên bạn không chỉ cần đặt một số chữ ở cả hai nơi, bởi vì chắc chắn bạn sẽ thay đổi một nhưng không thay đổi sau này. Trình biên dịch có thể giúp:

char buffer[4096]; 
fgets(buffer, (sizeof buffer/sizeof buffer[0]), stdin); 

Biểu thức đó được giải quyết tại thời gian biên dịch, không phải thời gian chạy. Đó là một nỗi đau để gõ, vì vậy tôi sử dụng để sử dụng một vĩ mô trong bộ tiêu đề thông thường của tôi:

#define ARRAYCOUNT(a) (sizeof a/sizeof a[0]) 

... nhưng tôi là một vài năm cũ với C tinh khiết của tôi, có lẽ có một cách tốt hơn những ngày này.

+0

nếu bạn đang xử lý một mảng 'char', không cần phải chia cho' sizeof buffer [0] 'như' sizeof (char) == 1' theo định nghĩa, tức là lời gọi hàm có thể được đơn giản hóa thành 'fgets (buffer, sizeof buffer, stdin) ' – Christoph

+0

@Christoph: Bạn chắc chắn * rằng' char' sẽ là một byte trên tất cả các nền tảng, và/hoặc nếu nó (nói) hai byte, tham số kích thước buf cho 'fgets 'sẽ được áp dụng như * ký tự * thay vì * byte *? Hầu hết các tài liệu tôi đã nhìn thấy đã nói byte. Tôi đã ra khỏi trò chơi C một lúc và tôi biết rằng công cụ này đã trở nên phức tạp hơn, vì vậy tôi đã được một chút phòng thủ trong mã. Nhưng có, @OP, * nếu * những giả định đó là an toàn, thì bạn có thể bỏ qua phép tính với mảng 'char' (nhưng không phải các ứng dụng tương tự của thành ngữ này với' int', 'long', v.v.). –

+0

@ T.J. Crowder: C standard * định nghĩa * 'char' thành 1 byte. – jamesdlin

5

man gets nói:

bao giờ sử dụng được(). Bởi vì nó là không thể biết mà không biết dữ liệu trước số lượng ký tự được() sẽ đọc và vì được() sẽ tiếp tục lưu trữ ký tự ở cuối bộ đệm, . Nó đã được sử dụng để phá vỡ bảo mật máy tính . Sử dụng fgets() để thay thế.

1

được() không an toàn. Phải mất một tham số, một con trỏ đến một bộ đệm char. Hãy tự hỏi bản thân mình lớn đến mức nào để tạo bộ đệm đó và người dùng có thể gõ đầu vào bao lâu mà không nhấn phím trả về.

Về cơ bản, không có cách nào để ngăn chặn tràn bộ đệm bằng() - sử dụng fgets().

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