int值意外改变

时间:2014-04-03 08:33:29

标签: c int cgi

我遇到了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 &lt; 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 &lt; 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 &gt; 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 &lt; 0)
                            {
                                /* code */
                                continue;
                            }
                            else
                            {

                                if (isStartFound &lt; 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.它发生在我调试如下:

  1. 在while中,currentIndex = 1表示它开始找到第二条记录
  2. 它找到&#34;完成&#34;,它开始做:
    
    isFinishFound = 1; 
    isStartFound = -1;
    finishContetn[currentIndex] = mallocString(buf);
    
  3. 之后,它再次运行到while,现在isStartFound更改为134538336
  4. 我还尝试将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!(我添加了在代码中评论)正如你所看到的,这里什么也没做!

    这是我的问题,我觉得这很奇怪。 (对不起代码太长了。如果这个版本还有问题,请告诉我。)

1 个答案:

答案 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。即使NULLsizeof,这也会有效,因为{{1}}是一个纯编译时运算符,它不会创建任何运行时代码。

您当然可能需要修改代码以适合您的应用程序,但上述内容应足以让您了解。