Tại sao rất khó để làm cho C ít bị tràn bộ đệm?


23

Tôi đang tham gia một khóa học ở trường đại học, nơi một trong những phòng thí nghiệm là thực hiện khai thác tràn bộ đệm trên mã mà họ cung cấp cho chúng tôi. Điều này bao gồm các khai thác đơn giản như thay đổi địa chỉ trả về cho một hàm trên ngăn xếp để trở về một chức năng khác, tất cả các cách để mã thay đổi trạng thái đăng ký / bộ nhớ chương trình nhưng sau đó quay lại hàm mà bạn đã gọi, nghĩa là chức năng bạn gọi là hoàn toàn không biết gì về khai thác.

Tôi đã thực hiện một số nghiên cứu về vấn đề này và các loại khai thác này được sử dụng khá nhiều ở mọi nơi ngay cả bây giờ, trong những việc như chạy homebrew trên Wiijailbreak không giới hạn cho iOS 4.3.1

Câu hỏi của tôi là tại sao vấn đề này rất khó khắc phục? Rõ ràng đây là một khai thác chính được sử dụng để hack hàng trăm thứ, nhưng có vẻ như nó sẽ khá dễ dàng để khắc phục bằng cách cắt ngắn mọi đầu vào vượt quá độ dài cho phép và chỉ cần vệ sinh tất cả đầu vào mà bạn lấy.

EDIT: Một viễn cảnh khác mà tôi muốn có câu trả lời để xem xét - tại sao những người tạo ra C không khắc phục những vấn đề này bằng cách thực hiện lại các thư viện?

Câu trả lời:


35

Họ đã sửa các thư viện.

Bất kỳ thư viện chuẩn C hiện đại chứa biến thể an toàn hơn strcpy, strcat, sprintf, và vân vân.

Trên các hệ thống C99 - hầu hết các Unix - bạn sẽ tìm thấy những cái này có tên như strncatsnprintf, "n" chỉ ra rằng nó cần một đối số có kích thước của bộ đệm hoặc số lượng phần tử tối đa để sao chép.

Các chức năng này có thể được sử dụng để xử lý nhiều hoạt động an toàn hơn, nhưng nhìn lại khả năng sử dụng của chúng là không lớn. Ví dụ, một số snprintftriển khai không đảm bảo bộ đệm bị hủy kết thúc. strncatmất một số yếu tố để sao chép, nhưng nhiều người nhầm lẫn vượt qua kích thước của bộ đệm mệnh.

Trên Windows, người ta thường tìm thấy strcat_s, sprintf_sthì "_s" hậu tố cho biết "an toàn". Những thứ này cũng đã tìm được đường vào thư viện chuẩn C trong C11 và cung cấp thêm quyền kiểm soát đối với những gì xảy ra trong trường hợp tràn (ví dụ cắt ngắn so với khẳng định).

Nhiều nhà cung cấp thậm chí còn cung cấp nhiều lựa chọn thay thế không chuẩn hơn như asprintftrong libc GNU, sẽ tự động phân bổ một bộ đệm có kích thước phù hợp.

Ý tưởng rằng bạn có thể "chỉ sửa C" là một sự hiểu lầm. Sửa C không phải là vấn đề - và đã được thực hiện. Vấn đề là sửa hàng thập kỷ mã C được viết bởi các lập trình viên dốt nát, mệt mỏi hoặc vội vã hoặc mã được chuyển từ các bối cảnh mà an ninh không quan trọng đối với bối cảnh bảo mật. Không có thay đổi nào đối với thư viện chuẩn có thể sửa mã này, mặc dù việc di chuyển sang trình biên dịch mới hơn và thư viện chuẩn thường có thể giúp xác định các vấn đề tự động.


11
+1 để nhắm đến vấn đề trên các lập trình viên, không phải ngôn ngữ.
Nicol Bolas

