Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid write of size 8, C Valgrind, string arrays

I have been using both valgrind and gdb and I can not quite figure out what the problem is. It hops around too much for me to really trace it down in gdb, and in valgrind I don't have enough information. Here is my makeargv function, which is putting strings outputted from strtok() into arrays. makeargv is called from the below parse function. I'm not sure where I'm going wrong. I would really appreciate the help :D.

Just an FYI I'm really new to all this malloc'ing and don't really understand the concept as well as I would like. I'm not sure when specifically I should be mallocing. I feel like since here I am mainly setting constant values I don't have to be, but I'm wondering why it won't work.

makeargv function

int makeargv(const char *string, char **argvp) {
    int i = 0;
    int numtokens = 0;
    const char *copy;
    char *buffer = malloc(160*sizeof(char));

    if ((string == NULL) || (delims == NULL) || (argvp == NULL)) {
      return -1;
    }

    argvp = NULL;
    copy = string + strspn(string, delims);
    if ((buffer = malloc(strlen(copy) + 1)) == NULL) {
      return -1;
    }
    strcpy(buffer, copy);
    numtokens = 0;
    if (strtok(buffer, delims) != NULL) {
      for (numtokens = 1; strtok(NULL, delims) != NULL; numtokens++);
    }

    if ((argvp = malloc((numtokens + 2)*sizeof(int))) == NULL) {
      free(buffer);
      return -1;
    }

    if (numtokens == 0) {
      free(buffer);
    }
    else {
      strcpy(buffer, copy);
      *argvp = malloc(16);
      *argvp = strtok(buffer, delims);

      for (i = 2; i < (numtokens*2); i += 2) {
      *(argvp + i) = strtok(NULL, delims);
      //printf("%s\n", strtok(NULL, delims)); /*When I run this the tokens come out
      correctly so I know it isn't a problem with strtok */
  }
}

//  *((argvp) + numtokens) = NULL;
free(buffer);
return numtokens;
}

Parse function

void parse_file(char* filename) {
    char* line = malloc(160*sizeof(char));
    FILE* fp = file_open(filename);
    int i = 0;

    while((line = file_getline(line, fp)) != NULL) {
      char** results = malloc(16*10*sizeof(char));

      if (strlen(line) == 1){
        continue;
      }

      if ((i = makeargv(line, results)) == -1){
        printf("ERROR SOMEWHERE IN MAKEARGV");
        continue;
      } 
    }

    fclose(fp);
    free(line);
}

valgrind output

==7309== Memcheck, a memory error detector
==7309== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==7309== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==7309== Command: ./custmake
==7309== 
==7309== Invalid write of size 8
==7309==    at 0x400C23: makeargv (main.c:62)
==7309==    by 0x400CD4: parse_file (main.c:120)
==7309==    by 0x400DFF: main (main.c:172)
==7309==  Address 0x51f25c0 is 16 bytes inside a block of size 20 alloc'd
==7309==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x400B76: makeargv (main.c:49)
==7309==    by 0x400CD4: parse_file (main.c:120)
==7309==    by 0x400DFF: main (main.c:172)
==7309== 
==7309== Use of uninitialised value of size 8
==7309==    at 0x4C2BFC2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x4EA2CEB: puts (ioputs.c:37)
==7309==    by 0x400D09: parse_file (main.c:128)
==7309==    by 0x400DFF: main (main.c:172)
==7309== 
==7309== Invalid read of size 1
==7309==    at 0x4C2BFC2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x4EA2CEB: puts (ioputs.c:37)
==7309==    by 0x400D09: parse_file (main.c:128)
==7309==    by 0x400DFF: main (main.c:172)
==7309==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==7309== 
==7309== 
==7309== Process terminating with default action of signal 11 (SIGSEGV)
==7309==  Access not within mapped region at address 0x0
==7309==    at 0x4C2BFC2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x4EA2CEB: puts (ioputs.c:37)
==7309==    by 0x400D09: parse_file (main.c:128)
==7309==    by 0x400DFF: main (main.c:172)
==7309==  If you believe this happened as a result of a stack
==7309==  overflow in your program's main thread (unlikely but
==7309==  possible), you can try to increase the size of the
==7309==  main thread stack using the --main-stacksize= flag.
==7309==  The main thread stack size used in this run was 8388608.
==7309== 
==7309== HEAP SUMMARY:
==7309==     in use at exit: 1,084 bytes in 6 blocks
==7309==   total heap usage: 7 allocs, 1 frees, 1,100 bytes allocated
==7309== 
==7309== 16 bytes in 1 blocks are definitely lost in loss record 1 of 6
==7309==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x400BCB: makeargv (main.c:59)
==7309==    by 0x400CD4: parse_file (main.c:120)
==7309==    by 0x400DFF: main (main.c:172)
==7309== 
==7309== 20 bytes in 1 blocks are definitely lost in loss record 2 of 6
==7309==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x400B76: makeargv (main.c:49)
==7309==    by 0x400CD4: parse_file (main.c:120)
==7309==    by 0x400DFF: main (main.c:172)
==7309== 
==7309== 160 bytes in 1 blocks are definitely lost in loss record 5 of 6
==7309==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7309==    by 0x400A6E: makeargv (main.c:32)
==7309==    by 0x400CD4: parse_file (main.c:120)
==7309==    by 0x400DFF: main (main.c:172)
==7309== 
==7309== LEAK SUMMARY:
==7309==    definitely lost: 196 bytes in 3 blocks
==7309==    indirectly lost: 0 bytes in 0 blocks
==7309==      possibly lost: 0 bytes in 0 blocks
==7309==    still reachable: 888 bytes in 3 blocks
==7309==         suppressed: 0 bytes in 0 blocks
==7309== Reachable blocks (those to which a pointer was found) are not shown.
==7309== To see them, rerun with: --leak-check=full --show-reachable=yes
==7309== 
==7309== For counts of detected and suppressed errors, rerun with: -v
==7309== Use --track-origins=yes to see where uninitialised values come from
==7309== ERROR SUMMARY: 7 errors from 6 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)
like image 518
user3321556 Avatar asked Feb 18 '14 07:02

user3321556


People also ask

What does Invalid write size mean in Valgrind?

Error message: Invalid write of size 4, means possible an integer or pointer on 32bits platform was stored in a memory that is not allocated with malloc() or on the stack. This happened at example. c 6th line, that was called from main.

What is invalid write in Valgrind?

“Invalid write” means that our program tries to write data in a memory zone where it shouldn't. But Valgrind tells you way more than that. It first tells you the size of the written data, which is 1 bytes, and corresponds to the size of a character. Then the line at 0x400553: main (test.


1 Answers

Your argvp variable in makeargv is an array of pointers, but when you allocate he memory for it you use sizeof(int) which will only be four bytes on a 64 bit system, while pointers will be 8 bytes.

As a result you write beyond the end of the array - that's why it reports you writing 8 bytes at offset 16 of a 20 byte block, which therefore overlaps the end of the block by 4 bytes.

Use sizeof(char *) to get the correct size of a pointer when allocating the argvp array.

like image 100
TomH Avatar answered Oct 12 '22 23:10

TomH