ฟังก์ชันใดจากไลบรารีมาตรฐานที่ต้อง (ควร) หลีกเลี่ยง


90

ฉันได้อ่านใน Stack Overflow ว่าฟังก์ชัน C บางฟังก์ชัน "ล้าสมัย" หรือ "ควรหลีกเลี่ยง" คุณช่วยยกตัวอย่างฟังก์ชันประเภทนี้และเหตุผลให้ฉันได้ไหม

มีทางเลือกใดบ้างสำหรับฟังก์ชันเหล่านั้น

เราสามารถใช้ได้อย่างปลอดภัย - มีแนวทางปฏิบัติที่ดีหรือไม่?


3
ฉันเชื่อว่ามันเป็นสิ่งที่ดีมากที่ได้รู้ ฟังก์ชั่นบางอย่างจาก C จริงๆควรหลีกเลี่ยงและใช้เพียงเพื่อการศึกษา
INS

@Felix มันจะง่ายกว่าในการแก้ไขคำตอบเดียว (ทำเครื่องหมายว่าถูกต้อง) ในอนาคต มันขึ้นอยู่กับอากาศเกี่ยวกับคำตอบที่มีแนวโน้มเปลี่ยนแปลงไปตามกาลเวลา ใครจะรู้บางทีเจฟฟ์อาจจะมอบป้าย 'ภารโรง' ให้กับคนที่คอยให้คำตอบเป็นปัจจุบันในอีกไม่กี่ปีข้างหน้า
Tim Post

1
@ Tim Post: โอเคฉันจะลบความคิดเห็นของฉัน
Felix Kling

3
ฉันจะไม่ใช้strncpy()แทนทั่วไปstrcpy()และฉันจะไม่ใช้strncat()เลยเพราะมันมีอินเทอร์เฟซที่ไม่ใช้งานง่ายที่สุดเท่าที่จะเป็นไปได้ - คุณรู้หรือไม่ว่าพารามิเตอร์ความยาวระบุอะไร
Jonathan Leffler

2
การใช้ strncpy และ strncat มักเป็นข้อผิดพลาด ไม่ควรใช้แทน strcpy และ strcat อย่างแน่นอน !! scanf และ sprintf ยังสามารถใช้งานได้อย่างสมบูรณ์แบบหากคุณรู้วิธีใช้ ...
R .. GitHub STOP HELPING ICE

คำตอบ:


59

ฟังก์ชันที่
ไม่รองรับไม่ปลอดภัย
ตัวอย่างที่สมบูรณ์แบบของฟังก์ชันดังกล่าวคือgets ()เนื่องจากไม่มีวิธีใดที่จะบอกได้ว่าบัฟเฟอร์ปลายทางมีขนาดใหญ่เพียงใด ดังนั้นโปรแกรมใด ๆ ที่อ่านอินพุตใช้รับ () มีช่องโหว่หน่วยความจำล้น สำหรับเหตุผลที่คล้ายกันควรใช้strncpy ()ในสถานที่ของstrcpy ()และstrncat ()ในสถานที่ของstrcat ()

ตัวอย่างเพิ่มเติมบางส่วน ได้แก่ฟังก์ชันtmpfile ()และmktemp ()เนื่องจากปัญหาด้านความปลอดภัยที่อาจเกิดขึ้นกับการเขียนทับไฟล์ชั่วคราวและสิ่งที่ถูกแทนที่ด้วยฟังก์ชันmkstemp () ที่ปลอดภัยยิ่งขึ้น

Non-Reentrant
ตัวอย่างอื่น ๆ ได้แก่gethostbyaddr ()และgethostbyname ()ซึ่งจะไม่ reentrant (และดังนั้นจึงไม่รับประกันว่าจะเป็นด้าย) และได้รับการแทนที่โดย reentrant getaddrinfo ()และfreeaddrinfo ()

คุณอาจสังเกตเห็นรูปแบบที่นี่ ... ทั้งการขาดความปลอดภัย (อาจเกิดจากการไม่รวมข้อมูลที่เพียงพอในลายเซ็นเพื่อนำไปใช้อย่างปลอดภัย) หรือการไม่กลับเข้ามาใหม่เป็นแหล่งที่มาของการเลิกใช้งานทั่วไป

ล้าสมัยไม่พกพา
ฟังก์ชันอื่น ๆ บางอย่างเลิกใช้งานไปแล้วเนื่องจากมีฟังก์ชันการทำงานซ้ำกันและไม่สามารถพกพาได้เหมือนกับฟังก์ชันอื่น ๆ ยกตัวอย่างเช่นbzero ()จะเลิกในความโปรดปรานของmemset ()

ความปลอดภัยและการตอบกลับของเธรดที่
คุณถามในโพสต์ของคุณเกี่ยวกับความปลอดภัยของเธรดและการย้อนกลับ มีความแตกต่างเล็กน้อย ฟังก์ชันจะถูกส่งกลับหากไม่ใช้สถานะที่แบ่งใช้ร่วมกันใด ๆ ที่เปลี่ยนแปลงได้ ตัวอย่างเช่นหากข้อมูลทั้งหมดที่ต้องการถูกส่งผ่านไปยังฟังก์ชันและบัฟเฟอร์ใด ๆ ที่จำเป็นจะถูกส่งผ่านไปยังฟังก์ชันด้วย (แทนที่จะใช้ร่วมกันโดยการเรียกใช้ฟังก์ชันทั้งหมด) ข้อมูลนั้นจะถูกส่งกลับ นั่นหมายความว่าเธรดที่แตกต่างกันโดยใช้พารามิเตอร์อิสระจะไม่เสี่ยงต่อสถานะการแชร์โดยไม่ได้ตั้งใจ การคืนสภาพเป็นการรับประกันที่แข็งแกร่งกว่าความปลอดภัยของด้าย ฟังก์ชันจะปลอดภัยหากสามารถใช้เธรดหลายเธรดพร้อมกันได้ ฟังก์ชันจะปลอดภัยต่อเธรดหาก:

  • เป็น reentrant (กล่าวคือไม่แบ่งปันสถานะใด ๆ ระหว่างการโทร) หรือ:
  • ไม่ได้ reentrant แต่ใช้การซิงโครไนซ์ / ล็อกตามความจำเป็นสำหรับสถานะที่ใช้ร่วมกัน

