我遇到了c程序的问题:int变量意外更改。
以下是关于这个问题的全部内容:
我尝试读取一个类似于:
的txt文件2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success
这是一个记录任务开始/结束时间的日志文件。我想解析日志文件并在订单时间(最新的第一个)中找到完成的任务记录。例如,我将尝试读取最后一行,它表明任务正在运行。因此我忽略它并继续阅读最后的第2行。一般来说,接下来的两行有"结束"并且"开始"成对可以标记为记录。
我的环境是:Centos6.5(通过VMWaire安装)。 以下是源代码,它使用libccgi:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "json/json.h"
#include "ccgi.h"
#include <errno.h>
const char *queryName = "account";
const char *queryPage = "pageIndex";
const char *startAction = "/activeJob/start/";
const char *finishAction = "/activeJob/finish/";
const char *contentDes[] = {"there is backup processing, start at :","there is no backup"};
const float pageNums = 8.0;
const char * jsonStringCreate(json_object *jsonObj,int statueCode, char *content, int totalPages)
{
json_object_object_add(jsonObj, "statueCode", json_object_new_int(statueCode));
json_object_object_add(jsonObj, "content", json_object_new_string(content));
json_object_object_add(jsonObj, "totalPages", json_object_new_int((int)totalPages));
//the memory of returned string is under control of jsonObj
return json_object_get_string(jsonObj);
}
char *mallocString(char *string)
{
char *returnString = malloc(sizeof(char) * (1 + strlen(string)));
strcpy(returnString, string);
//owner free the returned string
return returnString;
}
/* File must be open with 'b' in the mode parameter to fopen() */
/* Set file position to size of file before reading last line of file */
char* fgetsr(char* buf, int n, FILE* binaryStream)
{
long fpos;
int cpos;
int first = 1;
if (n < 1 || (fpos = ftell(binaryStream)) == -1 || fpos == 0)
return NULL;
cpos = n - 1;
buf[cpos] = '\0';
for (;;)
{
int c;
if (fseek(binaryStream, --fpos, SEEK_SET) != 0 ||
(c = fgetc(binaryStream)) == EOF)
return NULL;
if (c == '\n' && first == 0) /* accept at most one '\n' */
break;
first = 0;
if (c != '\r') /* ignore DOS/Windows '\r' */
{
unsigned char ch = c;
if (cpos == 0)
{
memmove(buf + 1, buf, n - 2);
++cpos;
}
memcpy(buf + --cpos, &ch, 1);
}
if (fpos == 0)
{
fseek(binaryStream, 0, SEEK_SET);
break;
}
}
memmove(buf, buf + cpos, n - cpos);
return buf;
}
</code></pre>
<pre><code>
int main(int argc, char const *argv[], char **env)
{
int statueCode = 0;
int totalPages = 0;
char *content = NULL;
json_object *jsonObj = json_object_new_object();
printf("Content-type: text/plain; encoding=utf-8\n\n");
CGI_varlist *vl;
const char *name;
CGI_value *value;
int i;
if ((vl = CGI_get_all("/tmp/cgi-upload-XXXXXX") ) == 0)
{
// CGI error
// fputs("CGI_get_all() failed\r\n", stdout);
statueCode = 501;
content = mallocString("CGI error");
}
else
{
//get the CGI env parameters, next to get the query parameter
char *accountName = NULL;
int queryIndex = -1;
for (name = CGI_first_name(vl); name != 0; name = CGI_next_name(vl))
{
value = CGI_lookup_all(vl, 0);
for ( i = 0; value[i] != 0; ++i)
{
if (strcmp(name, queryName) == 0)
{
accountName = malloc(sizeof(char) * (strlen(value[i]) + 4 + 1));
strcpy(accountName, value[i]);
strcat(accountName, ".log");
}
else if (strcmp(name, queryPage) == 0)
{
queryIndex = atoi(value[i]);
}
}
}
if (accountName == NULL || queryIndex < 0)
{
statueCode = 502;
content = mallocString("wrong query parameters format");
}
else
{
//for test, need remove
FILE *logFile = fopen("./test@mail.com.log", "rb");
// FILE *logFile = fopen(accountName, "r");
char *lastLineStr = NULL;
int lineNum = 0;
if (logFile != NULL)
{
//log file is found
char *line = NULL;
size_t len = 0;
ssize_t read;
while( (read = getline(&line, &len, logFile)) != -1)
{
// printf("%s\n", line);
if (strstr(line, finishAction) != 0)
{
/* code */
totalPages ++;
}
lineNum ++;
}
free(line);
int realPage = ceil(totalPages/pageNums);
if (queryIndex > realPage)
{
/* code */
statueCode = 503;
content = mallocString("wrong parameter: query index is beyond the total page");
}
else
{
//log file exist and query index is valid
long startIndex = 0, endIndex = 0, currentIndex = 0;;
startIndex = (queryIndex - 1) * pageNums;
endIndex = (queryIndex) *pageNums;
currentIndex = startIndex;
char buf[256];
int isFinishFound = -1;
int isStartFound = -1;
char *finishContetn[] = {};
char *startContent[] = {};
// this is the core part
while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex lt; endIndex)
{
if (strstr(buf, finishAction) != 0)
{
/* code */
if (isFinishFound > 0)
{
/* code */
continue;
}
else
{
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
}
}// strange part:
else if (strstr(buf, startAction) != 0)
{
//finish is not found, means: a start with no finish pairs
if (isFinishFound < 0)
{
/* code */
continue;
}
else
{
if (isStartFound < 0)
{
/* code */
startContent[currentIndex] = mallocString(buf);
isStartFound = 1;
isFinishFound = -1;
currentIndex ++;
}
else
{
continue;
}
}
}
}
}
}
else
{
//log file is not found
statueCode = 400;
content = mallocString("not found the account log");
// printf("not found\n");
// fprintf(stderr, "%d: %s\n", errno, strerror(errno) );
}
if (logFile)
{
fclose(logFile);
}
}
}
return 0;
}
libjson和libccgi被放置在正确的位置,我构建并使它像:
/usr/local/bin/clang -I /usr/include -DHAVE_SSL -DCLDMAN -DCLDMAN_USE_RETRY -DUSE_PROXY -c -MMD -fPIC -g -DHAVE_SSL -DCLDMAN -I../../build/include -I../../build/include/curl -I../../build/include/json -I../../build/include/svmdisk -o getLog.o getLog.c
/usr/local/bin/clang -o getLog getLog.o -L../../build/lib -lm -lccgi -ljson
并且终端没有错误。
我遇到的问题是int isStartFound
的值将有一个奇怪的值134538336.它发生在我调试如下:
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
while
,现在isStartFound
更改为134538336
。我还尝试将isStartFound
添加到watch变量中。它还显示在&#34;奇怪部分&#34;(我在代码中添加)isStartFound
的值从-1
更改为134538336
。
我找不到这个值的来源。我怀疑我构建和链接的方式是错误的。但是我找不到它。
任何人都可以建议我如何调查?
谢谢!
=======编辑: 问题主要在于下面的代码:
char buf[256];
int isFinishFound = -1;
int isStartFound = -1;
while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex 0)
{
continue;
}
else
{
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
}
}// here strange happens: the isStartFound changes!
else
{
// other part
}
}
fgetsr
用于读取文本的一行; isStartFound&isFinishFound
是2个掩码,用于显示&#34;开始&#34; /&#34;完成&#34;找到记录。
问题来自一个先决条件:找到第一条记录,现在我们尝试读取最后一条第5行(这是第二行)。文本文件是:
2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success
现在它开始阅读第二行并找到&#34;完成&#34;,因此需要标记var:isStartFound = -1。
当程序运行到第一个&#34;}&#34;时,isStartFound为-1。但当它运行到第二个&#34;}&#34;(if (strstr(buf, finishAction) != 0)
的&#34;}&#34;时,值会发生变化:siStartFound = 134538336
!(我添加了在代码中评论)正如你所看到的,这里什么也没做!
这是我的问题,我觉得这很奇怪。 (对不起代码太长了。如果这个版本还有问题,请告诉我。)
答案 0 :(得分:2)
问题在于这个声明:
char *finishContetn[] = {};
这将finishContetn
声明为空指针数组。为空,无论您使用什么索引来访问此数组,它都将超出范围。
分配给此数组时:
finishContetn[currentIndex] = mallocString(buf);
你将超越边界,并将undefined behavior。在这种情况下,您将覆盖其他变量所在的堆栈,例如isStartFound
变量。
解决此问题的方法是设置固定大小,或使用动态“数组”。动态数组解决方案要求您将变量声明为指向指针(指向char
)并使用realloc
来(重新)分配数组。
像
这样的东西char **finishContent = NULL;
size_t finishContentSize = 0; /* Current size of the array */
...
char **temp = realloc(finishContent, sizeof(finishContent[0]) * finishContentSize + 1);
if (temp != NULL)
{
finishContent = temp;
finishContent[finishContentSize++] = malloc(...);
}
请注意,我使用临时变量来返回realloc
,这是因为如果realloc
失败,那么它将不会为您释放finishContent
,如果您直接分配给finishContent
free
你将丢失原始指针,以后不能sizeof(finishContent[0])
。
另请注意,我使用finishContent
。即使NULL
为sizeof
,这也会有效,因为{{1}}是一个纯编译时运算符,它不会创建任何运行时代码。
您当然可能需要修改代码以适合您的应用程序,但上述内容应足以让您了解。