الوصول غير الصالح
الوصول خارج الحدود والبيانات غير المهيّأة
الوصول غير الصالح درس مجاني في C Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.
ما بعد التسرّبات
تهدر التسرّبات الذاكرة، لكن أخطاء الوصول غير الصالح تتسبب في إتلافها. تكتشف memcheck عدة أنواع منها:
- القراءة أو الكتابة بعد نهاية المخزن المؤقت
- استخدام الذاكرة بعد
free - قراءة قيم غير مهيّأة
- القراءة أو الكتابة عبر مؤشر غير صالح
تسبب هذه الأخطاء أخطر حالات التعطل وأصعبها من حيث إعادة الإنتاج.
الكتابة خارج الحدود
يخصص هذا البرنامج مساحة تكفي لـ 5 أعداد صحيحة، لكنه يكتب في الفهرس 5، أي في الخانة السادسة.
الفهرس 5 يتجاوز النهاية بعنصر واحد. وتبلغ memcheck عن Invalid write of size 4 في هذا السطر.
#include <stdlib.h>
int main(void) {
int *a = malloc(5 * sizeof(int));
a[5] = 99; /* valid indices are 0..4 */
free(a);
return 0;
}قراءة الخطأ
يذكر التقرير العملية والحجم والعلاقة بالكتلة:
Invalid write of size 4Address 0x... is 0 bytes after a block of size 20 alloc'd
تخبرك العبارة '0 bytes after a block of size 20' بأن الوصول وقع مباشرةً بعد كتلة حجمها 20 بايتًا (أي 5 أعداد صحيحة).
القراءة خارج الحدود
تُكتشف القراءات أيضًا. ففي هذه الحالة، تتجاوز الحلقة النهاية بعنصر واحد.
تبلغ memcheck عن Invalid read of size 4 في التكرار الأخير، حتى لو بدا أن البرنامج قد «يعمل» مصادفةً.
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *a = calloc(3, sizeof(int));
for (int i = 0; i <= 3; i++) /* should be i < 3 */
printf("%d\n", a[i]);
free(a);
return 0;
}القيم غير المهيّأة
لا تملأ malloc الذاكرة بالأصفار. ويؤدي استخدامها قبل إسناد قيمة إليها إلى إنتاج قيمة غير متوقعة.
تبلغ memcheck عن Conditional jump or move depends on uninitialised value(s) عندما تؤثر مثل هذه القيمة في تدفق التحكم أو في المخرجات.
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *p = malloc(sizeof(int));
if (*p == 0) /* *p was never set */
printf("zero\n");
free(p);
return 0;
}لماذا تتأخر تقارير القيم غير المهيّأة
لا تُصدر memcheck تنبيهًا لحظة قراءة ذاكرة غير مهيّأة. فهي تتتبع «التعريف» ولا تبلغ عن الخطأ إلا عندما تصبح قيمة غير معرّفة مهمة فعلًا، مثل استخدامها في فرع أو مخرج أو استدعاء نظام.
يمنع ذلك الإنذارات الكاذبة عند نسخ البايتات غير المهيّأة دون ضرر.
الاستخدام بعد التحرير
يُعد لمس الذاكرة بعد تحريرها سلوكًا غير معرّف. وتكتشفه memcheck بدقة.
تبلغ عن Invalid read of size 4 مع الملاحظة Address ... is 0 bytes inside a block of size 4 free'd، كما تعرض مكان حدوث free.
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 7;
free(p);
printf("%d\n", *p); /* read after free */
return 0;
}التحرير المزدوج
يؤدي تحرير المؤشر نفسه مرتين إلى إفساد سجلات إدارة الذاكرة.
يُبلغ memcheck عن Invalid free() ويعرض كلًّا من عملية التحرير الحالية والتخصيص الأصلي، مما يجعل الخطأ واضحًا.
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
free(p);
free(p); /* freed twice */
return 0;
}تتبّع المصادر
بالنسبة إلى أخطاء القيم غير المُهيّأة، أضف --track-origins=yes.
عندئذٍ يُبلغ memcheck عن الموضع الذي أُنشئت فيه القيمة الخاطئة، وليس فقط الموضع الذي استُخدمت فيه، مما يحوّل التحذير الغامض إلى إصلاح دقيق.
valgrind --track-origins=yes ./progالمكدس والمتغيرات العامة
يتفوّق memcheck في اكتشاف أخطاء الكومة. أما تغطيته للفيضانات في المكدس أو في المصفوفات العامة فهي أضعف.
في هذه الحالات، يكون AddressSanitizer (gcc -fsanitize=address) غالبًا الخيار الأفضل. وتكمّل الأداتان إحداهما الأخرى.
الخطأ بمقدار واحد: المُنهي الصفري
من أخطاء فيضان الكومة الشائعة نسيان مُنهي السلسلة النصية. تُعيد strlen القيمة 5 للسلسلة 'hello'، لكن السلسلة تحتاج إلى 6 بايتات لتخزين '\0' اللاحقة.
يُبلغ memcheck عن عملية كتابة غير صالحة عندما تكتب strcpy ذلك البايت الأخير بعد نهاية المساحة.
#include <stdlib.h>
#include <string.h>
int main(void) {
char *s = malloc(strlen("hello")); /* needs +1 */
strcpy(s, "hello"); /* writes the '\0' past end */
free(s);
return 0;
}تحقق سريع
حدّد ما الذي يبلّغ عنه memcheck بالنسبة إلى المقطع البرمجي.
مراجعة
يمكنك الآن اكتشاف أخطاء الوصول غير الصالح:
- تظهر عمليات القراءة والكتابة خارج الحدود على شكل Invalid read/write مع إزاحة الكتلة
- يُبلّغ عن القيم غير المُهيّأة عندما تؤثر في قرار أو ناتج
- يُكتشف استخدام الذاكرة بعد تحريرها والتحرير المزدوج مع موقعي الاستدعاء كليهما
- يحدّد
--track-origins=yesمواضع القيم غير المعرّفة؛ واستخدمه مع ASan لاكتشاف أخطاء المكدس
التالي: قراءة التقرير الكامل.
الأسئلة الشائعة
هل درس «الوصول غير الصالح» مجاني؟
نعم — نص درس «الوصول غير الصالح» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.
ماذا ستتعلم في «الوصول غير الصالح»؟
الوصول خارج الحدود والبيانات غير المهيّأة تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟
لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «الوصول غير الصالح»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟
نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- لماذا Valgrind
- اكتشاف التسربات
- الوصول غير الصالح
- قراءة التقارير