โดยทั่วไปในSingle UNIX SpecificationและIEEE 1003.1 (เช่น "POSIX") ฟังก์ชันใด ๆ ที่ไม่รับประกันว่าจะ reentrant จะไม่รับประกันว่าจะปลอดภัยต่อเธรด ดังนั้นกล่าวอีกนัยหนึ่งเฉพาะฟังก์ชันที่รับประกันว่าสามารถ reentrant สามารถใช้แบบพกพาได้ในแอปพลิเคชันมัลติเธรด (โดยไม่ต้องล็อกภายนอก) อย่างไรก็ตามนั่นไม่ได้หมายความว่าการนำมาตรฐานเหล่านี้ไปใช้ไม่สามารถเลือกที่จะสร้างเธรดที่ปลอดภัยสำหรับฟังก์ชันที่ไม่สามารถย้อนกลับได้ ตัวอย่างเช่นลินุกซ์มักจะเพิ่มการซิงโครไนซ์ให้กับฟังก์ชันที่ไม่มีการป้อนกลับเพื่อเพิ่มการรับประกัน (นอกเหนือจากข้อกำหนด Single UNIX) ของเธรดความปลอดภัย

สตริง (และบัฟเฟอร์หน่วยความจำโดยทั่วไป)
คุณยังถามว่ามีข้อบกพร่องพื้นฐานบางอย่างกับสตริง / อาร์เรย์หรือไม่ บางคนอาจโต้แย้งว่าเป็นเช่นนั้น แต่ฉันขอยืนยันว่าไม่ไม่มีข้อบกพร่องพื้นฐานในภาษา C และ C ++ ต้องการให้คุณส่งผ่านความยาว / ความจุของอาร์เรย์แยกกัน (ไม่ใช่คุณสมบัติ ".length" เหมือนในภาษาอื่น ๆ ) นี่ไม่ใช่ข้อบกพร่อง แต่อย่างใด นักพัฒนา C และ C ++ ทุกคนสามารถเขียนโค้ดที่ถูกต้องได้ง่ายๆเพียงแค่ส่งความยาวเป็นพารามิเตอร์ตามต้องการ ปัญหาคือ API หลายตัวที่ต้องการข้อมูลนี้ไม่สามารถระบุเป็นพารามิเตอร์ได้ หรือสันนิษฐานว่าจะใช้ค่าคงที่ MAX_BUFFER_SIZE บางค่า ขณะนี้ API ดังกล่าวได้เลิกใช้แล้วและแทนที่ด้วย API ทางเลือกที่อนุญาตให้ระบุขนาดอาร์เรย์ / บัฟเฟอร์ / สตริงได้

Scanf (ในการตอบคำถามสุดท้ายของคุณ) โดย
ส่วนตัวแล้วฉันใช้ไลบรารี C ++ iostreams (std :: cin, std :: cout, ตัวดำเนินการ << และ >>, std :: getline, std :: istringstream, std :: ostringstream ฯลฯ ) ดังนั้นฉันมักจะไม่จัดการกับสิ่งนั้น ถ้าฉันถูกบังคับให้ใช้ C บริสุทธิ์โดยส่วนตัวฉันจะใช้fgetc ()หรือgetchar ()ร่วมกับstrtol () , strtoul ()ฯลฯ และแยกวิเคราะห์ด้วยตนเองเนื่องจากฉันไม่ใช่แฟนตัวยงของ varargs หรือสตริงรูปแบบ ที่กล่าวว่าจากความรู้ของฉันมากที่สุดไม่มีปัญหากับ[f] scanf () , [f] printf ()ฯลฯ ตราบเท่าที่คุณสร้างสตริงรูปแบบด้วยตัวเองคุณจะไม่ส่งผ่านสตริงรูปแบบที่กำหนดเองหรืออนุญาตให้ผู้ใช้ป้อนข้อมูลเป็นสตริงรูปแบบและคุณใช้มาโครการจัดรูปแบบที่กำหนดไว้ใน<inttypes.h>ตามความเหมาะสม (หมายเหตุควรใช้snprintf ()แทนsprintf ()แต่จะเกี่ยวข้องกับการไม่ระบุขนาดของบัฟเฟอร์ปลายทางและไม่ใช่การใช้สตริงรูปแบบ) ฉันควรชี้ให้เห็นว่าใน C ++ รูปแบบ boost ::ให้การจัดรูปแบบเหมือน printf โดยไม่มี varargs


4
"Deprecated" เป็นคำที่ชัดเจนซึ่งมีความหมายเฉพาะเมื่อกล่าวถึงมาตรฐาน C ++ ในแง่นั้นจะไม่มีการเลิกใช้งาน gets (), strcpy () ฯลฯ

4
ตราบเท่าที่คุณแยกความแตกต่างระหว่าง "เลิกใช้งานโดยมาตรฐาน C" "เลิกใช้งานโดย Michael Aaron Safyan" และ "เลิกใช้งานโดยบุคคลหรือบุคคลที่ไม่รู้จักซึ่งหวังว่าจะรู้ว่าพวกเขากำลังพูดถึงอะไร [ต้องการอ้างอิง]" คำถามจะเกี่ยวกับการแนะนำการเข้ารหัสรูปแบบไม่ได้เกี่ยวกับมาตรฐาน C ดังนั้นที่สองทั้งสองมีความเหมาะสม แต่เช่นเดียวกับนีลฉันต้องใช้เวลาสองครั้งก่อนที่จะตระหนักว่าข้อความของคุณไม่ได้ตั้งใจจะบอกเป็นนัยถึงความหมายแรก
Steve Jessop

11
strncpyโดยทั่วไปควรหลีกเลี่ยงเช่นกัน มันไม่ได้ทำในสิ่งที่โปรแกรมเมอร์ส่วนใหญ่คิดว่ามันทำ ไม่รับประกันการยุติ (ซึ่งนำไปสู่การโอเวอร์รันบัฟเฟอร์) และจะทำให้สตริงสั้นลง (อาจทำให้ประสิทธิภาพลดลงในบางกรณี)
Adrian McCarthy

2
@ เอเดรียน: ฉันเห็นด้วยกับคุณ - ไม่strncpy()เลวร้ายไปกว่าstrncat()นั้นคือการทดแทนที่สมเหตุสมผลสำหรับตัวแปรที่ไม่น้อยกว่า
Jonathan Leffler

4
คำตอบนี้กระจายความเชื่อที่ไร้สาระเกี่ยวกับ "แทนที่ strcpy ด้วย strncpy - ฉันไม่รู้ว่าทำไม แต่ Microsoft บอกให้ฉันทำ" strncpy ไม่เคยตั้งใจให้เป็นเวอร์ชันที่ปลอดภัยของ strcpy! หากต้องเผชิญกับความไม่ปลอดภัย ดูเหตุใด strlcpy และ strlcat จึงถือว่าไม่ปลอดภัย .
Lundin

