【问题标题】:Valgrind: Invalid readsize of 1. strcpyValgrind:无效的读取大小为 1.strcpy
【发布时间】:2014-11-30 11:04:20
【问题描述】:

我收到来自 valgrind 的 seg 错误,我不确定错误的含义或如何实际修复它。我希望对错误和潜在的修复进行一些澄清。这是错误:我

==8063== 命令:./main stock.dat coin.dat ==8063==

==8063== 大小为 1 的读取无效

==8063== at 0x4C2E1C7: strcpy(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)

==8063== by 0x401046: setupNode(在 /home/joshua/Documents/Assignment 2/main)

==8063== by 0x400E78: main (in /home/joshua/Documents/Assignment 2/main)

==8063== 地址 0x0 没有被堆栈、malloc 或(最近)释放

==8063==

==8063==

==8063== 进程以信号 11 (SIGSEGV) 的默认操作终止

==8063== 访问不在地址 0x0 的映射区域内

==8063== at 0x4C2E1C7: strcpy(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)

==8063== by 0x401046: setupNode(在 /home/joshua/Documents/Assignment 2/main)

==8063== by 0x400E78: main (in /home/joshua/Documents/Assignment 2/main)

==8063== 错误摘要:来自 1 个上下文的 1 个错误(已抑制:来自 0 的 0 个)

    #include "vm_menu.h"
    #include "vm_type.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <malloc.h>
    #define NUMARGS 3
    void addNodeBottom(struct stock_item *val, struct stock_item *head);
    struct stock_item* setupNode(char* line);
    char* openFile(char fileName[]);
    int main(int argc, char * argv[])
    {
        struct vm vm;
        struct menu_item menu_items[NUM_MENU_ITEMS];


        /* The UNUSED() function is designed to prevent warnings while your
         * code is only partially complete. Delete these 4 function calls once
         * you are using the data structures declared above in your own code */
        UNUSED(argc);
        UNUSED(argv);
        UNUSED(vm);
        UNUSED(menu_items);
        //creates a the first element for the stock_items type in the data structure.
        struct stock_item *root;
        struct stock_item *item;
        item = (struct stock_item *) malloc( sizeof(struct stock_item) );


        /* Now rootNode points to a node struct */
        root = (struct stock_item *) malloc( sizeof(struct stock_item) );

        /* List of things to do in this function: */
        /* check command line arguments */
        if(argc!=3){
            printf("insuffcient arguments \n");
            return EXIT_SUCCESS;
        }
        /*open stock file*/
        char* fileName = argv[1];
        FILE *file;
        file = fopen(fileName,"r+");

        /*read file*/
        long lSize;
        char *buffer;
        fseek( file , 0L , SEEK_END);
        lSize = ftell( file);
        rewind( file );
        /* allocate memory for entire content */
        buffer = calloc( 1, lSize+1 );
        if( !buffer ) fclose(file),fputs("memory alloc fails",stderr),exit(1);
        /* copy the file into the buffer */
        if( 1!=fread( buffer , lSize, 1 , file) )
            fclose(file),free(buffer),fputs("entire read fails",stderr),exit(1);
        fclose(file);
        /*parse the file using | as the delmeter case*/
        //declare all variables used to store the string in.
        int counter = 0;
        const char newLine[2] = "\n";
        char *saveptr;
        char *line;
        int size;



        //parse the id and set it first.
        size = sizeof(strtok(buffer,newLine)); // allocated memory to store the id in.
        line = malloc(size); //allocates the memory

        int active = 0;

        line = strtok_r(buffer,newLine, &saveptr); // copies the first line from the text file into a char array. .


        while (!active){
            if (line == NULL) {
                printf("\n%s", "Reached end of file while parsing.");
                return(0);
            }

            printf("%s",line);
            item = setupNode(line);
            line = strtok_r(NULL,newLine, &saveptr);

            addNodeBottom(item, root);
            // free(item);
        }


        return 0;
    }
    char* openFile(char fileName[]){
        FILE *file;

        file = fopen(fileName,"r+");

        /*read file*/
        long lSize;
        char *buffer;



        fseek( file , 0L , SEEK_END);
        lSize = ftell( file);
        rewind( file );

        /* allocate memory for entire content */
        buffer = calloc( 1, lSize+1 );
        if( !buffer ) fclose(file),fputs("memory alloc fails",stderr),exit(1);

        /* copy the file into the buffer */
        if( 1!=fread( buffer , lSize, 1 , file) )
            fclose(file),free(buffer),fputs("entire read fails",stderr),exit(1);
        //printf("%s", buffer);
        //      printf("%s",content);

        free(buffer);

        fclose(file);
        return buffer;

    }
    struct stock_item* setupNode(char* line){
        struct stock_item *roots = {NULL};
        roots = (struct stock_item *) malloc( sizeof(struct stock_item)+1 );

        char *ptr;
        char *prices;
        const char del[2] = "|";
        const char delm[2] = ".";
        strcpy(roots->id, strtok_r(line,del,&ptr)); // returns the ID and stores in in the root node.
        strcpy(roots->name, strtok_r(NULL,del,&ptr)); // returns the description and stores it in the root node.
        strcpy(roots->description, strtok_r(NULL,del,&ptr)); // returns the description and stores it in the root node.
        prices = strtok_r(NULL,del,&ptr); // returns a string of the price for vm_item.

        int dol = atoi(strtok(prices,delm));
        int cent = atoi(strtok(NULL,delm));
        roots->price.dollars = dol;
        roots->price.cents = cent;
        int quantity = atoi(strtok_r(NULL,del,&ptr)); // returns how many items are in stock.
        roots->on_hand = quantity;
        return roots;
    }


    void addNodeBottom(struct stock_item *val, struct stock_item *head){

        //create new node
        struct vm_node *newNode = (struct vm_node*)malloc(sizeof(struct vm_node));
        if(newNode == NULL){
            printf("%s", "Unable to allocate memory for new node\n");
            exit(-1);
        }

        newNode->data= val;
        //  printf("%s",newNode->data->id);
        newNode->next = NULL;  // Change 1

        //check for first insertion
        if(head->next == NULL){
            head->next = newNode->data;

            printf("\nadded at beginning\n");
        }
        else
        {

            //else loop through the list and find the last
            //node, insert next to it
            struct vm_node *current = head;
            while (TRUE) { // Change 2
                if(current->next == NULL)
                {
                    current->next = newNode;
                    printf("\nadded later\n");
                    break; // Change 3
                }
                current = current->next;
            };

        }


    }

