سؤال

الفرق بين خطأ الناقل وخطأ التجزئة؟هل يمكن أن يحدث أن يعطي البرنامج خطأ seg ويتوقف للمرة الأولى وفي المرة الثانية قد يعطي خطأ في الحافلة ويخرج؟

هل كانت مفيدة؟

المحلول

في معظم البنيات التي استخدمتها، الفرق هو أن:

  • يحدث SEGV عندما تصل إلى الذاكرة التي لم يكن من المفترض أن تصل إليها (على سبيل المثال، خارج مساحة العنوان الخاصة بك).
  • يحدث SIGBUS بسبب مشكلات المحاذاة مع وحدة المعالجة المركزية (على سبيل المثال، محاولة قراءة طويلة من عنوان ليس من مضاعفات 4).

نصائح أخرى

كما سيتم رفع

وSIGBUS إذا كنت mmap() ملف ومحاولة للوصول إلى جزء من المخزن المؤقت المعين الذي يمتد بعد نهاية الملف، فضلا عن الظروف خطأ مثل من الفضاء. إذا قمت بتسجيل معالج الإشارات باستخدام sigaction() و لك وضع SA_SIGINFO، قد يكون من الممكن أن يكون البرنامج بفحص عنوان الذاكرة يخطأ والتعامل مع الذاكرة المعينة أخطاء الملف فقط.

وعلى سبيل المثال، قد يكون السبب خطأ في حافلة عندما يحاول البرنامج أن تفعل شيئا لا يدعم الحافلة الأجهزة. على SPARCs ، على سبيل المثال، في محاولة لقراءة قيمة متعددة البايت (مثل كثافة العمليات، 32 -bits) من عنوان غريب ولدت خطأ الحافلة.

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

وأفترض أنك نتحدث عن SIGSEGV وSIGBUS الإشارات التي يحددها POSIX.

ويحدث SIGSEGV عندما يحيل الى البرنامج عنوان غير صالح. SIGBUS هو خطأ الأجهزة المعرفة من قبل التنفيذ. الإجراء الافتراضي لهذه الإشارات اثنين هو إنهاء البرنامج.

وهذا البرنامج يمكن التقاط هذه الإشارات، وحتى تجاهلها.

تفسير سؤالك (ربما بشكل غير صحيح) بأنها تعني "أنا على الحصول بشكل متقطع SIGSEGV أو SIGBUS، لماذا أليس كذلك تتفق؟"، ومن الجدير بالذكر أن تفعل أشياء المراوغة مع مؤشرات غير مضمونة من قبل C أو المعايير C ++ أن يؤدي إلى segfault. انها مجرد "سلوك غير معرف"، التي كأستاذ كنت قد وضعت مرة واحدة فهذا يعني أنه بدلا من ذلك قد يسبب التماسيح للخروج من ألواح الأرضية وأكل لك.

وهكذا موقفك يمكن أن يكون لديك اثنين من البق، حيث أول من تحدث <م> أحيانا يسبب SIGSEGV، والثانية (إذا فإن segfault لن يحدث والبرنامج لا يزال قيد التشغيل) يسبب SIGBUS.

وأنصحك الخطوة من خلال مع مصحح، وابحث عن التماسيح.

وهذا من شأنه أن يكون الحزب الاتحادي الديمقراطي من ما هو الخطأ الحافلة؟ ، إذا كان لم يكن ل

<اقتباس فقرة>   

هل يمكن أن يحدث أن البرنامج يعطي خطأ SEG وتوقف للمرة الأولى وللمرة الثانية أنها قد تعطي خطأ الحافلات والخروج؟

والجزء من السؤال. يجب أن تكون قادرا على الإجابة على هذا لنفسك مع المعلومات الموجودة هنا.


<اقتباس فقرة>   

والجنون: تفعل الشيء نفسه مرارا وتكرارا وتتوقع نتائج مختلفة
  - ألبرت أينشتاين


وبطبيعة الحال، مع الأخذ في مسألة حرفيا ...

#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
    srand(time(NULL));
    if (rand() % 2)
        kill(getpid(), SIGBUS);
    else
        kill(getpid(), SIGSEGV);
    return 0;
}

وتادا، وهو البرنامج الذي يمكن الخروج مع خطأ تجزئة على تشغيل واحد والخروج مع خطأ الحافلة في ترشيح نفسه مرة اخرى.