24

เป็นอีกครั้งที่ผู้คนพูดซ้ำ ๆ กันเหมือนต้องมนต์การยืนยันอย่างไร้สาระว่าฟังก์ชัน str เวอร์ชัน "n" เป็นเวอร์ชันที่ปลอดภัย

หากนั่นคือสิ่งที่พวกเขาตั้งใจไว้พวกเขาก็จะยกเลิกสตริงเป็นโมฆะเสมอ

ฟังก์ชันเวอร์ชัน "n" ถูกเขียนขึ้นเพื่อใช้กับฟิลด์ที่มีความยาวคงที่ (เช่นรายการไดเร็กทอรีในระบบไฟล์ยุคแรก ๆ ) โดยที่ nul terminator จำเป็นต่อเมื่อสตริงไม่เต็มฟิลด์ นี่เป็นเหตุผลว่าทำไมฟังก์ชันจึงมีผลข้างเคียงแปลก ๆ ที่ไม่มีประสิทธิภาพหากใช้เพียงทดแทน - ใช้ strncpy () ตัวอย่างเช่น:

ถ้าอาร์เรย์ชี้ไปที่ s2 เป็นสตริงที่สั้นกว่า n ไบต์ไบต์ว่างจะถูกต่อท้ายกับสำเนาในอาร์เรย์ที่ชี้ด้วย s1 จนกว่าจะมีการเขียน n ไบต์ทั้งหมด

เนื่องจากบัฟเฟอร์ที่จัดสรรเพื่อจัดการกับชื่อไฟล์มักจะมีขนาด 4kbytes จึงทำให้ประสิทธิภาพการทำงานแย่ลงอย่างมาก

หากคุณต้องการเวอร์ชันที่ปลอดภัย "ตามสมควร" ให้ดาวน์โหลดหรือเขียน - กิจวัตร strl ของคุณเอง (strlcpy, strlcat ฯลฯ ) ซึ่งจะยุติสตริงและไม่มีผลข้างเคียง โปรดทราบว่าสิ่งเหล่านี้ไม่ปลอดภัยจริงๆเนื่องจากสามารถตัดสตริงได้อย่างเงียบ ๆ ซึ่งแทบจะไม่ได้เป็นแนวทางปฏิบัติที่ดีที่สุดในโปรแกรมใด ๆ ในโลกแห่งความเป็นจริง มีหลายครั้งที่สิ่งนี้ใช้ได้ แต่ก็มีหลายสถานการณ์เช่นกันที่อาจนำไปสู่ผลลัพธ์ที่ร้ายแรง (เช่นการพิมพ์ใบสั่งยาทางการแพทย์)


1
คุณมีสิทธิเกี่ยวแต่เกี่ยวกับการที่ไม่ถูกต้อง strncpy() ไม่ได้ออกแบบมาเพื่อใช้กับฟิลด์ที่มีความยาวคงที่ - จริง ๆ แล้วมันถูกออกแบบมาเพื่อจำกัด จำนวนอักขระที่ต่อกัน มันค่อนข้างง่ายที่จะใช้สิ่งนี้เป็น "ปลอดภัย" โดยการติดตามพื้นที่ที่เหลืออยู่ในบัฟเฟอร์เมื่อทำการเรียงต่อกันหลาย ๆ ครั้งและยังง่ายกว่าที่จะใช้เป็น "ปลอดภัย" (โดยการตั้งค่าอักขระตัวแรกของบัฟเฟอร์ปลายทางเป็นก่อน เรียกมัน) จะยกเลิกสตริงปลายทางเสมอและจะไม่เขียนs พิเศษ strncat()strncat()strcat()strcat()strcpy()'\0'strncat() '\0'
คาเฟ่

2
@caf - ใช่ แต่ strncat () ไม่มีประโยชน์โดยสิ้นเชิงเนื่องจากต้องใช้ความยาวสูงสุดที่จะคัดลอกเป็นพารามิเตอร์ไม่ใช่ความยาวของบัฟเฟอร์ปลายทาง เพื่อป้องกันไม่ให้บัฟเฟอร์ล้นคุณจำเป็นต้องทราบความยาวของสตริงปลายทางปัจจุบันและถ้าคุณรู้ว่าเหตุใดคุณจึงใช้ strncat () ซึ่งต้องคำนวณความยาวปลายทางอีกครั้งแทนที่จะเป็นเพียง strlcat () สตริงต้นทางเป็น จุดสิ้นสุดของสตริงปลายทาง
Dipstick

นั่นยังไม่เปลี่ยนความจริงที่ว่าคุณบอกเป็นนัยstrncat()ว่าไม่ได้ยุติปลายทางเสมอไปและถูกออกแบบมาเพื่อใช้กับฟิลด์ที่มีความยาวคงที่ซึ่งทั้งสองอย่างผิด
คาเฟ่

2
@chrisharris: strncat()จะทำงานอย่างถูกต้องโดยไม่คำนึงถึงความยาวของสตริงต้นทางในขณะที่strcat()จะไม่ทำงาน ปัญหาของstrlcat()ที่นี่คือมันไม่ใช่ฟังก์ชัน C มาตรฐาน
David Thornley

@caf - คุณพูดถูกต้องเกี่ยวกับ strncat () ฉันไม่เคยใช้มันจริง ๆ เพราะ - อย่างที่ฉันชี้ไว้ข้างต้น - มันไร้ประโยชน์โดยสิ้นเชิง ดังนั้นจึงควรหลีกเลี่ยง
Dipstick

19

หลายคำตอบที่นี่ขอแนะนำให้ใช้strncat()มากกว่าstrcat(); ฉันขอแนะนำว่าควรหลีกเลี่ยงstrncat()(และstrncpy()) ด้วย มีปัญหาที่ทำให้ใช้งานได้ยากและนำไปสู่ข้อบกพร่อง:

  • พารามิเตอร์ length to strncat()เกี่ยวข้องกับ (แต่ไม่ตรง - ดูจุดที่ 3) จำนวนอักขระสูงสุดที่สามารถคัดลอกไปยังปลายทางได้แทนที่จะเป็นขนาดของบัฟเฟอร์ปลายทาง ทำให้strncat()ใช้งานได้ยากกว่าที่ควรจะเป็นโดยเฉพาะอย่างยิ่งถ้าหลายรายการจะเชื่อมต่อกับปลายทาง
  • อาจเป็นเรื่องยากที่จะตรวจสอบว่าผลลัพธ์ถูกตัดทอนหรือไม่ (ซึ่งอาจสำคัญหรือไม่ก็ได้)
  • เป็นเรื่องง่ายที่จะมีข้อผิดพลาดทีละรายการ ดังบันทึกมาตรฐาน C99 "ดังนั้นจำนวนอักขระสูงสุดที่สามารถลงท้ายด้วยอาร์เรย์ที่ชี้โดยs1คือstrlen(s1)+n+1" สำหรับการเรียกที่ดูเหมือนstrncat( s1, s2, n)

