سؤال

كان ذهني يتجول اليوم حول موضوع المؤشرات الوظيفية، وخرجت بالسيناريو التالي في رأسي:

__stdcall int function (int)
{
    return 0;
}

int main()
{
    (*(int(*)(char*,char*))function)("thought", "experiment");
    return 0;
}

AFAIK قد يؤدي هذا الرمز إلى إتلاف المكدس، فما هي أنواع المشكلات التي يمكن أن أبحث عنها إذا قمت بتشغيل هذا الرمز؟

سأقوم بهذا التحقيق بنفسي ولكنني بعيد عن جهاز التطوير الخاص بي لمدة أسبوع.

يحرر:انتظر لحظة، لقد كنت أفكر أكثر قليلاً.كما لوحظ في التعليقات، كان القصد من هذا الرمز هو ترك معلمة على المكدس عندما يتم قول كل شيء وفعله (يضع المتصل معلمتين على المكدس، ويستدعى callee - متوقعًا معلمة واحدة فقط - ينبثق واحدًا فقط ).ومع ذلك، نظرًا لأن طاقم الممثلين الخاص بي لا يذكر اتفاقية الاتصال، فهل أقوم بتجاهل stdcall، على الأقل من وجهة نظر المتصل؟ وظيفة كثافة العمليات (كثافة العمليات) سيظل ينبثق معلمة من المكدس، ولكن هل يعود المتصل إلى التفكير في أن الوظيفة هي __cdecl (الافتراضي) بسبب الإرسال؟(أي.ثلاثة إجمالي البارامترات برزت؟)

تحرير 2:الجواب على هذا السؤال الثاني، كما أكد روب، هو نعم.سأضطر إلى إعادة صياغة __stdcall إذا أردت ترك معلمة على المكدس:

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment");
هل كانت مفيدة؟

المحلول

أنت تقوم باستدعاء الوظيفة كما لو كانت _cdecl مما يعني أن المتصل يدفع الوسائط وينظف المكدس.

وظيفة الاستلام هي _stdcall مما يعني أن المستدعى يقوم بتنظيف المكدس.يتوقع المستدعى وسيطة واحدة لذلك سيتم إخراج 4 بايت من المكدس.

عندما تعود الدالة، سيخرج المتصل مؤشرين (بعد أن قام بالضغط مسبقًا على مؤشرين)، لذلك يتم إتلاف مكدسك بمقدار 4 بايت.

تستخدم كلا اتفاقيات الاتصال نفس آلية الإرجاع، ولها نفس قواعد التسجيل (لا يتم الاحتفاظ بـ eax وecx وedx).يرى ويكيبيديا لمزيد من التفاصيل.

اعتمادًا على تخطيط إطار المكدس والمحاذاة، قد يتسبب عدم التطابق هذا في عدد من التأثيرات.إذا كنت محظوظا فإنك تفلت من العقاب.إذا لم يكن الأمر كذلك، فقد تفسد عنوان المرسل لوظيفتك الرئيسية، مما يتسبب في تعطل البرنامج عندما يتفرع إلى "من يعرف أين".إذا قام المترجم بإدخال نوع من حماية المكدس للقبض على الفساد، فمن المرجح أن يكتشف ذلك ويجهض البرنامج.

نصائح أخرى

لا، بالتأكيد لن يسبب شاشة زرقاء.لا توجد عملية في وضع المستخدم قادرة على القيام بذلك.حتى لو كان هذا الخطأ في كود وضع kernel، فإن شاشة الموت الزرقاء لن تحدث إلا بعد الوصول إلى ذاكرة غير صالحة أو تمرير وسائط خاطئة إلى إحدى الوظائف.

أنت ببساطة تقوم بإفساد الذاكرة الخاصة للعملية الخاصة بك، وقد يؤدي (أو لا) الفساد لاحقًا إلى عملية غير صالحة (على سبيل المثال.إلغاء الإشارة إلى مؤشر يشير إلى ذاكرة غير صالحة).عندما يحدث هذا، يقوم نظام التشغيل بإنهاء العملية الخاصة بك، ولكن ليس قبل ذلك.

أعتقد أنه سيكون لديك "سلوك غير محدد" في هذه الحالة.

من معيار ج:(أفترض أنه هو نفسه في C++)

768 إذا تم استخدام مؤشر تم تحويله لاستدعاء وظيفة لا يكون نوعها متوافقًا مع النوع المدبب ، فإن السلوك غير محدد.

يحرر:في معظم أنظمة التشغيل، لن يتسبب هذا النوع من الأخطاء في حدوث مشكلات في نظام التشغيل بأكمله.ولكنه قد يسبب مشاكل غير محددة في برنامجك.سيكون من الصعب جدًا أن يتمكن برنامج وضع المستخدم من التسبب في ظهور شاشة زرقاء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top