8
@Nicol: Nói rằng "vấn đề [là] các lập trình viên" là không công bằng. Vấn đề là trong nhiều năm (nhiều thập kỷ) C đã dễ dàng viết mã không an toàn hơn mã an toàn, đặc biệt là định nghĩa "an toàn" của chúng tôi phát triển nhanh hơn bất kỳ tiêu chuẩn ngôn ngữ nào và mã đó vẫn còn tồn tại. Nếu bạn muốn cố gắng giảm nó thành một danh từ riêng, vấn đề là "1970-1999 libc", không phải "lập trình viên".

1
Các lập trình viên vẫn có trách nhiệm sử dụng các công cụ hiện có để khắc phục các sự cố này. Mất nửa ngày hoặc lâu hơn và thực hiện một số thông qua mã nguồn cho những điều này.
Nicol Bolas

1
@Nicol: Mặc dù tầm thường để phát hiện lỗi tràn bộ đệm tiềm năng, nhưng nó thường không tầm thường để chắc chắn đó là một mối đe dọa thực sự và ít tầm thường hơn để tìm ra điều gì sẽ xảy ra nếu bộ đệm bị tràn. Việc xử lý lỗi thường / không được xem xét, không thể "nhanh chóng" thực hiện cải tiến vì bạn có thể thay đổi hành vi của mô-đun theo những cách không mong muốn. Chúng tôi vừa thực hiện điều này trong một cơ sở mã kế thừa hàng triệu dòng, và mặc dù một giá trị trong khi thực hiện nó tốn rất nhiều thời gian (và Tiền).
mattnz

4
@NicolBolas: Không chắc bạn làm việc ở cửa hàng nào , nhưng nơi cuối cùng tôi viết C để sử dụng sản xuất yêu cầu sửa đổi tài liệu thiết kế chi tiết, xem xét nó, thay đổi mã, sửa đổi kế hoạch kiểm tra, xem xét kế hoạch kiểm tra, thực hiện hoàn thành kiểm tra hệ thống, xem xét kết quả kiểm tra, sau đó xác nhận lại hệ thống tại trang web của khách hàng. Đây là một hệ thống viễn thông trên một lục địa khác được viết cho một công ty không còn tồn tại nữa. Cuối cùng tôi biết, nguồn gốc là một trong RCS lưu trữ trên băng QIC rằng nên vẫn có thể đọc được, nếu bạn có thể tìm thấy một ổ đĩa băng phù hợp.
TMN

19

Thật sự không chính xác khi nói rằng C thực sự "dễ bị lỗi" theo thiết kế . Ngoài một số sai lầm nghiêm trọng như gets, ngôn ngữ C thực sự không thể là bất kỳ cách nào khác mà không làm mất tính năng chính thu hút mọi người đến C ngay từ đầu.

C được thiết kế như một ngôn ngữ hệ thống để hoạt động như một loại "lắp ráp di động". Một tính năng chính của ngôn ngữ C là không giống như các ngôn ngữ cấp cao hơn, mã C thường ánh xạ rất sát với mã máy thực tế. Nói cách khác, ++ithường chỉ là một inchướng dẫn và bạn thường có thể có được một ý tưởng chung về những gì bộ xử lý sẽ làm trong thời gian chạy bằng cách xem mã C.

Nhưng việc thêm vào kiểm tra giới hạn ngầm sẽ bổ sung thêm rất nhiều chi phí - chi phí mà lập trình viên không yêu cầu và có thể không muốn. Chi phí này vượt xa dung lượng lưu trữ bổ sung cần thiết để lưu trữ độ dài của mỗi mảng hoặc các hướng dẫn bổ sung để kiểm tra giới hạn mảng trên mỗi truy cập mảng. Số học con trỏ thì sao? Hoặc nếu bạn có một hàm lấy con trỏ thì sao? Môi trường thời gian chạy không có cách nào để biết liệu con trỏ đó có nằm trong giới hạn của khối bộ nhớ được phân bổ hợp pháp hay không. Để theo dõi điều này, bạn cần một số kiến ​​trúc thời gian chạy nghiêm túc có thể kiểm tra từng con trỏ dựa vào bảng các khối bộ nhớ hiện được phân bổ, tại thời điểm đó chúng ta đã đi vào lãnh thổ thời gian chạy được quản lý theo kiểu Java / C #.