strncpy()นอกจากนี้ยังมีปัญหาที่อาจทำให้เกิดข้อบกพร่องที่คุณพยายามใช้ด้วยวิธีที่เข้าใจง่าย - ไม่รับประกันว่าปลายทางจะถูกยกเลิก เพื่อให้แน่ใจว่าคุณต้องแน่ใจว่าคุณจัดการกรณีที่เข้ามุมโดยเฉพาะโดยการวาง'\0'ในตำแหน่งสุดท้ายของบัฟเฟอร์ด้วยตัวคุณเอง (อย่างน้อยก็ในบางสถานการณ์)

ฉันขอแนะนำให้ใช้บางอย่างเช่น OpenBSD strlcat()และstrlcpy()(แม้ว่าฉันรู้ว่าบางคนไม่ชอบฟังก์ชั่นเหล่านั้นฉันเชื่อว่ามันใช้งานง่ายกว่าอย่างปลอดภัยมากกว่าstrncat()/ strncpy())

นี่คือสิ่งที่ Todd Miller และ Theo de Raadt พูดถึงปัญหาstrncat()และstrncpy():

มีหลายปัญหาที่พบเมื่อstrncpy()และstrncat()จะถูกใช้เป็นรุ่นที่ปลอดภัยและstrcpy() strcat()ฟังก์ชันทั้งสองจัดการกับการสิ้นสุด NUL และพารามิเตอร์ความยาวในรูปแบบที่แตกต่างกันและไม่ใช้งานง่ายซึ่งสร้างความสับสนให้กับโปรแกรมเมอร์ที่มีประสบการณ์ นอกจากนี้ยังไม่มีวิธีง่ายๆในการตรวจจับเมื่อเกิดการตัดทอน ... จากปัญหาทั้งหมดนี้ความสับสนที่เกิดจากพารามิเตอร์ความยาวและปัญหาที่เกี่ยวข้องของการยกเลิก NUL นั้นสำคัญที่สุด เมื่อเราตรวจสอบแหล่งต้นไม้ OpenBSD สำหรับช่องโหว่ที่มีศักยภาพที่เราพบในทางที่ผิดอาละวาดและstrncpy() strncat()แม้ว่าสิ่งเหล่านี้จะไม่ส่งผลให้เกิดช่องโหว่ด้านความปลอดภัยที่ใช้ประโยชน์ได้ แต่ก็ทำให้ชัดเจนว่ากฎสำหรับการใช้งานstrncpy()และstrncat()การดำเนินการสตริงที่ปลอดภัยนั้นเข้าใจผิด

การตรวจสอบความปลอดภัยของ OpenBSD พบว่าจุดบกพร่องของฟังก์ชันเหล่านี้ "อาละวาด" ไม่เหมือนกับgets()ฟังก์ชันเหล่านี้สามารถใช้งานได้อย่างปลอดภัย แต่ในทางปฏิบัติมีปัญหามากมายเนื่องจากอินเทอร์เฟซสับสนไม่เข้าใจง่ายและใช้งานได้ยาก ฉันรู้ว่า Microsoft ได้ทำการวิเคราะห์ด้วย (แม้ว่าฉันจะไม่รู้ว่าข้อมูลของพวกเขาอาจเผยแพร่ไปมากแค่ไหน) และด้วยเหตุนี้จึงมีการแบน (หรืออย่างน้อยก็ท้อใจอย่างยิ่ง - 'การแบน' อาจไม่สมบูรณ์) การใช้strncat()และstrncpy()(ท่ามกลางฟังก์ชันอื่น ๆ )

ลิงก์บางส่วนที่มีข้อมูลเพิ่มเติม:


1
การติดตามความยาวของสตริงนอกสตริงนั้นดีกว่ามาก เช่นนั้นการเชื่อมต่อสองสตริงเข้าด้วยกัน (- มีความยาว) อย่างปลอดภัยกลายเป็นเรื่องของการคำนวณง่ายๆ (เพื่อให้ได้ขนาดบัฟเฟอร์ที่ต้องการ) การจัดสรรใหม่ที่เป็นไปได้และ a memmove(). (คุณสามารถใช้memcpy()ในกรณีปกติเมื่อสตริงเป็นอิสระ)
Donal Fellows

1
จุดที่สองของคุณไม่ถูกต้อง - strncat() จะยกเลิกสตริงปลายทางเสมอ
คาเฟ่

1
strncat()จุดที่สองของคุณคือผิด อย่างไรก็ตามมันถูกต้องสำหรับstrncpy()ซึ่งมีปัญหาอื่น ๆ strncat()เป็นแทนเหมาะสมstrcat()แต่ไม่เปลี่ยนที่เหมาะสมสำหรับstrncpy() strcpy()
David Thornley

2
คาเฟ่และเดวิดถูกต้อง 100% เกี่ยวกับการอ้างสิทธิ์ของฉันที่strncat()ไม่ได้ยุติลง ฉันสับสนกับพฤติกรรมของstrncat()และstrncpy()เล็กน้อย (อีกเหตุผลหนึ่งที่พวกเขาทำหน้าที่หลีกเลี่ยง - พวกเขามีชื่อที่บ่งบอกถึงพฤติกรรมที่คล้ายกัน แต่ในความเป็นจริงมีพฤติกรรมที่แตกต่างกันในรูปแบบที่สำคัญ ... ) ฉันได้แก้ไขคำตอบของฉันเพื่อแก้ไขปัญหานี้พร้อมทั้งเพิ่มข้อมูลเพิ่มเติม
Michael Burr

1
โปรดทราบว่าchar str[N] = ""; strncat(str, "long string", sizeof(str));บัฟเฟอร์ล้นหาก N ไม่ใหญ่พอ strncat()ฟังก์ชั่นเป็นเรื่องง่ายเกินไปที่จะในทางที่ผิด; ไม่ควรใช้ หากคุณสามารถใช้ได้strncat()อย่างปลอดภัยคุณสามารถใช้memmove()หรือใช้memcpy()แทนได้ (และสิ่งเหล่านี้จะมีประสิทธิภาพมากกว่า)
Jonathan Leffler