代码运行时的输出是:

I0001|可乐|75 ml 可乐罐|3.50|50

在开头添加

I0002|百事可乐|375 毫升罐装百事可乐|3.00|20

稍后添加

I0003|柠檬芝士蛋糕|一块美味的 1/8 大小的芝士蛋糕|4.00|10

稍后添加

I0004|Mars Bar|美味的 50 克 Mars Bar 以您喜欢的方式冷藏。|3.00|20

稍后添加

I0005|柠檬馅饼|美味的柠檬奶油馅饼和糕点|3.75|12

稍后添加

解析时到达文件末尾。

此输出是使用 Eclipse 生成的,当我在终端中运行它时,它只会以不显示的段错误响应。

    #ifndef VM_TYPE
    #define VM_TYPE

    #define IDLEN 5
    #define NAMELEN 40
    #define DESCLEN 255
    #define NUMDENOMS 8
    #define UNUSED(var) (void)var
    #define COIN_COUNT 20
    #define DEFAULT_ONHAND 20

    /* Type definition for our boolean type */
    typedef enum truefalse
    {
        FALSE, TRUE
    } BOOLEAN;

    /* Each price will have a dollars and a cents component */
    struct price
    {
        unsigned dollars,cents;
    };

    /* The different denominations of coins available */
    enum denomination
    {
        FIVE_CENTS, TEN_CENTS, TWENTY_CENTS, FIFTY_CENTS, ONE_DOLLAR, 
        TWO_DOLLARS, FIVE_DOLLARS, TEN_DOLLARS
    };

    /* Each coin in the coins array will have a denomination (20 cents, 
     * 50 cents, etc) and a count - how many of that coin do we have on hand
     */
    struct coin
    {
        enum denomination denom;
        unsigned count;
    };

    /* The data structure that holds the data for each item of stock
     */
    struct stock_item
    {
        char id[IDLEN+1];
        char name[NAMELEN+1];
        char description[DESCLEN+1];
        struct price price;
        unsigned on_hand;
        struct stock_item *next;
    };

    /* The data structure that holds a pointer to the stock_item data and a
     * pointer to the next node in the list
     */
    struct vm_node
    {
        struct stock_item * data;
        struct vm_node * next;
    };

    /* The head of the list - has a pointer to the rest of the list and a 
     * stores the length of the list 
     */
    struct vm_list
    {
        struct vm_node * head;
        unsigned length;
    };

    /* This is the head of our overall data structure. We have a pointer to 
     * the vending machine list as well as an array of coins. 
     */
    struct vm
    {
        struct vm_list * item_list;
        struct coin coins[NUMDENOMS];
        char * foodfile;
        char * coinsfile;
    };

    #endif