<اقتباس فقرة>   

هل يمكن أن يحدث أن البرنامج يعطي خطأ SEG وتوقف للمرة الأولى وللمرة الثانية أنها قد تعطي خطأ الحافلات والخروج؟

ونعم، حتى واحد ونفس الأخطاء: هنا هو مثال خطير ولكن التبسيط من ماك التي يمكن أن تنتج على حد سواء، خطأ تجزئة (SIGSEGV) والخطأ حافلة (SIGBUS)، بواسطة فهارس خارج حدود صفيف، في طريقة حتمية. وصول محاذاتها المذكورة أعلاه ليست قضية مع ماك. (وهذا المثال لا يسبب أي SIGBUS، إذا كان يعمل داخل المصحح، lldb في حالتي!)

وbus_segv.c:

#include <stdlib.h>

char array[10];

int main(int argc, char *argv[]) {
    return array[atol(argv[1])];
}

والمثال يأخذ عدد صحيح من سطر الأوامر، والتي هي بمثابة مؤشر للمجموعة. في بعض القيم مؤشر (حتى خارج مجموعة) التي لن يسبب أي إشارة. (كل القيم المعطاة تعتمد على أحجام جزء / القسم القياسية. كنت رنة-902.0.39.1 لإنتاج ثنائي على ارتفاع سييرا ماك 10.13.5، i5-4288U CPU @ 2.60GHz).

وفهرس فوق 77791 وتحت -4128 سوف يؤدي إلى خطأ تجزئة (SIGSEGV). 24544 إلى حدوث خطأ الناقل (SIGBUS). هنا خريطة كاملة:

$ ./bus_segv -4129
Segmentation fault: 11
$ ./bus_segv -4128
...
$ ./bus_segv 24543
$ ./bus_segv 24544
Bus error: 10
...
$ ./bus_segv 28639
Bus error: 10
$ ./bus_segv 28640
...
$ ./bus_segv 45023
$ ./bus_segv 45024
Bus error: 10
...
$ ./bus_segv 53215
Bus error: 10
$ ./bus_segv 53216
...
$ ./bus_segv 69599
$ ./bus_segv 69600
Bus error: 10
...
$ ./bus_segv 73695
Bus error: 10
$ ./bus_segv 73696
...
$ ./bus_segv 77791
$ ./bus_segv 77792
Segmentation fault: 11

إذا نظرتم الى رمز تفكيكها، ترى أن حدود النطاقات مع أخطاء الحافلة ليست غريبة كما يظهر مؤشر:

و$ otool -tv bus_segv

bus_segv:
(__TEXT,__text) section
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp, %rbp
0000000100000f64    subq    $0x10, %rsp
0000000100000f68    movl    $0x0, -0x4(%rbp)
0000000100000f6f    movl    %edi, -0x8(%rbp)
0000000100000f72    movq    %rsi, -0x10(%rbp)
0000000100000f76    movq    -0x10(%rbp), %rsi
0000000100000f7a    movq    0x8(%rsi), %rdi
0000000100000f7e    callq   0x100000f94 ## symbol stub for: _atol
0000000100000f83    leaq    0x96(%rip), %rsi
0000000100000f8a    movsbl  (%rsi,%rax), %eax
0000000100000f8e    addq    $0x10, %rsp
0000000100000f92    popq    %rbp    
0000000100000f93    retq    

حسب leaq 0x96(%rip), %rsi، يصبح مؤشر القوة النسبية على (PC نسبيا عنوان تحديدها) من عنوان بداية المصفوفة:

rsi = 0x100000f8a + 0x96 = 0x100001020
rsi - 4128 = 0x100000000 (below segmentation fault)
rsi + 24544 = 0x100007000 (here and above bus error)
rsi + 28640 = 0x100008000 (below bus error)
rsi + 45024 = 0x10000c000 (here and above bus error)
rsi + 53216 = 0x10000e000 (below bus error)
rsi + 69600 = 0x100012000 (here and above bus error)
rsi + 73696 = 0x100013000 (below bus error)
rsi + 77792 = 0x100014000 (here and above segmentation fault)

وlldb ربما يضع العملية مع حدود صفحة مختلفة. لم أكن قادرا على إعادة إنتاج أي أخطاء حافلة في جلسة التصحيح. لذلك المصحح قد يكون حلا لثنائيات البصق الخطأ الحافلة.

وأندرياس

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