9

ฟังก์ชันไลบรารีมาตรฐานที่ไม่ควรใช้:

setjmp.h

  • setjmp(). ร่วมกับlongjmp()ฟังก์ชันเหล่านี้ได้รับการยอมรับอย่างกว้างขวางว่าเป็นอันตรายต่อการใช้งานอย่างไม่น่าเชื่อซึ่งนำไปสู่การเขียนโปรแกรมแบบสปาเก็ตตี้มีพฤติกรรมที่ไม่ได้กำหนดหลายรูปแบบซึ่งอาจทำให้เกิดผลข้างเคียงที่ไม่ได้ตั้งใจในสภาพแวดล้อมของโปรแกรมเช่นส่งผลต่อค่าที่เก็บไว้ในสแต็ก อ้างอิง: MISRA-C 2012 กฎ 21.4 CERT C MSC22-C
  • longjmp(). ดูsetjmp().

stdio.h

  • gets(). ฟังก์ชันถูกลบออกจากภาษา C (ตาม C11) เนื่องจากไม่ปลอดภัยตามการออกแบบ ฟังก์ชันนี้ถูกตั้งค่าสถานะว่าล้าสมัยใน C99 แล้ว ใช้fgets()แทน ข้อมูลอ้างอิง: ISO 9899: 2011 K.3.5.4.1 ดูหมายเหตุ 404 ด้วย

stdlib.h

  • atoi()ตระกูลฟังก์ชั่น สิ่งเหล่านี้ไม่มีการจัดการข้อผิดพลาด แต่จะเรียกใช้พฤติกรรมที่ไม่ได้กำหนดเมื่อใดก็ตามที่เกิดข้อผิดพลาด ฟังก์ชันที่ไม่จำเป็นโดยสิ้นเชิงที่สามารถแทนที่ด้วยstrtol()ตระกูลฟังก์ชัน ข้อมูลอ้างอิง: MISRA-C: 2012 rule 21.7

สตริง h

  • strncat(). มีอินเทอร์เฟซที่น่าอึดอัดซึ่งมักใช้ในทางที่ผิด ส่วนใหญ่เป็นฟังก์ชันที่ไม่จำเป็น strncpy()ยังเห็นข้อสังเกตสำหรับ
  • strncpy(). ความตั้งใจของฟังก์ชันนี้ไม่เคยเป็นเวอร์ชันที่ปลอดภัยกว่าของstrcpy(). จุดประสงค์เดียวคือจัดการรูปแบบสตริงโบราณบนระบบ Unix เสมอและการรวมอยู่ในไลบรารีมาตรฐานถือเป็นข้อผิดพลาดที่ทราบ ฟังก์ชั่นนี้เป็นอันตรายเนื่องจากอาจปล่อยให้สตริงโดยไม่มีการสิ้นสุดเป็นโมฆะและโปรแกรมเมอร์มักใช้อย่างไม่ถูกต้อง ข้อมูลอ้างอิง: เหตุใด strlcpy และ strlcat จึงถือว่าไม่ปลอดภัย .

ฟังก์ชันไลบรารีมาตรฐานที่ควรใช้ด้วยความระมัดระวัง:

ยืนยัน h

  • assert(). มาพร้อมกับค่าใช้จ่ายและโดยทั่วไปไม่ควรใช้ในรหัสการผลิต ควรใช้ตัวจัดการข้อผิดพลาดเฉพาะแอปพลิเคชันซึ่งแสดงข้อผิดพลาด แต่ไม่จำเป็นต้องปิดโปรแกรมทั้งหมด

สัญญาณ h

  • signal(). อ้างอิง: MISRA-C 2012 กฎ 21.5 CERT C SIG32-C

stdarg.h

  • va_arg()ตระกูลฟังก์ชั่น การมีฟังก์ชั่นความยาวผันแปรในโปรแกรม C มักจะบ่งบอกถึงการออกแบบโปรแกรมที่ไม่ดี ควรหลีกเลี่ยงเว้นแต่คุณจะมีข้อกำหนดที่เฉพาะเจาะจงมาก

stdio.h
โดยทั่วไปแล้วไม่แนะนำให้ใช้ไลบรารีทั้งหมดนี้สำหรับโค้ดการผลิตเนื่องจากมีหลายกรณีของพฤติกรรมที่กำหนดไม่ดีและประเภทความปลอดภัยที่ไม่ดี

  • fflush(). เหมาะอย่างยิ่งสำหรับใช้สำหรับสตรีมเอาต์พุต เรียกใช้พฤติกรรมที่ไม่ได้กำหนดหากใช้สำหรับอินพุตสตรีม
  • gets_s(). เวอร์ชันปลอดภัยที่gets()รวมอยู่ในอินเทอร์เฟซการตรวจสอบขอบเขต C11 ขอแนะนำให้ใช้fgets()แทนตามคำแนะนำมาตรฐาน C เอกสารอ้างอิง: ISO 9899: 2011 K.3.5.4.1
  • printf()ตระกูลฟังก์ชั่น ทรัพยากรฟังก์ชั่นหนักที่มาพร้อมกับพฤติกรรมที่ไม่ได้กำหนดจำนวนมากและความปลอดภัยประเภทที่ไม่ดี sprintf()ยังมีช่องโหว่ ควรหลีกเลี่ยงฟังก์ชันเหล่านี้ในรหัสการผลิต เอกสารอ้างอิง: MISRA-C: 2012 rule 21.6.
  • scanf()ตระกูลฟังก์ชั่น ดูข้อสังเกตเกี่ยวกับprintf(). นอกจากนี้ - scanf()มีความเสี่ยงที่จะบัฟเฟอร์มากเกินไปหากใช้ไม่ถูกต้อง fgets()ควรใช้เมื่อเป็นไปได้ เอกสารอ้างอิง: CERT C INT05-C , MISRA-C: 2012 rule 21.6
  • tmpfile()ตระกูลฟังก์ชั่น มาพร้อมกับปัญหาช่องโหว่ต่างๆ ข้อมูลอ้างอิง: CERT C FIO21-C .

