سؤال

أنا أكتب خفيًا عالي التحميل يجب تشغيله على FreeBSD 8.0 وعلى Linux أيضًا. الغرض الرئيسي من Daemon هو تمرير الملفات التي يطلبها معرفها. يتم تحويل المعرف إلى اسم الملف/حجم الملف المحلي عبر طلب إلى DB. ثم أستخدم التسلسل mmap() مكالمات لتمرير كتل الملفات مع send().

ومع ذلك ، يوجد في بعض الأحيان عدم تطابق الملفات في DB وملفات على نظام الملفات (RealSize <size in db). في هذه الحالة ، أرسلت جميع كتل البيانات الحقيقية ، وعندما يتم تعيين كتلة البيانات التالية - لا تُرجع MMAP أي أخطاء ، وعنوان معتاد فقط (لقد قمت بفحص متغير Errno أيضًا ، فإنه يساوي الصفر بعد MMAP). وعندما يحاول Daemon إرسال هذه الكتلة ، فإنه يحصل على خطأ تجزئة. (يتم إصدار هذا السلوك بشكل غير ذلك على FreeBSD 8.0 AMD64)

كنت أستخدم فحصًا آمنًا قبل فتحه لضمان الحجم مع stat() يتصل. ومع ذلك ، فإن الحياة الحقيقية تُظهر لي أن Segfault لا يزال يمكن رفعه في مواقف نادرة.

لذا ، سؤالي هل هناك طريقة للتحقق مما إذا كان المؤشر متاحًا قبل إخلاءه؟ عندما فتحت Core في GDB ، يقول GDB أن العنوان المعطى خارج الملزمة. ربما هناك حل آخر يمكن أن يقترحه شخص ما.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define FILENAME        "./datafile"

int main()
{
    unsigned long i, j;

    srand(time(NULL));
    unsigned long pagesize = sysconf(_SC_PAGESIZE);

    unsigned long basesize = 4 * pagesize;
    unsigned long cropsize = 2 * pagesize;

    // create 4*pagesize sized file
    int f = creat(FILENAME, 0644);
    for (i = 0; i < basesize; i++) {
        unsigned char c = (unsigned char)rand();
        if (write(f, &c, 1) < 1) { perror("write"); break; }
    }
    close(f);

    f = open(FILENAME, O_RDONLY);

    // walk trough file
    unsigned char xor = 0;
    unsigned long offset = 0;
    for (j = 0; j < 4; j++) {
        // trunc file to 2*pagesize
        if (j == 2) truncate(FILENAME, cropsize);

        char *data = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE, f, offset);
        if (data == MAP_FAILED) { perror("mmap"); break; }
        printf("mmap: %lu@%lu for %i\n", pagesize, offset, f);

        for (i = 0; i < pagesize; i++) xor ^= data[i];

        offset += pagesize;
    }

    close(f);

    return 0;
}
هل كانت مفيدة؟

المحلول

بالطبع لا يمكنني إثبات ذلك من هنا ، لكنني أظن بشدة أن لديك فقط خطأ في حفظ الدفاتر في التعليمات البرمجية الخاصة بك. إذا قمت بالاتصال بـ MMAP ومرت بحجم ، ونجحت ، يجب ألا تحصل على SIGSEGV.

أوصي بتقديم تطبيق Valgrind على التحقيق الخاص بك.

في العديد من أنظمة Linux/Proc/PID/خرائط ستظهر لك المناطق التي يتم تعيينها مع أذونات الوصول.

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