متغير غير مهيأ
في مجال الحوسبة ، المتغير غير المُهيأ هو متغير تم تعريفه ولكن لم يتم تعيين قيمة محددة له قبل استخدامه. سيكون له قيمة ما ، ولكنها غير قابلة للتنبؤ. ولذلك، يُعد هذا خطأً برمجياً ومصدراً شائعاً للأخطاء في البرامج.
مثال على لغة C
من الافتراضات الشائعة لدى المبرمجين المبتدئين أن جميع المتغيرات تُعيّن لها قيمة معروفة، مثل الصفر، عند تعريفها. مع أن هذا صحيح في العديد من لغات البرمجة، إلا أنه ليس صحيحًا في جميعها، مما يُعرّضها لخطر الخطأ. تستخدم لغات مثل C مساحة المكدس للمتغيرات، وتُعرف مجموعة المتغيرات المُخصصة لروتين فرعي باسم إطار المكدس . وبينما يُخصّص الحاسوب المساحة المناسبة لإطار المكدس، فإنه عادةً ما يفعل ذلك ببساطة عن طريق تعديل قيمة مؤشر المكدس ، دون تغيير حالة الذاكرة نفسها (عادةً لأسباب تتعلق بالكفاءة). لذلك، ستظهر محتويات تلك الذاكرة في ذلك الوقت كقيم ابتدائية للمتغيرات التي تشغل تلك العناوين.
إليك مثال بسيط بلغة C:
دالة العد ( void ) { int k ; for ( int i = 0 ; i < 10 ; i ++ ) { k = k + 1 ; } printf ( "%d" , k ); }القيمة النهائية للمتغير kغير مُعرَّفة. يفترض الجواب بأن قيمته يجب أن تكون 10 أنه بدأ من الصفر، وهو ما قد يكون صحيحًا أو خاطئًا. لاحظ أنه في المثال، iتم تهيئة المتغير إلى الصفر في الجزء الأول من forالعبارة.
مثال آخر على ذلك هو التعامل مع الهياكل . في مقتطف الشفرة أدناه، لدينا هيكل struct studentيحتوي على بعض المتغيرات التي تصف معلومات عن طالب. registerStudentتُسرّب الدالة محتويات الذاكرة لأنها تفشل في تهيئة أعضاء الهيكل بالكامل struct Student newStudent. إذا دققنا النظر، سنجد أن المتغيرين `a` و`b` و` agec` مُهيّأة في البداية. لكن تهيئة المتغيرين ` a` و`b` غير صحيحة. والسبب هو أنه إذا كان طول مصفوفات الأحرف ` a` و` b` أقل من 16 بايت، فخلال عملية التهيئة ، [ 1 ] نفشل في تهيئة كامل مساحة الذاكرة المحجوزة لكل من هذين المتغيرين (16 بايت). وبالتالي، بعد تحويل الهيكل الناتج إلى الهيكل ، [ 2 ] نُسرّب بعض ذاكرة المكدس إلى الدالة المُستدعية.semesterstudentNumberfirstNamelastNamefirstNamelastNamestrcpymemcpy()output
#include <stdio.h> #include <string.h>typedef struct { char firstName [ 16 ]; char lastName [ 16 ]; unsigned int studentNumber ; unsigned int age ; unsigned int chapter ; float gpa ; } Student ;int registerStudent ( Student * output , int age , char * firstName , char * lastName ) { // إذا كان أي من هذه المؤشرات يساوي NULL، فأرجع -1. if ( ! output || ! first_name || ! last_name ) { fprintf ( stderr , "خطأ! أحد المعاملات يساوي NULL. \n " ); return -1 ; }// نتأكد من أن طول السلاسل النصية أقل من 16 بايت (بما في ذلك البايت الفارغ) // لتجنب تجاوز السعة إذا كان ( طول ( الاسم الأول ) > 15 || طول ( الاسم الأخير ) > 15 ) { fprintf ( stderr , "لا يمكن أن يتجاوز طول الاسم الأول والاسم الأخير 16 حرفًا! \n " ); return -1 ; }// تهيئة أعضاء المتغير Student newStudent { . student_number = getNewStudentNumber () . age = age ; . chapter = 1 ; . gpa = 4.0f ; } strcpy ( newStudent . firstName , firstName ); strcpy ( newStudent . lastName , lastName );// نسخ النتيجة إلى ملف الإخراج memcpy ( output , & newStudent , sizeof ( Student )); return 0 ; }على أي حال، حتى عندما تُهيأ متغيرة ضمنيًا بقيمة افتراضية مثل 0، فإن هذه القيمة عادةً لا تكون صحيحة . فالتهيئة لا تعني بالضرورة صحة القيمة إذا كانت افتراضية. (مع ذلك، تُعد التهيئة الافتراضية إلى NULL (أو NULL nullptrمنذ C23 أو NULL في C++ ) ممارسةً سليمةً للمؤشرات ومصفوفات المؤشرات، لأنها تجعلها غير صالحة قبل تهيئتها فعليًا بقيمتها الصحيحة). في لغة C، تُهيأ المتغيرات ذات مدة التخزين الثابتة التي لم تُهيأ صراحةً إلى الصفر (أو NULL NULLللمؤشرات). [ 3 ]
لا تقتصر مشكلة المتغيرات غير المُهيأة على كونها سببًا شائعًا للأخطاء البرمجية، بل إن هذا النوع من الأخطاء خطيرٌ للغاية لأنه قد لا يكون قابلاً للتكرار؛ فعلى سبيل المثال، قد يبقى المتغير غير مُهيأ في جزءٍ مُحدد من البرنامج فقط. وفي بعض الحالات، قد تجتاز البرامج التي تحتوي على متغيرات غير مُهيأة اختبارات البرمجيات بنجاح .
التأثيرات
تُعدّ المتغيرات غير المُهيأة ثغرات خطيرة، إذ يُمكن استغلالها لتسريب بيانات عشوائية من الذاكرة، أو للكتابة فوق بيانات أخرى، أو لتنفيذ تعليمات برمجية إضافية، وذلك بحسب الحالة. عند استغلال برنامج يستخدم تقنية عشوائية تخطيط مساحة العناوين (ASLR)، غالبًا ما يكون من الضروري معرفة عنوان البرنامج الأساسي في الذاكرة. يُمكن استغلال متغير غير مُهيأ بطريقة تُجبر البرنامج على تسريب مؤشر من مساحة عناوينه لتجاوز تقنية ASLR.
الاستخدام في اللغات
تُعدّ المتغيرات غير المُهيأة مشكلةً خاصةً في لغات البرمجة مثل لغة التجميع ، ولغة C، ولغة C++ ، المصممة لبرمجة الأنظمة . وقد اعتمد تطوير هذه اللغات على فلسفة تصميمٍ تُرجّح كفة الأداء على السلامة. وكان على المبرمج مسؤولية الانتباه إلى المشكلات الخطيرة، كالمتغيرات غير المُهيأة.
في لغات البرمجة الأخرى، تُهيأ المتغيرات عادةً بقيم معروفة عند إنشائها. ومن الأمثلة على ذلك:
- تُهيئ لغة VHDL جميع المتغيرات القياسية بقيمة خاصة 'U'. يُستخدم هذا في المحاكاة، ولأغراض تصحيح الأخطاء، ولإعلام المستخدم متى تؤثر القيم الأولية غير المهمة ، من خلال منطق متعدد القيم ، على المخرجات.
- لا تحتوي لغة جافا على متغيرات غير مهيأة. تُهيأ حقول الفئات والكائنات التي لا تحتوي على مُهيئ صريح، وعناصر المصفوفات، تلقائيًا بالقيمة الافتراضية لنوعها ( لجميع
falseالأنواع العددية، ولجميع أنواع المراجع). [ 4 ] يجب إسناد قيم للمتغيرات المحلية في جافا بشكل قاطع قبل الوصول إليها، وإلا سيحدث خطأ أثناء الترجمة.boolean0null - يقوم بايثون بتهيئة المتغيرات المحلية إلى
NULL(مختلفة عنNone) ويرفع استثناءًUnboundLocalErrorعند الوصول إلى مثل هذا المتغير قبل إعادة تهيئته إلى قيمة صالحة. - يقوم D بتهيئة جميع المتغيرات ما لم يحدد المبرمج صراحةً عدم القيام بذلك.
حتى في اللغات التي تسمح باستخدام المتغيرات غير المُهيأة، تحاول العديد من المترجمات تحديد استخدام هذه المتغيرات والإبلاغ عنها كأخطاء أثناء الترجمة . تُسهّل بعض اللغات هذه المهمة من خلال توفير بنيات للتعامل مع حالة تهيئة المتغيرات؛ على سبيل المثال، تتميز لغة C# بنوع خاص من المعاملات المُستدعاة بالمرجع للروتينات الفرعية (يُشار إليها بـ `const` بدلاً من `const` )، مما يُؤكد أنه يُسمح للمتغير بأن يكون غير مُهيأ عند الدخول، ولكنه سيُهيأ لاحقًا.outref
انظر أيضاً
مراجع
- ↑ strcpy
- ↑ memcpy()
- ↑ "ISO/IEC 9899:TC3 (المعيار الحالي C)" (ملف PDF) . 7 سبتمبر 2007. صفحة 126. تاريخ الاطلاع: 26 سبتمبر 2008 .القسم 6.7.8، الفقرة 10.
- ↑ "مواصفات لغة جافا: 4.12.5 القيم الأولية للمتغيرات" . صن مايكروسيستمز . تم الاطلاع عليه بتاريخ 18-10-2008 .
للمزيد من القراءة
- أخطاء برمجية
- متغير (علوم الحاسوب)