stdlib.h

  • malloc()ตระกูลฟังก์ชั่น ดีอย่างสมบูรณ์แบบที่จะใช้ในระบบเจ้าภาพแม้ว่าจะตระหนักถึงปัญหาที่รู้จักกันดีใน C90 และดังนั้นจึงไม่ได้ทิ้งผล malloc()ครอบครัวของฟังก์ชั่นไม่ควรที่จะใช้ในงานอิสระ เอกสารอ้างอิง: MISRA-C: 2012 rule 21.3.

    นอกจากนี้โปรดทราบว่าrealloc()เป็นอันตรายในกรณีที่คุณเขียนทับตัวชี้เก่าด้วยผลลัพธ์ของrealloc(). ในกรณีที่ฟังก์ชันล้มเหลวคุณจะสร้างการรั่วไหล

  • system(). มาพร้อมกับค่าใช้จ่ายจำนวนมากและแม้ว่าจะพกพาได้ แต่ก็มักจะใช้ฟังก์ชัน API เฉพาะระบบแทนได้ดีกว่า มาพร้อมกับพฤติกรรมที่กำหนดไว้ไม่ดีต่างๆ อ้างอิง: CERT C ENV33-C

สตริง h

  • strcat(). strcpy()ดูหมายเหตุสำหรับ
  • strcpy(). ใช้งานได้อย่างสมบูรณ์แบบเว้นแต่ว่าขนาดของข้อมูลที่จะคัดลอกนั้นไม่ทราบขนาดหรือใหญ่กว่าบัฟเฟอร์ปลายทาง หากไม่มีการตรวจสอบขนาดข้อมูลขาเข้าอาจมีการโอเวอร์รันบัฟเฟอร์ ซึ่งเป็นความผิดของไม่มีstrcpy()ตัวเอง แต่ของแอพลิเคชันโทร - ที่strcpy()ไม่ปลอดภัยส่วนใหญ่จะเป็นตำนานที่สร้างขึ้นโดยไมโครซอฟท์
  • strtok(). แก้ไขสตริงผู้โทรและใช้ตัวแปรสถานะภายในซึ่งอาจทำให้ไม่ปลอดภัยในสภาพแวดล้อมแบบมัลติเธรด

ฉันขอแนะนำให้แนะนำstatic_assert()ในassert()กรณีที่สามารถแก้ไขเงื่อนไขได้ในเวลาคอมไพล์ นอกจากนี้ยังsprintf()สามารถเปลี่ยนได้เกือบตลอดเวลาsnprintf()ซึ่งปลอดภัยกว่าเล็กน้อย
user694733

1
การใช้strtok()ในฟังก์ชัน A หมายความว่า (a) ฟังก์ชันไม่สามารถเรียกฟังก์ชันอื่นใดที่ใช้strtok()ในขณะที่ A ใช้งานได้เช่นกันและ (b) หมายความว่าไม่มีฟังก์ชันใดที่เรียกใช้ A strtok()เมื่อเรียกใช้ A กล่าวอีกนัยหนึ่งคือการใช้strtok()เป็นพิษต่อสายโซ่; ไม่สามารถใช้อย่างปลอดภัยในรหัสไลบรารีได้เนื่องจากต้องจัดทำเอกสารที่ใช้strtok()เพื่อป้องกันไม่ให้ผู้ใช้รายอื่นstrtok()เรียกรหัสไลบรารี
Jonathan Leffler

ฟังก์ชันstrncpyนี้เป็นฟังก์ชันที่เหมาะสมที่จะใช้เมื่อเขียนสตริงบัฟเฟอร์ที่มีเบาะเป็นศูนย์พร้อมข้อมูลที่นำมาจากสตริงที่มีการสิ้นสุดศูนย์หรือบัฟเฟอร์ที่มีเบาะเป็นศูนย์ซึ่งมีขนาดอย่างน้อยที่สุดเท่าที่ปลายทาง บัฟเฟอร์ที่ไม่มีเบาะเป็นศูนย์ไม่ใช่เรื่องธรรมดามากนัก แต่ก็ไม่ได้คลุมเครือเช่นกัน
supercat

7

บางคนจะอ้างว่าstrcpyและstrcatควรหลีกเลี่ยงในความโปรดปรานของและstrncpy strncatนี่เป็นเรื่องส่วนตัวในความคิดของฉัน

ควรหลีกเลี่ยงอย่างแน่นอนเมื่อจัดการกับอินพุตของผู้ใช้ - ไม่ต้องสงสัยเลยที่นี่

ในรหัส "ห่างไกล" จากผู้ใช้เมื่อคุณเพิ่งรู้ว่าบัฟเฟอร์ยาวเพียงพอstrcpyและstrcatอาจมีประสิทธิภาพมากกว่าเล็กน้อยเนื่องจากการคำนวณnเพื่อส่งต่อไปยังลูกพี่ลูกน้องของพวกเขาอาจไม่จำเป็น


4
และถ้ามีก็ยังดีกว่าstrlcatและstrlcpyเนื่องจากเวอร์ชัน 'n' ไม่รับประกันการยุติสตริงปลายทางที่เป็น NULL
Dan Andreatta

ดูเหมือนการเพิ่มประสิทธิภาพก่อนกำหนดสำหรับฉัน แต่ IIRC strncpy()จะเขียนเป็นnไบต์โดยใช้อักขระ nul หากจำเป็น ในฐานะ Dan การใช้เวอร์ชันปลอดภัยเป็นตัวเลือกที่ดีที่สุด IMO
Bastien Léonard

@ Dan ฟังก์ชั่นเหล่านี้น่าเสียดายที่ไม่เป็นมาตรฐานดังนั้นจึงไม่ได้อยู่ในการสนทนานี้
Eli Bendersky

@ เอลี: แต่ความจริงที่strncat()อาจเป็นเรื่องยากที่จะใช้อย่างถูกต้องและปลอดภัย (และควรหลีกเลี่ยง) อยู่ในหัวข้อ
Michael Burr

@ ไมเคิล: ฉันจะไม่บอกว่ามันยากที่จะใช้อย่างถูกต้องและปลอดภัย ด้วยความระมัดระวังมันก็ใช้ได้ดี
Eli Bendersky

6

หลีกเลี่ยง

  • strtok สำหรับโปรแกรมมัลติเธรดเนื่องจากไม่ปลอดภัยต่อเธรด
  • gets เนื่องจากอาจทำให้เกิดบัฟเฟอร์ล้น

2
เป็นกรณีที่แตกต่างกันเล็กน้อย คุณสามารถใช้ strtok ได้อย่างปลอดภัยหากคุณรู้ว่าโปรแกรมของคุณไม่ใช่มัลติเธรดหรือคุณล็อกการเข้าถึง แต่คุณไม่สามารถใช้งานได้อย่างปลอดภัยดังนั้นไม่ควรใช้
jcoder

