C腐败或双重免费,为什么?

时间:2012-10-06 06:23:10

标签: c memory-corruption

我有一个C代码(我编写的第一个C代码),并且有一个错误,但我不知道,在哪里。当我尝试释放一个变量(dinamically allocate,它的名字是out_html)时,我得到双重免费或腐败。我不知道为什么我的程序会这样做,我检查了所有免费电话等。

代码:

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

#include "fcntl.h"
#include "errno.h"

#include "sys/types.h"
#include "sys/stat.h"

#include "unistd.h"

#define MAX_SIZE 512

typedef struct node
{
    char* data;
    struct node * nextnode;
} node;

int max(int a, int b)
{
    if(a>b) return a;
    else return b;
}

node* push(node * stackTop, char* data)
{
    //static 
    node* newItem;

    newItem = calloc(sizeof(node),1);
    newItem->data = data;
    newItem->nextnode = stackTop;

    return newItem;
}

node* pop(node* stackTop)
{
    if(stackTop != NULL)
    {
        free(stackTop->data);
        node* P = stackTop;
        return stackTop->nextnode;
        free(P);
    }else return NULL;
}

int isMajorTag(char* tag)
{
    if(strcmp(tag, "<html>") == 0 || strcmp(tag, "</html>") == 0 ||
       strcmp(tag, "<body>") == 0 || strcmp(tag, "</body>") == 0 ||
       strcmp(tag, "<head>") == 0 || strcmp(tag, "</head>") == 0 ) { return 1; }
    else                         { return 0; };
}

int isHTMLtag(char* tag, char* tags)
{
    char* tag2;
    if(strstr(tag," ") != NULL)
    {
        char* strptr = strstr(tag, " ");
        int End = strptr - tag;
        char* tag_ = strndup(tag, End);
        tag2 = calloc((strlen(tag_) + strlen("*") + 2), sizeof(char));
        strcpy(tag2, tag_);
        strcat(tag2,"*");
        free(tag_); 
    } 
    else tag2 = tag;
    int ret;
    if(strstr(tags, tag2) != NULL){ ret =  1; }
    else                         { ret = 0; };
    if(tag2 != tag ) free(tag2); 
    return ret;
}

int isCloserTagOf(char* cltag, char* tag)
{
    int ret = 1;
    if( cltag[1] != '/' ) ret = 0;
    if( tag[1] == '/' ) ret = 0;
    char* ntag;
    char* ncltag;
    if(strstr(tag," ") != NULL)
    {
        char* strptr = strstr(tag, " ");
        int End = strptr - tag;
        ntag = strndup(tag, End) + 1;
        // ntag = calloc(strlen(ntag0) + 1 + 1, sizeof(char)); strcpy(ntag, ntag0); strcat(ntag, ">");
        ncltag = strndup(cltag+2,strlen(cltag) - 3);
    } else
    {
        ntag = tag + 1;
        ncltag = cltag + 2;
    }
//  printf("|%s|%s|  %i", ntag, ncltag, strcmp(ncltag, ntag));

    if(strcmp(ncltag, ntag) != 0) ret = 0;
    return ret;
}

int isIndividualTag(char* tag)
{
    if(strcmp(tag,"</br>") == 0) return 1;
    else if(strncmp(tag,"<!--#include file=",18) == 0) return 2;
    else if(strncmp(tag,"<!--#echo var=",14) == 0) return 3;
    else if(strncmp(tag,"<!--",4) == 0) return 4;
    else return 0;
}

