我有一个C代码(我写过的第一个C代码),其中有一个错误,但我不知道在哪里。当我试图释放一个变量(通常分配,它的名称是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 nn", 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] != ' ' )
{
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 tagn");
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 Coden");
printf("nn%sn",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标签的有效html文件-没有这个,代码就没有用了,我指的是这样的文件:)
错误消息可能有点令人困惑。
当用calloc分配200个字节时,例程会在内部分配更多的字节:
比如8、16或32个字节来制作链表和其他记账(即它是否已释放)。
如果用strcpy/strcat附加或复制的字符串不适合目标数组,则可能会在内部导致记帐损坏。
因此,该错误不一定与两次释放指针有关。
很难弄清楚代码中发生了什么,但一些可能毫无意义的操作一眼就能看到。例如,考虑这个序列
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
视为以null结尾的字符串:将其用作strlen
的参数。
但你从来没有费心去空命名你的buff
!这是怎么回事?如果它不是以null结尾的,则它不是字符串,并且不能有意义地用作strlen
的参数。
您的程序包含几个遵循相同模式的代码实例:某个文件的整个内容被读取到一个完全大小的缓冲区中,然后被解释为以null结尾的字符串,而实际上它并不是以null结尾(没有人愿意确保null结尾)。
终止零应该存在于文件本身中吗?如果是这样的话,我们怎么知道呢?我们在这里不是心灵感应者。
这看起来是错误的:(顺便说一句:我找不到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;
}