9
ปัญหากับstrtok()ไปเล็ก ๆ น้อย ๆ ที่อยู่นอกเหนือความปลอดภัยหัวข้อ - มันไม่ปลอดภัยแม้ในโปรแกรมเดียวเกลียวจนกว่าคุณจะรู้ได้อย่างชัดเจนว่าฟังก์ชั่นที่ไม่มีรหัสของคุณอาจจะเรียกในขณะที่ใช้strtok()ไม่ได้ยังใช้ (หรือพวกเขาจะเลอะstrtok()ของรัฐที่เหมาะสม จากใต้คุณ) ในความเป็นจริงคอมไพเลอร์ส่วนใหญ่ที่กำหนดเป้าหมายแพลตฟอร์มแบบมัลติเธรดจะดูแลstrtok()ปัญหาที่อาจเกิดขึ้นได้เท่าที่เธรดดำเนินการโดยใช้ที่จัดเก็บเธรดโลคัลสำหรับstrtok()ข้อมูลคงที่ของเธรด แต่นั่นก็ยังไม่สามารถแก้ไขปัญหาของฟังก์ชันอื่น ๆ ที่ใช้งานได้ในขณะที่คุณใช้งานอยู่ (ในเธรดเดียวกัน)
Michael Burr

อันที่จริงและฉันจะหุบปากทันทีเพราะฉันไม่ต้องการสนับสนุนให้ใครใช้ strtok เพราะมันประสบปัญหามากมาย ฉันแค่อยากจะชี้ให้เห็นว่ามันแตกต่างจากการได้รับแม้ว่าจะสามารถใช้งานได้อย่างปลอดภัยในขณะที่ใช้งานไม่ได้อย่างปลอดภัย
jcoder

@ จิมมี่: มักจะมีส่วนขยายของไลบรารีที่ไม่เป็นมาตรฐานหรือคุณอาจเขียนเองก็ได้ ปัญหาใหญ่strtok()คือมันเก็บบัฟเฟอร์เพียงตัวเดียวที่จะทำงานได้ดังนั้นการแทนที่ที่ดีส่วนใหญ่จำเป็นต้องมีการเก็บค่าบัฟเฟอร์ไว้รอบ ๆ และส่งผ่านไป
David Thornley

strcspnทำสิ่งที่คุณต้องการเกือบทั้งหมด - ค้นหาตัวคั่นโทเค็นถัดไป คุณสามารถนำรูปแบบที่มีเหตุผลมาstrtokใช้ใหม่ได้
bluss

5

อาจคุ้มค่าที่จะเพิ่มอีกครั้งที่strncpy()ไม่ใช่การแทนที่ด้วยวัตถุประสงค์ทั่วไปstrcpy()ที่ชื่ออาจแนะนำ ได้รับการออกแบบมาสำหรับฟิลด์ที่มีความยาวคงที่ซึ่งไม่จำเป็นต้องมี nul-terminator (เดิมถูกออกแบบมาเพื่อใช้กับรายการไดเรกทอรี UNIX แต่อาจมีประโยชน์สำหรับสิ่งต่างๆเช่นช่องคีย์การเข้ารหัส)

อย่างไรก็ตามเป็นเรื่องง่ายที่จะใช้strncat()แทนstrcpy():

( ifเห็นได้ชัดว่าการทดสอบสามารถลดลงได้ในกรณีทั่วไปซึ่งคุณรู้ว่าdest_sizeไม่ใช่ศูนย์แน่นอน)


5

นอกจากนี้ยังตรวจสอบรายชื่อ Microsoft ของAPI ที่ต้องห้าม API เหล่านี้ (รวมถึงหลายรายการที่แสดงไว้ที่นี่แล้ว) ที่ถูกแบนจากรหัสของ Microsoft เนื่องจากมักใช้ผิดประเภทและนำไปสู่ปัญหาด้านความปลอดภัย

คุณอาจไม่เห็นด้วยกับพวกเขาทั้งหมด แต่ก็คุ้มค่าที่จะพิจารณา พวกเขาเพิ่ม API ลงในรายการเมื่อการใช้งานผิดวัตถุประสงค์ทำให้เกิดข้อบกพร่องด้านความปลอดภัยจำนวนมาก


2

เกือบทุกฟังก์ชันที่เกี่ยวข้องกับสตริงที่ยกเลิก NUL อาจไม่ปลอดภัย หากคุณกำลังรับข้อมูลจากโลกภายนอกและจัดการข้อมูลผ่านทางฟังก์ชัน str * () แสดงว่าคุณเตรียมพร้อมสำหรับภัยพิบัติ


2

อย่าลืมเกี่ยวกับ sprintf - มันเป็นสาเหตุของปัญหามากมาย นี่เป็นความจริงเนื่องจากทางเลือกอื่น snprintf มีการใช้งานที่แตกต่างกันในบางครั้งซึ่งอาจทำให้คุณไม่สามารถรายงานรหัสได้

  1. ลินุกซ์: http://linux.die.net/man/3/snprintf

  2. windows: http://msdn.microsoft.com/en-us/library/2ts7cx93%28VS.71%29.aspx

ในกรณีที่ 1 (linux) ค่าส่งคืนคือจำนวนข้อมูลที่จำเป็นในการจัดเก็บบัฟเฟอร์ทั้งหมด (หากมีขนาดเล็กกว่าขนาดของบัฟเฟอร์ที่กำหนดผลลัพธ์จะถูกตัดทอน)

ในกรณีที่ 2 (windows) ค่าที่ส่งคืนเป็นจำนวนลบในกรณีที่เอาต์พุตถูกตัดทอน

โดยทั่วไปคุณควรหลีกเลี่ยงฟังก์ชันที่ไม่ใช่:

  1. บัฟเฟอร์ล้นปลอดภัย (มีการกล่าวถึงฟังก์ชั่นมากมายที่นี่)

  2. เธรดปลอดภัย / ไม่ reentrant (เช่น strtok)

ในคู่มือของแต่ละฟังก์ชันคุณควรค้นหาคีย์เวิร์ดเช่น: safe, sync, async, thread, buffer, bugs


2
_sprintf()ถูกสร้างขึ้นโดย Microsoft ก่อนที่มาตรฐานจะsnprintf()มาถึง IIRC ´StringCbPrintf () ´ค่อนข้างคล้ายกับsnprintf()แม้ว่า
Bastien Léonard