int main(int argc,char *argv[])
{
    char* fname;
    if(argc == 2)
    {
        fname = argv[1];
    } else
    {
        printf("Give me a filename!");
        fname = calloc( MAX_SIZE, sizeof(char));
        scanf("%s", fname);
    };
    printf("Parameter: %s \n\n", fname);

// beolvasas
    int f = open(fname, O_RDONLY);
    long pos = lseek(f, 0, SEEK_END);
    lseek(f, 0, SEEK_SET);

    char *buff = calloc(pos,1);
    read(f, buff, pos);
    close(f);

    f = open("valid-tags", O_RDONLY);
    pos = lseek(f, 0, SEEK_END);
    lseek(f, 0, SEEK_SET);

    char *valids = calloc(pos,1);
    read(f, valids, pos);
    close(f);

//  printf("File: %s %s %i   ",buff, valids, isCloserTagOf("</html>","<html>")); printf("Igen? %i", isHTMLtag("</head>",valids));

    node* Stack = NULL;
    char *P = buff;
    int is_valid = 1;
    int bodyCnt = 0;
    char* body[6];
    int correct_body = 1;
    char* out_html = calloc(strlen(buff), sizeof(char));
    while(P[0] != '\0' )
    {
        if(P[0] == '<')
        {
            char* strptr = strstr(P, ">");
            if(strptr != NULL)
            {
                int nextCloser = strptr - P + 1;
                char* tag = strndup(P, nextCloser);
                int IsIndividual = isIndividualTag(tag);
                if(isHTMLtag(tag, valids) || IsIndividual)
                {
                    if(IsIndividual)
                    { 
                        if(IsIndividual == 2) // file inclusion
                        {
                            char* firstQ = strstr(tag, "\"");
                            char* secondQ;
                            if( firstQ ) secondQ = strstr(firstQ + 1, "\"");

                            if( firstQ && secondQ )
                            {
                                char* incl_filename = strndup((firstQ + 1), (secondQ - firstQ - 1));
                                f = open(incl_filename, O_RDONLY);
                                pos = lseek(f, 0, SEEK_END);
                                lseek(f, 0, SEEK_SET);
                                char *inclstr = calloc(pos,1);
                                read(f, inclstr, pos);
                                close(f);
                                char* new_out_html = calloc((max(strlen(buff),strlen(out_html)) + pos + 1 + 1 + 1), sizeof(char));
                                strcpy(new_out_html, out_html);
                                strcat(new_out_html, inclstr);
                                free(out_html); out_html = NULL; // free(inclstr);
                                out_html = new_out_html; 
                            } else
                            {   
                                printf("Invalid file inclusion! \n");
                                is_valid = 0; break;
                            };
                        } else if (IsIndividual == 3) // date time
                        {
                            time_t t = time(NULL);                  
                        //  int nDigits = floor(log10(abs(t)) + 1; (strlen(out_html) + nDigits
                            char* timestring = ctime(&t);
                            char* new_out_html = calloc(1 + max(strlen(buff),strlen(out_html)) + strlen(timestring), sizeof(char));
                            strcpy(new_out_html, out_html);
                            strcat(new_out_html, timestring);
                            //printf("%s",new_out_html);
                            free(out_html); out_html = NULL; // free(timestring);
                            out_html = new_out_html;  
                        } else
                        {
                            strcat(out_html, tag);
                        };
                    }else
                    {
                        strcat(out_html, tag);
                        if(Stack != NULL && isCloserTagOf(tag,Stack->data))
                        {
                            Stack = pop(Stack);
                        }else
                        {
                            Stack = push(Stack, tag);
                        };
                    } 
                    if(isMajorTag(tag))
                    {   
                        if(bodyCnt < 6)
                        {   body[bodyCnt] = calloc(strlen(tag), sizeof(char));
                            strcpy(body[bodyCnt],tag);
                            ++bodyCnt;
                        }else
                        {   
                            printf("Too much major html tag found...");
                            correct_body = 0;
                        }
                    }
                }else
                {
                    printf("Invalid html tag: %s \n", tag);
                    is_valid = 0;
                    break;
                }
                P = P + nextCloser;
            } 
            else
            {
                printf("Unclosed tag\n");
                is_valid = 0;
                break;
            }
        } else
        {  //printf("-%c",P[0]);
           strncat(out_html, P,1); 
        //  printf("{(%s)}",out_html);
           P = P + 1;
        };
    };

    int i;
    char* correctBody[] = { "<html>", "<head>", "</head>", "<body>", "</body>", "</html>"};
    for(i = 0; i < bodyCnt && correct_body; ++i) {
            correct_body = (strcmp(body[i],correctBody[i]) == 0); }
    if(is_valid && Stack == NULL && 
       correct_body && bodyCnt == 6){ printf("\nValid HTML Code\n");
                                      printf("\n\n%s\n",out_html);
                                        }
    else                              printf("\nInvalid.\n");

//  printf("%i %i %i",bodyCnt,correct_body,is_valid);
    /*****************************************************************/
    for(i=0;i<bodyCnt;++i) free(body[i]);
    free(buff); free(valids); // 
    if(out_html != NULL) free(out_html);
    return 0;
}

在代码的最后:     if(out_html!= NULL)free(out_html); 没有这个,就没有崩溃。

我认为坠机是在第196行附近造成的。

(必须有一个带有正确html标签的valig-html文件 - 没有这个,代码没用,我的意思是这样的文件:)

3 个答案:

答案 0 :(得分:1)

很难弄清楚代码中发生了什么,但是第一眼就看到了一些无意义的无意义操作。例如,考虑这个序列

int f = open(fname, O_RDONLY);
long pos = lseek(f, 0, SEEK_END);
lseek(f, 0, SEEK_SET);

char *buff = calloc(pos,1);
read(f, buff, pos);
close(f);
...

char* out_html = calloc(strlen(buff), sizeof(char));

您将某个文件的内容读入已分配的缓冲区buff(缓冲区的大小正好是文件的大小)。之后您将buff视为以空字符结尾的字符串:您将其用作strlen的参数。

但是你从来没有打扰过你的buff!这应该怎么样?如果它不是以null结尾,则它不是字符串,并且不能有意义地用作strlen的参数。

你的程序包含几个遵循相同模式的代码实例:某个文件的整个内容被读入一个具有确切大小的缓冲区,然后被解释为以null结尾的字符串,而实际上它不是以null结尾的(没有人为确保无效终止而烦恼。)

终止零是否应该出现在文件本身中?如果是这样,那我们怎么知道呢?我们不是在这里进行远程会议。

答案 1 :(得分:0)

错误消息可能有点令人困惑。

当使用calloc分配200字节时,例程内部分配更多:
说8,16或32个字节来制作链表和其他簿记(即它已被释放)。

如果使用strcpy / strcat附加或复制的字符串不适合目标数组,则内部可能会导致簿记损坏。

因此,错误不一定会释放指针两次。

答案 2 :(得分:0)

这看起来不对: (顺便说一句:我找不到stackTop的定义/声明)

node* pop(node* stackTop)
{
    if(stackTop != NULL)
    {
        free(stackTop->data);
        node* P = stackTop;
        return stackTop->nextnode;
        free(P);
    }else return NULL;
}

这是另一个太短的calloc()。 (strcpy()会将其nul字节放在不属于calloc()ed对象的位置.BTW:根据定义,sizeof(char)为1。

                    if(bodyCnt < 6)
                    {   body[bodyCnt] = calloc(strlen(tag), sizeof(char));
                        strcpy(body[bodyCnt],tag);
                        ++bodyCnt;
                    }else
                    {   
                        printf("Too much major html tag found...");
                        correct_body = 0;
                    }