12
Thành thật khi mọi người hỏi tại sao C không "an toàn", điều đó khiến tôi tự hỏi liệu họ có phàn nàn rằng lắp ráp không "an toàn" hay không.
Ben Brocka

5
Ngôn ngữ C rất giống với lắp ráp di động trên máy PDP-11 của Thiết bị kỹ thuật số. Đồng thời các máy Burroughs có mảng giới hạn kiểm tra trong CPU, vì vậy họ đã thực sự dễ dàng để có được chương trình ngay trong kiểm tra mảng trong cuộc sống của phần cứng trên trong phần cứng Rockwell Collins. (Chủ yếu được sử dụng trong ngành hàng không.)
Tim Williscroft

15

Tôi nghĩ rằng vấn đề thực sự không phải là các loại lỗi rất khó để sửa chữa, nhưng điều đó họ rất dễ dàng để thực hiện: Nếu bạn sử dụng strcpy, sprintfvà bạn bè trong (dường như) Cách đơn giản nhất là công việc có thể, sau đó bạn đã có thể mở cửa cho một tràn bộ đệm. Và không ai sẽ nhận thấy nó cho đến khi ai đó khai thác nó (trừ khi bạn có đánh giá mã rất tốt). Bây giờ hãy thêm một thực tế là có rất nhiều lập trình viên tầm thường và họ luôn chịu áp lực về thời gian - và bạn có một công thức mã bị xáo trộn với bộ đệm tràn đến mức khó có thể khắc phục tất cả chỉ vì có rất nhiều người trong số họ và họ đang trốn rất tốt.


3
Bạn không thực sự cần "đánh giá mã rất tốt". Bạn chỉ cần cấm sprintf hoặc xác định lại sprintf với thứ gì đó sử dụng sizeof () và lỗi về kích thước của một con trỏ, v.v. Thậm chí bạn không cần đánh giá mã, bạn có thể thực hiện loại công cụ này với cam kết SCM móc và grep.

1
@JoeWreschnig: sizeof(ptr)nói chung là 4 hoặc 8. Đó là một giới hạn C khác: không có cách nào để xác định độ dài của một mảng, chỉ đưa ra con trỏ tới nó.
MSalters

@MSalters: Có, một mảng int [1] hoặc char [4] hoặc bất cứ điều gì có thể là dương tính giả, nhưng trong thực tế, bạn không bao giờ xử lý các bộ đệm có kích thước đó với các chức năng đó. (Tôi không nói về mặt lý thuyết ở đây - Tôi đã làm việc trên một cơ sở mã C lớn trong bốn năm sử dụng phương pháp này. Tôi chưa bao giờ đạt đến giới hạn của việc chạy nước rút vào một char [4].)

5
@BlackJack: Hầu hết các lập trình viên không ngu ngốc - nếu bạn buộc họ vượt qua kích thước, họ sẽ vượt qua đúng. Nó hầu như cũng không vượt qua kích thước trừ khi bị ép buộc. Bạn có thể viết một macro sẽ trả về độ dài của một mảng nếu nó có kích thước tĩnh hoặc tự động, nhưng lỗi nếu được cung cấp một con trỏ. Sau đó, bạn # xác định sprintf để gọi snprintf với macro đó cho kích thước. Bây giờ bạn có một phiên bản sprintf chỉ hoạt động trên các mảng với các kích thước đã biết và buộc lập trình viên gọi snprintf với kích thước được chỉ định thủ công theo cách khác.

1
Một ví dụ đơn giản về macro như vậy #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / (sizeof(a) != sizeof(void *))sẽ kích hoạt phân chia thời gian biên dịch bằng 0. Một thông minh khác mà tôi thấy lần đầu tiên trong Chromium là #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / !(sizeof(a) % sizeof((a)[0]))giao dịch một số tích cực sai cho một số phủ định sai - thật không may, nó vô dụng đối với char []. Bạn có thể sử dụng các phần mở rộng trình biên dịch khác nhau để làm cho nó thậm chí còn đáng tin cậy hơn, ví dụ: blog.msdn.com/b/ce_base/archive/2007/05/08/ .

7

Thật khó để sửa lỗi tràn bộ đệm vì C hầu như không cung cấp công cụ hữu ích nào để giải quyết vấn đề. Đó là một lỗ hổng ngôn ngữ cơ bản mà các bộ đệm bản địa cung cấp không có bảo vệ nó hầu như, nếu không hoàn toàn, không thể thay thế chúng bằng một sản phẩm cao cấp, giống như C ++ đã làm với std::vectorstd::array, thật khó ngay cả dưới chế độ gỡ lỗi để tìm đệm tràn.


13
"Lỗ hổng ngôn ngữ" là một tuyên bố thiên vị khủng khiếp. Rằng các thư viện không cung cấp giới hạn - kiểm tra là một lỗ hổng; rằng ngôn ngữ không phải là một lựa chọn có ý thức để tránh chi phí. Sự lựa chọn đó là một phần của những gì cho phép các công trình cấp cao hơn muốn std::vectorđược triển khai hiệu quả. Và vector::operator[]đưa ra lựa chọn tương tự cho tốc độ trên an toàn. Sự an toàn vectorđến từ việc làm cho nó dễ dàng hơn để xoay quanh kích thước, đó là cách tiếp cận tương tự các thư viện C hiện đại.

1
@Charles: "C chỉ không cung cấp bất kỳ loại bộ đệm mở rộng động nào như một phần của thư viện chuẩn." Không, điều này không có gì để làm với nó. Đầu tiên, C cung cấp chúng thông qua realloc(C99 cũng cho phép bạn định cỡ các mảng ngăn xếp bằng cách sử dụng kích thước không đổi được xác định trong thời gian chạy thông qua bất kỳ biến tự động nào, hầu như luôn luôn thích hợp hơn char buf[1024]). Thứ hai, vấn đề không liên quan gì đến việc mở rộng bộ đệm, nó liên quan đến việc bộ đệm có mang kích thước với chúng hay không và kiểm tra kích thước đó khi bạn truy cập chúng.

5
@Joe: Vấn đề không phải là nhiều mảng bản địa bị hỏng. Đó là điều họ không thể thay thế. Để bắt đầu, vector::operator[]không kiểm tra giới hạn trong chế độ gỡ lỗi - một số mảng gốc không thể làm được - và thứ hai, không có cách nào trong C để hoán đổi loại mảng gốc với một loại có thể kiểm tra giới hạn, bởi vì không có mẫu và không có toán tử quá tải. Trong C ++, nếu bạn muốn chuyển từ T[]sang std::array, thực tế bạn có thể trao đổi một typedef. Trong C, không có cách nào để đạt được điều đó và không có cách nào để viết một lớp có chức năng tương đương, chứ đừng nói đến giao diện.
DeadMG

3
@Joe: Ngoại trừ nó không bao giờ có thể có kích thước tĩnh, và bạn không bao giờ có thể làm cho nó chung chung. Không thể viết bất kỳ thư viện nào trong C hoàn thành vai trò tương tự std::vector<T>std::array<T, N>thực hiện trong C ++. Sẽ không có cách nào để thiết kế và chỉ định bất kỳ thư viện nào, thậm chí không phải là Thư viện tiêu chuẩn, có thể làm điều này.
DeadMG

