简体   繁体   中英

valgrind invalid read of size 1 (realloc makes errors “use-after-free condition”)

The function of my path_append() function is.

  • append given two strings and store them in one global string.
  • Add '/' to the midle of two strings.
  • returns the appended strings first address.

But we store every input in the same variable with null termination.

eg:- as input "/usr", "bin" is given.

then output sholud be ---> "/usr/bin"

In memory it should be like this.

+---+---+---+---+---+---+---+---+----+
| / | u | s | r | / | b | i | n | \0 |
+---+---+---+---+---+---+---+---+----+

let us say the previous call is function's first time call. If we call it second time giving arguments like "/etc", "sshd" the output should be "/etc/sshd". In memory it should be like this.

+---+---+---+---+---+---+---+---+----+---+---+---+---+---+---+---+---+---+----+
| / | u | s | r | / | b | i | n | \0 | / | e | t | c | / | s | s | h | d | \0 |
+---+---+---+---+---+---+---+---+----+---+---+---+---+---+---+---+---+---+----+

ERROR

If we call it more than one time it gives valgrind "invalid read size" error pointing the realloc function call in my program.

Here is my program.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *p_app = NULL; /* This is global variable */

char *path_append(const char *p1, const char *p2)
{
    static int p_app_len = 0;
    int cur_len;    /*current len*/

    /* length of '/' + strlen(p1) + strlen(p2) + null charachter */
    cur_len = (strlen(p1) + strlen(p2) + 2);
    p_app_len += cur_len;

    if ((p_app_len - cur_len) == 0) /* Detect first time call */
        p_app = (char *)malloc(p_app_len);
    else
        p_app = (char *)realloc(p_app, (size_t)p_app_len);

    sprintf(p_app + p_app_len - cur_len, "%s/%s", p1, p2);

    return p_app + p_app_len - cur_len;
}

int main()
{
    char *x = path_append("/usr", "bin");
    char *y = path_append("/home", "minol");

    printf("%s\n", x);
    printf("%s\n", y);

    free(p_app); /* we do not free x or y */
    return 0;
}

Here is My error output

==4139== Memcheck, a memory error detector
==4139== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4139== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4139== Command: ./test2
==4139== 
==4139== Invalid read of size 1
==4139==    at 0x4C2E0E2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4139==    by 0x4EA6E3B: puts (ioputs.c:36)
==4139==    by 0x4007C3: main (test2.c:42)
==4139==  Address 0x51fc040 is 0 bytes inside a block of size 9 free'd
==4139==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4139==    by 0x40071F: path_append (test2.c:30)
==4139==    by 0x4007B3: main (test2.c:40)
==4139== 
==4139== Invalid read of size 1
==4139==    at 0x4C2E0F4: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4139==    by 0x4EA6E3B: puts (ioputs.c:36)
==4139==    by 0x4007C3: main (test2.c:42)
==4139==  Address 0x51fc041 is 1 bytes inside a block of size 9 free'd
==4139==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4139==    by 0x40071F: path_append (test2.c:30)
==4139==    by 0x4007B3: main (test2.c:40)
==4139== 
==4139== Invalid read of size 1
==4139==    at 0x4EB26FE: _IO_default_xsputn (genops.c:480)
==4139==    by 0x4EB06E1: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1353)
==4139==    by 0x4EA6ED6: puts (ioputs.c:41)
==4139==    by 0x4007C3: main (test2.c:42)
==4139==  Address 0x51fc040 is 0 bytes inside a block of size 9 free'd
==4139==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4139==    by 0x40071F: path_append (test2.c:30)
==4139==    by 0x4007B3: main (test2.c:40)
==4139== 
/usr/bin
/etc/sshd
==4139== 
==4139== HEAP SUMMARY:
==4139==     in use at exit: 0 bytes in 0 blocks
==4139==   total heap usage: 2 allocs, 2 frees, 28 bytes allocated
==4139== 
==4139== All heap blocks were freed -- no leaks are possible
==4139== 
==4139== For counts of detected and suppressed errors, rerun with: -v
==4139== ERROR SUMMARY: 17 errors from 3 contexts (suppressed: 0 from 0)

This is caused by use-after-free condition.

The first call to path_append() returns a pointer x to some memory which was allocated by malloc() .

The second call to path_append() calls realloc() which return a new pointer making the pointer x in main invalid.

Here p_app is changed to point to a larger memory segment, but x is not updated with the new value and still points to old memory.

p_app = (char *)realloc(p_app, (size_t)p_app_len);

This wouldn't happen if a global variable wasn't used. To fix the design flaw, use an array of char pointers and add strings to it and pass them to a function instead of using a global.

x is invalid after realloc()

the line

    p_app = (char *)realloc(p_app, (size_t)p_app_len);

the sting in p_app is now on a new place, but x still points to the old location of this string.

so

printf("%s\n", x);

is invalid. (but in this case, the data are still there, so it will print the right thing)

Edit, why the first string is still in memory:

realloc can work like this (i make it simple, no error check):

char *newPos = malloc(newSize);
memcpy(newPos,oldPos,oldSize);
free(oldPos);

But free() only set the location of oldPos as not used, it don't delete the content of oldPos.

Memory before realloc call can be like (here is sizeof size_t and intptr_t = 1, to make it simple):

1  NULL  4  'f' 'o' 'o' '\0'  0    0   0   0   0    0   0  0  0  0  

and after

7  NULL  4  'f' 'o' 'o' '\0' NULL  8  'f' 'o' 'o' '\0'  0  0  0  0  

The first number is a pointer to the first alloced block. The second number before realloc points to the next alloced Block, there is no other alloced Block, so it is NULL.

The next is the lenght of the Alloced Bytes, 4 for sthe string "Foo". After realloc, the first valid alloced block start at adress 7. The previous block is still there but it freed, and not valid anymore. The block given from realloc() start at 7. The data start at 9, on adress 7 is Stored, where the next valid block is and on byte 8 the lenght of the block.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM