سؤال

أحتاج إلى بعض المساعدة في هذا الأمر، لأنه يحيرني في برنامج C الخاص بي

لدي سلسلتين (القاعدة والمسار)

BASE: /home/steve/cps730
PATH: /page2.html

هذه هي الطريقة التي يقرأ بها printf قبل أن أتصل بـ sprintf لضم محتواه معًا.هنا كتلة التعليمات البرمجية

        int memory_alloc = strlen(filepath)+1;
        memory_alloc += strlen(BASE_DIR)+1;
        printf("\n\nAlloc: %d",memory_alloc);
        char *input = (char*)malloc(memory_alloc+9000);
        printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
        sprintf(input, "%s%s",BASE_DIR,filepath); //   :(

        printf("\n\nPATH: %s\n\n",input);

الآن، هل يمكنك شرح كيفية إرجاع بيان printf النهائي

PATH: e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev

لأنه لا يفهمها على الإطلاق.

** أضفت 9000 في بيان malloc لمنع البرنامج من التعطل (نظرًا لأن حجم السلسلة أكبر من 31 بايت بشكل واضح).

الإخراج الكامل

Alloc: 31

BASE: /home/steve/cps730
PATH: /page2.html



PATH: /home/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev

Sending: 
HTTP/1.0 404 Not Found
Date: Sat, 12 Sep 2009 19:01:53 GMT
Connection: close

تحرير...................جميع التعليمات البرمجية التي تستخدم هذه المتغيرات

const char *BASE_DIR = "/home/steve/cps730";
 char* handleHeader(char *header){
    //Method given by browser (will only take GET, POST, and HEAD)
    char *method;
    method = (char*)malloc(strlen(header)+1);
    strcpy(method,header);
    method = strtok(method," ");

    if(!strcmp(method,"GET")){
        char *path = strtok(NULL," ");
        if(!strcmp(path,"/")){
            path = (char*)malloc(strlen(BASE_DIR)+1+12);
            strcpy(path,"/index.html");
        }
        free(method);
        return readPage(path);
    }
    else if(!strcmp(method,"POST")){

    }
    else if(!strcmp(method,"HEAD")){

    }
    else{
        strcat(contents,"HTTP/1.1 501 Not Implemented\n");
                strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
                strcat(contents, "Connection: close\n\n");
    }
    free(method);

}

//Return the contents of an HTML file
char* readPage(char* filepath){
    int memory_alloc = strlen(filepath)+1;
    memory_alloc += strlen(BASE_DIR)+1;
    printf("\n\nAlloc: %d",memory_alloc);
    char *input = (char*)malloc(memory_alloc+9000); 
    printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
    sprintf(input, "%s%s\0",BASE_DIR,filepath);

    printf("\n\nPATH: %s\n\n",input);

    FILE *file;
    file = fopen(input, "r");
    char temp[255];
    strcat(contents,"");

    if(file){
        strcat(contents, "HTTP/1.1 200 OK\n");
                strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
                strcat(contents, "Content-Type: text/html; charset=utf-8\n");
                strcat(contents, "Connection: close\n\n");

        //Read the requested file line by line
        while(fgets(temp, 255, file)!=NULL) { 
            strcat(contents, temp);         
        }
    }
    else{
        strcat(contents, "HTTP/1.0 404 Not Found\n");
                strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
                strcat(contents, "Connection: close\n\n");
    }

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

المحلول

واستدعاء readPage مع path مؤشر غير صالحة - يشير إلى الذاكرة المخصصة سابقا مع مؤشر method، الذي يتم تحرير الحق قبل استدعاء readPage. وmalloc المقبل يمكن إعادة استخدام هذه الذاكرة ثم أي شيء يمكن أن يحدث ...

نصائح أخرى

حسنا، من الواضح أن هذا لا يمكن أن يحدث: -)

وتخميني هو أن كومة الخاص بك فظيعة تالفة بالفعل.

وأود أن ننظر في القيم مؤشر الفعلية التي يستخدمها أسم دليل، ومدخلات وقاعدة. وأتساءل عما إذا ستجد أن المدخلات قريب جدا من أسم دليل؟

وأود أن ننظر أيضا في كيفية أسم دليل، قاعدة الخ تم إنشاؤها أصلا، هل يمكن أن يكون منطقة عازلة أكثر من التي تديرها هناك؟

وحاول هذا الرمز:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    const char* BASE_DIR = "/home/steve/cps730";
    const char* filepath = "/page2.html";
    int memory_alloc = strlen(filepath);
    memory_alloc += strlen(BASE_DIR)+1;
    printf("\n\nAlloc: %d",memory_alloc);
    char *input = (char*)malloc(memory_alloc);
    printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
    sprintf(input, "%s%s",BASE_DIR,filepath); //   :(

    printf("\n\nPATH: %s\n\n",input);

    return 0;
}

إذا هذا لم يكن لديك مشكلة، وبعد ذلك يجب أن يكون هناك شيء خاطئ في أي مكان آخر في التعليمات البرمجية. هذه هي الطريقة سلوك غير معرف في بعض الأحيان قد يعبر عن نفسه (لخبطة كيف كود علاقة يعمل).

و(راجع للشغل، لم أكن إضافة +1 على كل المكالمات strlen، منذ سلسلة متسلسلة لا يزال مستمرا لديها واحدة فقط خالية فاصل).

وبما أن قيمة BASE_DIR يعيد نفسه، إما BASE_DIR أو filepath ربما تداخل في الذاكرة input.