1
Tôi không chắc ý của bạn là "nó không bao giờ có thể có kích thước tĩnh". Vì tôi sử dụng thuật ngữ đó, std::vectorcũng không bao giờ có thể có kích thước tĩnh. Đối với chung chung, bạn có thể làm cho nó chung chung như C tốt cần có - một số lượng nhỏ các thao tác cơ bản trên void * (thêm, xóa, thay đổi kích thước) và mọi thứ khác được viết cụ thể. Nếu bạn sẽ phàn nàn rằng C không có thuốc generic kiểu C ++, thì đó là ngoài phạm vi xử lý bộ đệm an toàn.

7

Vấn đề không phải là với C ngôn ngữ .

IMO, trở ngại lớn duy nhất cần vượt qua là C chỉ đơn giản là dạy xấu . Hàng thập kỷ thực hành xấu và thông tin sai đã được thể chế hóa trong các tài liệu tham khảo và ghi chú bài giảng, đầu độc tâm trí của mỗi thế hệ lập trình viên mới ngay từ đầu. Học sinh được cung cấp một mô tả ngắn gọn về các chức năng I / O "dễ dàng" như gets1 hoặc scanfsau đó để lại cho các thiết bị của riêng họ. Họ không cho biết những công cụ đó có thể thất bại ở đâu hoặc làm thế nào để ngăn chặn những thất bại đó. Họ không nói về việc sử dụng fgetsstrtol/strtodbởi vì những công cụ được coi là "tiên tiến". Sau đó, họ tung ra thế giới chuyên nghiệp để tàn phá thế giới của họ. Không phải là nhiều lập trình viên có kinh nghiệm hơn biết nhiều hơn, bởi vì họ nhận được cùng một nền giáo dục bị tổn thương não. Thật điên rồ. Tôi thấy rất nhiều câu hỏi ở đây và trên Stack Overflow và trên các trang web khác, nơi rõ ràng rằng người hỏi câu hỏi đang được dạy bởi một người chỉ đơn giản là không biết họ đang nói về điều gì , và tất nhiên bạn không thể nói "Giáo sư của bạn sai," bởi vì anh ta là Giáo sư và bạn chỉ là một người trên Internet.

Và sau đó, bạn có đám đông coi thường bất kỳ câu trả lời nào bắt đầu bằng "tốt, theo tiêu chuẩn ngôn ngữ ..." bởi vì họ đang làm việc trong thế giới thực và theo họ, tiêu chuẩn này không áp dụng cho thế giới thực . Tôi có thể đối phó với một người chỉ có một nền giáo dục tồi tệ, nhưng bất cứ ai khăng khăng không biết gì cũng chỉ là một sự tàn phá trong ngành.

Sẽ không có vấn đề tràn bộ đệm nếu ngôn ngữ được dạy chính xác với sự nhấn mạnh vào việc viết mã bảo mật. Nó không "cứng", nó không "tiên tiến", nó chỉ cẩn thận.

Vâng, đây đã là một cơn thịnh nộ.


1 Điều may mắn là cuối cùng đã được rút ra khỏi đặc tả ngôn ngữ, mặc dù nó sẽ ẩn trong mã di sản trị giá 40 năm mãi mãi.


1
Mặc dù tôi hầu hết đồng ý với bạn, tôi nghĩ bạn vẫn hơi bất công. Những gì chúng tôi coi là "an toàn" cũng là một chức năng của thời gian (và tôi thấy bạn đã là một nhà phát triển phần mềm chuyên nghiệp lâu hơn tôi rất nhiều, vì vậy tôi chắc chắn bạn đã quen với điều này). Mười năm nữa, ai đó sẽ có cuộc trò chuyện tương tự về lý do tại sao mọi người trong năm 2012 sử dụng các triển khai bảng băm có thể DoS, chúng ta không biết gì về bảo mật? Nếu có một vấn đề trong giảng dạy, thì đó là một vấn đề mà chúng ta tập trung quá nhiều vào việc dạy thực hành "tốt nhất", và bản thân nó không phát triển tốt nhất.