这些都是def的类型

这是正在读取的文件结构。

I0001|可乐|75 ml 可乐罐|3.50|50

I0002|百事可乐|375 毫升罐装百事可乐|3.00|20

I0003|柠檬芝士蛋糕|一块美味的 1/8 大小的芝士蛋糕|4.00|10

I0004|Mars Bar|美味的 50 克 Mars Bar 以您喜欢的方式冷藏。|3.00|20

I0005|柠檬馅饼|美味的柠檬奶油馅饼和糕点|3.75|12

【问题讨论】:

  • 请显示结构root_item
  • 另外,您确定没有strtok(或strtok_r)调用返回NULL
  • 最后,不要使用逗号分隔语句,这会使代码难以阅读和理解。而是使用适当的块,即将语句放在花括号 {} 中。另外,与其将整个文件读入内存并手动解析行,不如简单地使用fgets 直接从文件中获取行?
  • @JoachimPileborg 我没有考虑过使用 fgets。生病看看如何使用它。感谢您的建议。

标签: c linux eclipse segmentation-fault valgrind


【解决方案1】:

错误Address 0x0 is not stack'd, malloc'd or (recently) free'd 表示strcpy 的源是NULL 指针。显然,strtok_r 正在返回 NULL 而不是您所期望的。

你应该重写你的代码,如果你的输入格式不正确,你会检测到NULL而不是崩溃。 (您的代码还有其他问题)。

【讨论】:

  • 哦,好的,谢谢。这意味着它正在到达 txt 文件的末尾并且不知道该怎么做?
  • @JoshuaTheeuf 不,这意味着该行本身的格式错误。
  • 我已经编辑了帖子以包含文件格式和类型。所以我很困惑该行的格式如何不正确。 ://
【解决方案2】:
size = sizeof(strtok(buffer,newLine));
line = malloc(size); //allocates the memory

这是错误的:sizeof 产生返回指针的大小(strtopk 返回 char *),基本上是 4 或 8 个字节。

【讨论】:

  • 嗯好的,我可以删除该行。虽然它不影响我在 setupNode 函数中收到的段错误。
  • @JoshuaTheeuf 您可能还有其他问题,但您的测试用例中缺少一些信息,例如struct stock_item 类型是如何定义的?
  • 我已经编辑了帖子以包含正在读取的文件的格式和类型 defs。
猜你喜欢
  • 2020-08-19
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 2017-11-17
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多