تأكد من كلا BASE_DIR وfilepath الذاكرة حقا خصصت.

وA المحاولة الأولى هو جعل مجرد نسخة محلية من BASE_DIR وfilepath قبل استدعاء sprintf.

وAAAH - من التشويق والمطاردة إلى مسألة نقرأ بينما نحاول حل المشكلة

والقانون الحالي يشبه:

const char *BASE_DIR = "/home/steve/cps730";

//Handles the header sent by the browser
char* handleHeader(char *header){
    //Method given by browser (will only take GET, POST, and HEAD)
    char *method;
    method = (char*)malloc(strlen(header)+1);
    strcpy(method,header);
    method = strtok(method," ");

    if(!strcmp(method,"GET")){
        char *path = strtok(NULL," ");
        if(!strcmp(path,"/")){
                path = (char*)malloc(strlen(BASE_DIR)+1+12);
                strcpy(path,"/index.html");
        }
        free(method);
        return readPage(path);
    }
    ...

والسؤال: إذا كان هذا يعمل في خادم الويب، هل هو آمن أن يكون باستخدام وظيفة strtok() الخيط غير آمنة؟ انا ذاهب الى تحمل "نعم، وأنها آمنة، على الرغم من أنني لست مقتنعا تماما. هل طباعة سلسلة header؟ هل المطبوعة قيمة path؟ هل حقا تنوي تسرب path المخصصة؟ هل ندرك أن تسلسل malloc() + strcpy() لا ينسخ BASE_DIR إلى path؟


والنسخة الأصلية من قانون انتهى:

 printf("\n\nPATH: %s\n\n", filepath);

ومن هنا جاءت إجابة جزئية اقترح الأصلي:

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

وأن تنسق في input. يمكنك طباعة من filepath؟


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

وأنا كما ذكر في تعليق التي قد تحتاج تصور لضمان أعلن أن malloc() وتحقق قيمة الإرجاع من ذلك. و"(char *)" يلقي ليس إلزاميا في C (وهو في C ++)، ويفضل كثير من عدم إدراج يلقي إذا كان رمز بدقة C وليس باللغتين C و C ++.


وهذا الرمز يعمل بالنسبة لي:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    const char *BASE_DIR = "/home/steve/cps730";
    const char *filepath = "/page2.html";

    int memory_alloc = strlen(filepath) + 1;
    memory_alloc += strlen(BASE_DIR) + 1;
    printf("\n\nAlloc: %d", memory_alloc);
    char *input = (char*)malloc(memory_alloc + 9000);
    printf("\n\nBASE: %s\nPATH: %s\n\n", BASE_DIR, filepath);
    sprintf(input, "%s%s", BASE_DIR, filepath);

    printf("\n\nPATH: %s\n\n", filepath);
    printf("\n\nPATH: %s\n\n", input);

    return(0);
}

ووتنتج خطوط فارغة غريبة بالإضافة إلى:

Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html

أسهل طريقة لمعرفة ما يحدث هي تتبع التنفيذ في مصحح الأخطاء (ربما إسقاط تتبع رمز التجميع).

بعض التخمينات حول ما قد يحدث:

  • تلف الذاكرة بواسطة مؤشر ترابط آخر (يبدو غير مرجح إذا كان هذا قابلاً للتكرار بسهولة)
  • الكومة الفاسدة (يبدو أيضًا غير مرجح، حيث تقوم بتفريغ سلسلتي المكون بعد ملف malloc() يتصل)
  • كما ذكر جوناثان ليفلر في أحد التعليقات، قد تفتقد رأسًا (ربما stdio.h) ويقوم المترجم بإنشاء تسلسل تنظيف الاستدعاء/المكدس غير الصحيح لـ printf/sprintf المكالمات.أتوقع أنك سترى بعض التحذيرات الخاصة بوقت الترجمة إذا كان هذا هو الحال - تلك التي يجب أن تأخذها في الاعتبار.

ما المترجم/الهدف الذي تستخدمه؟

لقيام بذلك بشكل صحيح، فما استقاموا لكم فاستقيموا تغيير رمز إلى:

/* CHANGED: allocate additional space for "index.html" */
method = (char*)malloc(strlen(header)+1+10);
strcpy(method,header);
method = strtok(method," ");

if(!strcmp(method,"GET")){
    char *path = strtok(NULL," ");
    if(!strcmp(path,"/")){
             /* CHANGED: don't allocate new memory, use previously allocated */
             strcpy(path,"/index.html");
    }
    /* CHANGED: call function first and free memory _after_ the call */
    char *result = readPage(path);
    free(method);
    return result;
}

اقتراحات


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

  1. malloc(3) عائدات void * لذلك لا ينبغي أن يكون من الضروري أن يلقيها.إذا تلقيت تحذيرًا، فهذا يعني على الأرجح أنك لم تقم بتضمينه <stdlib.h>.إذا لم تكن كذلك، يجب عليك.(على سبيل المثال، على نظام 64 بت، وليس النماذج الأولية malloc(3) يمكن أن تكون خطيرة للغاية.بعض بيئات 64 بت لا تدعم حقًا K&R C.:-)
  2. عند الحديث عن التحذيرات، يرجى التأكد من تشغيلها جميعًا.مع gcc يمكنك تشغيل معظمها باستخدام -Wall.
  3. أنت لا تتحقق من قيمة الإرجاع لـ malloc(3) لخطأ.
  4. استخدم مصحح أخطاء الذاكرة يحب سياج مكهرب.هناك العديد من الخيارات، انظر الرابط الخاص بي.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top