1
Và hãy trung thực. Bạn chỉ có thể viết mã an toàn sprintf, nhưng điều đó không có nghĩa là ngôn ngữ không hoàn hảo. C đã được thiếu sót và đang bị biến dị - như ngôn ngữ nào - và điều quan trọng là chúng ta thừa nhận những sai sót vì vậy chúng tôi có thể tiếp tục để giải quyết chúng.

@JoeWreschnig - Mặc dù tôi đồng ý với quan điểm lớn hơn, tôi nghĩ rằng có một sự khác biệt về chất giữa việc triển khai bảng băm DoS có thể và tràn bộ đệm. Cái trước có thể được quy cho các tình huống phát triển xung quanh bạn, nhưng cái thứ hai không có lý do; tràn bộ đệm là lỗi mã hóa, thời gian. Có, C không có người bảo vệ lưỡi và sẽ cắt bạn nếu bạn bất cẩn; chúng ta có thể tranh luận về việc đó có phải là một lỗ hổng trong ngôn ngữ hay không. Đó là của trực giao với thực tế là rất ít học sinh được cho bất kỳ hướng dẫn an toàn khi họ đang học ngôn ngữ.
John Bode

5

Vấn đề là một trong những sự thiển cận của người quản lý hơn là sự bất tài của lập trình viên. Hãy nhớ rằng, một ứng dụng 90.000 dòng chỉ cần một thao tác không an toàn là hoàn toàn không an toàn. Gần như không có khả năng rằng bất kỳ ứng dụng nào được viết trên đầu xử lý chuỗi không an toàn về cơ bản sẽ hoàn hảo 100% - điều đó có nghĩa là nó sẽ không an toàn.

Vấn đề là chi phí không an toàn sẽ không được tính cho người nhận đúng (công ty bán ứng dụng sẽ gần như không bao giờ phải hoàn trả giá mua) hoặc không thể thấy rõ tại thời điểm quyết định được đưa ra ("Chúng tôi phải giao hàng vào tháng 3 không có vấn đề gì! "). Tôi khá chắc chắn rằng nếu bạn chú ý đến chi phí và chi phí dài hạn cho người dùng thay vì lợi nhuận của công ty bạn, thì việc viết bằng C hoặc các ngôn ngữ liên quan sẽ tốn kém hơn nhiều, có thể đắt đến mức rõ ràng là lựa chọn sai ở nhiều người lĩnh vực mà ngày nay trí tuệ thông thường nói rằng đó là một điều cần thiết. Nhưng điều đó sẽ không thay đổi trừ khi trách nhiệm phần mềm chặt chẽ hơn được đưa ra - điều mà không ai trong ngành muốn.


-1: Đổ lỗi cho quản lý là gốc rễ của mọi tội lỗi không đặc biệt mang tính xây dựng. Bỏ qua lịch sử ít hơn một chút như vậy. Câu trả lời gần như được chuộc lại bằng câu cuối cùng.
mattnz

Trách nhiệm phần mềm chặt chẽ hơn có thể được giới thiệu bởi người dùng quan tâm đến bảo mật và sẵn sàng trả tiền cho nó. Có thể cho rằng, nó có thể được đưa ra bằng cách có các hình phạt nghiêm khắc cho các vi phạm an ninh. Một giải pháp dựa trên thị trường sẽ hoạt động nếu người dùng sẵn sàng trả tiền cho bảo mật, nhưng họ không làm thế.
David Thornley

4

Một trong những sức mạnh tuyệt vời của việc sử dụng C là nó cho phép bạn thao tác bộ nhớ theo bất kỳ cách nào bạn thấy phù hợp.

Một trong những điểm yếu lớn của việc sử dụng C là nó cho phép bạn thao tác bộ nhớ theo bất kỳ cách nào bạn thấy phù hợp.

