سؤال

لدي خطأ غريب في برنامجي، ويبدو لي أن malloc() يسبب SIGSEGV، والذي حسب فهمي ليس له أي معنى.أنا أستخدم مكتبة تسمى simclist للقوائم الديناميكية.

إليك البنية التي سيتم الرجوع إليها لاحقًا:

typedef struct {
    int msgid;
    int status;
    void* udata;
    list_t queue;
} msg_t;

وهنا هو الكود:

msg_t* msg = (msg_t*) malloc( sizeof( msg_t ) );

msg->msgid = msgid;
msg->status = MSG_STAT_NEW;
msg->udata = udata;
list_init( &msg->queue );

list_init هو المكان الذي يفشل فيه البرنامج، إليك رمز list_init:

/* list initialization */
int list_init(list_t *restrict l) {
    if (l == NULL) return -1;

    srandom((unsigned long)time(NULL));

    l->numels = 0;

    /* head/tail sentinels and mid pointer */
    l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->head_sentinel->next = l->tail_sentinel;
    l->tail_sentinel->prev = l->head_sentinel;
    l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
    l->head_sentinel->data = l->tail_sentinel->data = NULL;

    /* iteration attributes */
    l->iter_active = 0;
    l->iter_pos = 0;
    l->iter_curentry = NULL;

    /* free-list attributes */
    l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
    l->spareelsnum = 0;

#ifdef SIMCLIST_WITH_THREADS
    l->threadcount = 0;
#endif

    list_attributes_setdefaults(l);

    assert(list_repOk(l));
    assert(list_attrOk(l));

    return 0;
}

الخط l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * هو المكان الذي يحدث فيه SIGSEGV وفقًا لتتبع المكدس.أنا أستخدم gdb/nemiver لتصحيح الأخطاء ولكني في حيرة من أمري.في المرة الأولى التي يتم فيها استدعاء هذه الوظيفة تعمل بشكل جيد ولكنها تفشل دائمًا في المرة الثانية.كيف يمكن أن يتسبب malloc() في SIGSEGV؟

هذا هو تتبع المكدس:

#0  ?? () at :0
#1  malloc () at :0
#2  list_init (l=0x104f290) at src/simclist.c:205
#3  msg_new (msg_switch=0x1050dc0, msgid=8, udata=0x0) at src/msg_switch.c:218
#4  exread (sockfd=8, conn_info=0x104e0e0) at src/zimr-proxy/main.c:504
#5  zfd_select (tv_sec=0) at src/zfildes.c:124
#6  main (argc=3, argv=0x7fffcabe44f8) at src/zimr-proxy/main.c:210

أي مساعدة أو البصيرة هو موضع تقدير كبير!

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

المحلول

وmalloc يمكن segfault على سبيل المثال عند تلف الكومة. تأكد من أنك لا تكتب أي شيء يتجاوز حدود أي تخصيص السابق.

نصائح أخرى

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

وتحرير: أداة أخرى مفيدة هي href="http://en.wikipedia.org/wiki/Electric_Fence" سياج كهربائي . كما يوفر سي العمومية لل MALLOC_CHECK_ المتغير البيئي للمساعدة في مشاكل في الذاكرة التصحيح. هاتين الطريقتين لا تؤثر سرعة تشغيل بقدر valgrind.

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

إذا بنيات البيانات الداخلية المستخدمة بواسطة malloc من تلف بهذه الطريقة، malloc يستخدم بيانات غير صالحة، وربما تحطم الطائرة.

هناك طرق لا تعد ولا تحصى لإثارة التفريغ الأساسي من malloc()realloc() و calloc()).وتشمل هذه:

  • تجاوز سعة المخزن المؤقت:الكتابة بعد نهاية المساحة المخصصة (تدوس معلومات التحكم التي malloc() كان يبقي هناك).
  • تجاوز سعة المخزن المؤقت:الكتابة قبل بدء المساحة المخصصة (تدوس معلومات التحكم التي malloc() كان يبقي هناك).
  • تحرير الذاكرة التي لم يتم تخصيصها من قبل malloc().في برنامج مختلط C وC++، قد يتضمن ذلك تحرير الذاكرة المخصصة في C++ بواسطة new.
  • تحرير مؤشر يشير جزئيًا إلى كتلة الذاكرة المخصصة بواسطة malloc() - وهي حالة خاصة بالحالة السابقة .
  • تحرير المؤشر الذي تم تحريره بالفعل - "المجاني المزدوج" سيئ السمعة.

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

وعليك أن تحاول تصحيح هذا الرمز في العزلة، لمعرفة ما إذا كان موجودا مشكلة فعلا حيث يتم إنشاء segfault. (وأظن أنه ليس).

وهذا يعني:

و# 1: ترجمة التعليمات البرمجية مع -O0، للتأكد من أن جدب يحصل على معلومات صحيحة ترقيم خط

و# 2: اكتب وحدة الاختبار الذي يدعو هذا الجزء من قانون

.

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

وعن طريق Valgrind، والبعض الآخر قد اقترح، هو أيضا فكرة جيدة للغاية.

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

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