سؤال

أعلم أنه من الممكن أن تتفوق على الكود العادي:

سلسلة char [9] ؛

Scanf ("٪ s" ، سلسلة).

ولكن هل من الممكن أن تتفوق على Scanf ("٪ 8s" ، سلسلة)؟ 8 مجرد مثال.

أعلم أن "٪ 8s" يعمل مثل المحدد ، لكنني لاحظت أيضًا عندما أقوم بإدخال سلسلة أطول من 8 chars ، سينتهي البرنامج بسبب:

* مكدس تحطيم المكتشف *: ./A.out إنهاء

======= Backtrace: ==========

...

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

على عكس التدفق العادي الذي يتجول في المخططات SCANF ("٪ S") ، إذا كان SCANF ("٪ 8s") يمكن أن يفيض ، فسيتم تدفقه في وظيفة ScanF بحيث يتم الحصول على التحكم في ScanF.

لكن ScanF عبارة عن syscall تتطلب تبديل الوضع (التبديل من وضع المستخدم إلى وضع kernel) ، وداعيًا سوف يتصل بأشياء مثل القراءة إلى stdin وما إلى ذلك. لذا لست متأكدًا مما إذا كان بإمكاننا التمر في وضع kernel أو شيء من هذا القبيل ..

التعليقات مرحب بها !!

تحديث >>

يفترض سلسلة Char [9] في المثال أعلاه. سلسلة char [8] في التالية الكود الحقيقي.

السؤال يتعلق حقًا بالقصة المتضاربة بين Safe ScanF ("٪ 8s") وإجهاض GCC بسبب تحطيم المكدس.

رمز مبسط:

void foo(pass some pointer) {
char input[8];
int input_number = 0;

while (1) { // looping console
   printf some info;
   scanf("%8s", input);

   input_number = atoi(input);

   if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) {
       input_number = -1;
   }
   switch (input_number) {
       case -1: to quit the console if input = 'q';
       default: to print info that pointer refers to;
       ...
   } 

}

}

ملحوظة:

  1. يسمى فو شخص آخر.
  2. على الرغم من أن السلسلة هي 8 بايت في رمز حقيقي مع "٪ 8s" ، لا أعتقد أن هذا يؤدي إلى تحطيم.
هل كانت مفيدة؟

المحلول

نرى http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html:

يتكون كل توجيه من واحد مما يلي ... عدد صحيح اختياري غير صفري عشري يحدد الحد الأقصى لعرض الحقل.

س
يطابق سلسلة من البايتات التي ليست أحرف مساحة بيضاء. يجب أن يضمن التطبيق أن الوسيطة المقابلة هي مؤشر إلى البايت الأولي لمجموعة من char ، أو char الموقعة ، أو Char غير موقعة كبيرة بما يكفي لقبول التسلسل ورمز الحرف الفارغ ، والتي يجب إضافتها تلقائيًا.

لذلك لن يتفوق على المخزن المؤقت لسلسلة 9 بايت.

نصائح أخرى

لا أي وقت مضى استعمال scanf (أو fscanf لهذه المسألة) إذا كنت تريد أن تكون مدخلاتك قوية.

يجب أن تستخدم fgets (أو بالمثل "محمي من سعة المخزن المؤقت") ثم استخدم sscanf على ذلك.

المشكلة الرئيسية مع scanf و fscanf هل يمكن أن ينتهي مؤشر الملف الخاص بك في موضع غير محدد إذا لم يكن السطر من التنسيق المتوقع (أي ، إذا كان scanf فشل). مع ال fgets/sscanf الطريقة ، من الأسهل بكثير ضمان أنك على حدود خط ، دون الحاجة إلى استخدام ftell و fseek للتنقل حول الملف.

فيما يتعلق باستعلامك المحدد حول ما إذا كان المخزن المؤقت سوف يفيض ، فإن معيار C يقول هذا:

... يجب أن تكون الوسيطة المقابلة مؤشرًا للعنصر الأولي لمصفوفة الأحرف كبيرة بما يكفي لقبول التسلسل والطرف الفارغ ، والذي سيتم إضافته تلقائيًا.

لذلك ، ل "%8s" تنسيق ، تحتاج إلى مجموعة من 9 أحرف.

أظن أن لديك مشكلة أخرى في الكود الخاص بك. مع برنامج اختبار:

#include <stdio.h>
int main(int argc, char* argv[]) {
    char x1;
    char a[9];
    char x2;
    x1 = x2 = ' ';
    scanf ("%s",a);
    printf ("[%c] [%s] [%c]\n",x1,a,x2);
    return 0;
}

انا حصلت:

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[s] [dfjdhadgha...lghjdfgjhd] [ ]
  6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state
  (probably corrupted stack)
  Segmentation fault (core dumped)

عندما أقوم بتغيير هذا البرنامج نفسه لاستخدامه "%8s", ، أحصل على (لنفس المدخلات بالضبط):

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[ ] [dfjdhadg] [ ]

إذا تم تخصيص السلسلة بأقل من 8 مواثيق ، فمن المؤكد أنها ستحصل على المكتوبة ، فلن يقوم ScanF أيضًا بإلحاق المنهي الفارغ. ولكن طالما أن لديك مساحة كافية في السلسلة لقيمتك ، يجب ألا تحصل على صفة مفرطة.

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

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