יום שלישי, מאי 30, 2023

כשאומרים שיש משהוא שהוא בטוח, לפעמים זה לא אומר מה שאתה חושב שזה אומר

בתקופה האחרונה התחילו לעבור לשימוש במערכות בטוחות בשביל לההחליף את הדברים המקובלים שקיימים כבר שנים, משום מה חושבים שכשמדברים על דברים בטוחים לא יהיו חריגות. אם יצא לכם לכתוב בשפת C ב VS והשתמשתם בפונקציות strcpy או strcat יכול להיות שראיתם את ההמלצה החמה לעבור לשימוש בפונקציותה המסתיימות ב_s מכיוון שזה משהוא "בטוח".
 
הבעיה שהרבה מאוד אנשים לא מבינים מה אומרת המילה בטוח, ופשוט מאמצים את הבקשה ומחליפים את הקוד להשתמש ב _s ושוכחים מזה. הבעיה היא שדבר ראשון זה ממש לא קוד פורטבילי אלא שיש תופעת לוואי חריגה (ידועה) שהיא העלאת אירוע חריגה.
 
לדוגמה הקוד הלא תקין הבא:

#include <stdio.h>
#include <string.h>

void bad_function(const char * const argument_to_copy)
{
   char destination[10];
   strcpy(destination,argument_to_copy);
 }
int main()
{
  bad_function("this is an example of bad coding");
  return 0;
}

הקוד הזה לא נותן לנו שום התראה כברירת מחדל ב gcc ,אבל אם נקמפל זאת ב VS ונפעיל התראות נקבל המלצה להשתמש ב strcpy_s כי הוא בטוח יותר, אבל הבטיחות שלו מגיעה מזה שהחליפו את הoverflow הישן והטוב במשהוא גרוע שהוא זריקת חריגה שנושכת אותך בתוחס לאחר חצי שנה (כי משהוא שכח לבדוק את גודל המערך). 

למזלנו gcc לא מכיל את ההמלצה להשתמש בזה, ולנו בקבצי man יש הסבר טוב מאוד לגבי זה שאומר 

Bugs

If the destination string of a strcpy() is not large enough, then anything might happen. Overflowing fixed-length string buffers is a favorite cracker technique for taking complete control of the machine. Any time a program reads or copies data into a buffer, the program first needs to check that there's enough space. This may be unnecessary if you can show that overflow is impossible, but be careful: programs can get changed over time, in ways that may make the impossible possible.

מהניסיון שלי, המנעו משימוש בפונקציות _s, אבל בדקו את הגודל תמיד והשתמשו ב strncpy מלתחילה, השתמשו בקוד פורטבילי ולא קוד שיעבוד רק ב VS. חבל שהאנשים שעומדים מאחורי Visual Studio שוב פעם מנסים להפוך שפה פשוטה, ומקובלת למשהוא שיהיה רק של הקומפיילר הזה.

2 תגובות:

ארתיום אמר/ה...

האמת, הנוהל הסטנדרטי כשעובדים עם Visual Studio זה פשוט לכבות את ההתראות האלה. בעיקר בגלל אי אבחנה בין פונקציות בעייתיות ושאר פונקציות נורנליות.

המזל שב־VS2017 התמיכה ב־C99 כבר סבירה. למשל יש snprintf וכד' כך שאפשר לכתוב בצורה תקינה וזהו.

אבל יש חלק הבעייתיים שצריך להיות מודע אליו (הוא לא ב־strcpy)

למשל strncpy שלא ישים 0 בסוף המחרוזת אם היא גדולה מהיעד. ורבים לא מכירית את זה. זה לא ממש אינטואיטיבי ומפתיע היום. לכן תמיד צריך לדאוג שיהיה 0 בסוף בצורה ידנית

גם פרמטרים של strncat מפתיעים כי אורך מתייחס לא גודל היעד אלא של מקור.

אני פשוט משתמש ב־snprintf כשעובד ב־C שהרבה יותר נוח בטיפול במחרוזות.

אנונימי אמר/ה...

תראה, תשמע, אצלי לא רק שלא מכבים אלא אפילו מפעילים מספר רמות, משתמשים ב SAL, ואפילו GSL, אני האמת משתמש ב Visual Studio 2022 ולא 17 (ובכלל 15 כנראה היה האחרון הטוב באמת).

לגבי הנקודה לגבי הטרמנציה, הדבר מתועד ומתכנתים צעירים לומדים את זה די מהר (ymmv), לגבי הגדלים , זה האמת די מקובל כאשר יש ארגומנט אחד. הבעסה ש strcpy_s .

נ.ב. יחי C11 !