Có phiên bản an toàn của bất kỳ chức năng không an toàn. Tuy nhiên, các lập trình viên và trình biên dịch không thực thi nghiêm ngặt việc sử dụng của họ.


2

Tại sao những người tạo ra C không khắc phục những vấn đề này bằng cách thực hiện lại các thư viện?

Có lẽ vì C ++ đã làm điều này và tương thích ngược với mã C. Vì vậy, nếu bạn muốn một loại chuỗi an toàn trong mã C của mình, bạn chỉ cần sử dụng std :: string và viết mã C của mình bằng trình biên dịch C ++.

Hệ thống con bộ nhớ cơ bản có thể giúp ngăn chặn lỗi tràn bộ đệm bằng cách giới thiệu các khối bảo vệ và kiểm tra tính hợp lệ của chúng - vì vậy tất cả các phân bổ đều có 4 byte 'fefefefe' được thêm vào, khi các khối này được ghi vào, hệ thống có thể ném một wobbler. Nó không được đảm bảo để ngăn chặn việc ghi bộ nhớ, nhưng nó sẽ cho thấy rằng đã xảy ra lỗi và cần phải sửa.

Tôi nghĩ vấn đề là các thói quen strcpy cũ vẫn còn tồn tại. Nếu chúng được loại bỏ có lợi cho strncpy, vv thì điều đó sẽ giúp ích.


1
Loại bỏ strcpy, vv hoàn toàn sẽ làm cho các đường dẫn nâng cấp gia tăng thậm chí còn khó khăn hơn, điều này sẽ dẫn đến việc mọi người không nâng cấp gì cả. Cách thực hiện bây giờ bạn có thể chuyển sang trình biên dịch C11, sau đó bắt đầu sử dụng các biến thể _s, sau đó cấm các biến thể không phải _s, sau đó sửa chữa việc sử dụng hiện tại, trong bất kỳ khoảng thời gian nào thực tế khả thi.

-2

Thật đơn giản để hiểu tại sao vấn đề tràn không được khắc phục. C đã bị thiếu sót trong một vài lĩnh vực. Tại thời điểm những sai sót được coi là có thể chấp nhận được hoặc thậm chí là một tính năng. Bây giờ nhiều thập kỷ sau những sai sót đó là không thể sửa chữa.

Một số phần của cộng đồng lập trình không muốn những lỗ đó được cắm. Chỉ cần nhìn vào tất cả các cuộc chiến ngọn lửa bắt đầu qua chuỗi, mảng, con trỏ, bộ sưu tập rác ...


5
LOL, câu trả lời khủng khiếp và sai lầm.
Heath Hunnicutt

1
Để giải thích lý do tại sao đây là một câu trả lời tồi: C thực sự có nhiều sai sót, nhưng cho phép tràn bộ đệm, v.v ... có rất ít liên quan đến chúng, nhưng với các yêu cầu ngôn ngữ cơ bản. Không thể thiết kế một ngôn ngữ để thực hiện công việc của C và không cho phép tràn bộ đệm. Các bộ phận của cộng đồng không muốn từ bỏ các khả năng mà C cho phép họ, thường là có lý do chính đáng. Cũng có những bất đồng về cách tránh một số vấn đề này, cho thấy rằng chúng ta không có sự hiểu biết đầy đủ về thiết kế ngôn ngữ lập trình, không có gì hơn thế.
David Thornley

1
@DavidThornley: Người ta có thể thiết kế một ngôn ngữ để thực hiện công việc của C nhưng làm cho nó để các cách làm thành ngữ bình thường ít nhất sẽ cho phép trình biên dịch kiểm tra bộ đệm tràn một cách hợp lý một cách hiệu quả, nếu trình biên dịch chọn làm như vậy. Có một sự khác biệt lớn giữa việc có memcpy()sẵn và chỉ có nó là phương tiện tiêu chuẩn để sao chép hiệu quả một phân khúc mảng.
supercat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.