คุณสามารถใช้sprintfอย่างใดอย่างปลอดภัยในบางกรณี: sprintf(buffer,"%10s",input);จำกัด nb คัดลอกไบต์ถึง 10 (ถ้าbufferเป็นchar buffer[11]มันปลอดภัยแม้ว่าข้อมูลอาจลมขึ้นตัดทอน.
Jean-Françoisฟาเบร

2

มันยากมากที่จะใช้scanfอย่างปลอดภัย การใช้งานที่ดีscanfสามารถหลีกเลี่ยงการเกิดบัฟเฟอร์ล้น แต่คุณยังคงเสี่ยงต่อพฤติกรรมที่ไม่ได้กำหนดเมื่ออ่านตัวเลขที่ไม่ตรงกับประเภทที่ร้องขอ ในกรณีส่วนใหญ่fgetsตามด้วยตนเองแยก (ใช้sscanf, strchrฯลฯ ) เป็นตัวเลือกที่ดีกว่า

แต่ฉันจะไม่พูดว่า "หลีกเลี่ยงscanfตลอดเวลา" scanfมีการใช้งาน ตัวอย่างเช่นสมมติว่าคุณต้องการอ่านอินพุตของผู้ใช้ในcharอาร์เรย์ที่มีความยาว 10 ไบต์ คุณต้องการลบบรรทัดต่อท้ายถ้ามี หากผู้ใช้ป้อนอักขระมากกว่า 9 ตัวก่อนขึ้นบรรทัดใหม่คุณต้องการจัดเก็บอักขระ 9 ตัวแรกในบัฟเฟอร์และทิ้งทุกอย่างจนกว่าจะขึ้นบรรทัดใหม่ถัดไป คุณทำได้:

เมื่อคุณคุ้นเคยกับสำนวนนี้แล้วมันจะสั้นกว่าและในบางวิธีก็สะอาดกว่า:


0

ในสถานการณ์จำลองสตริงคัดลอก / ย้ายทั้งหมด - strcat (), strncat (), strcpy (), strncpy () ฯลฯ - สิ่งต่าง ๆ จะดีขึ้นมาก ( ปลอดภัยกว่า ) หากมีการบังคับใช้ฮิวริสติกสองสามแบบ:

   1. เติม NUL เสมอ บัฟเฟอร์ของคุณก่อนเพิ่มข้อมูล
   2. ประกาศบัฟเฟอร์อักขระเป็น [SIZE + 1] โดยมีค่าคงที่มาโคร

ตัวอย่างเช่นกำหนด:

เราสามารถใช้รหัสเช่น:

ค่อนข้างปลอดภัย memset () ควรปรากฏก่อน strncpy () แม้ว่าเราจะเริ่มต้นบัฟเฟอร์ในเวลาคอมไพล์เนื่องจากเราไม่ทราบว่ามีการใส่โค้ดอื่นใดลงไปก่อนที่ฟังก์ชันของเราจะถูกเรียกใช้ strncpy () จะตัดทอนข้อมูลที่คัดลอกเป็น "1234567890" และจะไม่ยุติ NUL อย่างไรก็ตามเนื่องจากเราได้เติม NUL เต็มบัฟเฟอร์ทั้งหมดแล้ว - sizeof (Buffer) แทนที่จะเป็น BUFSIZE จึงรับประกันได้ว่าจะมีการยกเลิก NUL แบบ "นอกขอบเขต" ขั้นสุดท้ายตราบใดที่เรา จำกัด การเขียนของเราโดยใช้ BUFSIZE ค่าคงที่แทนที่จะเป็น sizeof (บัฟเฟอร์)

บัฟเฟอร์และ BUFSIZE ทำงานได้ดีสำหรับ snprintf ():

แม้ว่า snprintf () จะเขียนเฉพาะอักขระ BUFIZE-1 เท่านั้นตามด้วย NUL แต่ก็ทำงานได้อย่างปลอดภัย ดังนั้นเราจึง "เสีย" NUL ไบต์ที่ไม่เกี่ยวข้องในตอนท้ายของบัฟเฟอร์ ... เราป้องกันทั้งบัฟเฟอร์ล้นและเงื่อนไขสตริงที่ไม่สิ้นสุดสำหรับหน่วยความจำต้นทุนเล็กน้อย

การโทรของฉันบน strcat () และ strncat () นั้นยากกว่า: อย่าใช้มัน เป็นการยากที่จะใช้ strcat () อย่างปลอดภัยและ API สำหรับ strncat () นั้นใช้งานง่ายมากจนความพยายามที่จำเป็นในการใช้งานอย่างถูกต้องจะลบล้างผลประโยชน์ใด ๆ ฉันเสนอดรอปอินต่อไปนี้:

การสร้างดร็อปอิน strcat () เป็นเรื่องที่น่าดึงดูด แต่ไม่ใช่ความคิดที่ดี:

เนื่องจากเป้าหมายอาจเป็นตัวชี้ (ดังนั้น sizeof () จึงไม่ส่งคืนข้อมูลที่เราต้องการ) ฉันไม่มีโซลูชัน "สากล" ที่ดีสำหรับอินสแตนซ์ของ strcat () ในโค้ดของคุณ

ปัญหาที่ฉันพบบ่อยจากโปรแกรมเมอร์ "strFunc () - awareness คือความพยายามในการป้องกันบัฟเฟอร์ล้นโดยใช้ strlen () นี่เป็นเรื่องปกติหากรับประกันว่าเนื้อหาจะถูกยกเลิก NUL มิฉะนั้น strlen () เองอาจทำให้เกิดข้อผิดพลาดบัฟเฟอร์โอเวอร์รันได้ (โดยปกติจะนำไปสู่การละเมิดการแบ่งกลุ่มหรือสถานการณ์การถ่ายโอนข้อมูลหลักอื่น ๆ ) ก่อนที่คุณจะไปถึงโค้ด "ที่มีปัญหา" ที่คุณพยายามป้องกัน


-2

atoi ไม่ด้ายปลอดภัย ฉันใช้ strtol แทนตามคำแนะนำจาก man page


5
ดูเหมือนว่าจะใช้กับการนำไปใช้งานอย่างใดอย่างหนึ่ง ไม่มีเหตุผลใดที่strtol()จะปลอดภัยต่อเธรดและatoi()จะไม่เป็นเช่นนั้น
David Thornley

2
คำแนะนำในการใช้ strtol ไม่มีส่วนเกี่ยวข้องกับความปลอดภัยของเธรด แต่มีข้อผิดพลาดในการจัดการ ไม่แน่ใจว่าคุณได้รับข้อมูลนั้นจากหน้าคนใด - ฉันไม่พบคำแนะนำใด ๆ ด้านล่างman atoi(ควรมี)
Lundin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.