public inbox for libc-help@sourceware.org
 help / color / mirror / Atom feed
* [Question] How does obstack deal with the specific valid address in obstack_free ?
@ 2021-12-16  1:09 TU Haoxin
  0 siblings, 0 replies; only message in thread
From: TU Haoxin @ 2021-12-16  1:09 UTC (permalink / raw)
  To: libc-help

[-- Attachment #1: Type: text/plain, Size: 1864 bytes --]

Dear developers,

I hope it's fine for me to ask you a question, please forgive me if not. I just have a question about the implementation intention of obstack_free.

The question is about the intention of how does obstack_free free an address at the bottom of a chunk in the obstack. Here is a quick demonstration code: https://godbolt.org/z/arv4ha19b

My point here is that the address "string_obstack->chunk" in obstrack_free (line 40) is a valid address from this chunk, and it should be freed normally as other pointers (execute this line will crash). However, it seems the current obstack_free function can not handle it and it will finally get an abort failure. (please refer to the gdb-log.txt in the attachment, as well as the testing code and the compiling script, for more details).

I found this "issue" when I tested the library using the symbolic execution technique. Again, I am not sure whether it's an issue or not. If so, the possible fixing is just changing the if condition "__obj > (void *) __o->chunk" to "__obj >= (void *) __o->chunk". Or if not, is it the intention of the obstack implementation to do so? Or in what purpose does obstack not support free from that specific address? Since the obstack is widely used, I guess it's quite important to avoid any potential issues in the implementation code.

obstack_free defined in "obstack.h"
```
# define obstack_free(OBSTACK, OBJ)      \
  __extension__      \
    ({ struct obstack *__o = (OBSTACK);      \
       void *__obj = (OBJ);      \
       if (__obj > (void *) __o->chunk && __obj < (void *) __o->chunk_limit)  \
__o->next_free = __o->object_base = (char *) __obj;      \
       else (__obstack_free) (__o, __obj); })
```

Any suggestions or comments are welcome!

Thank you very much for your time and waiting for your reply~


Best regards,
Haoxin


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: compile.sh --]
[-- Type: text/x-sh; name="compile.sh", Size: 259 bytes --]

gcc -g obstack-test.c -o obstack -Wl,--rpath=/home/haoxin/haoxin-data/smu-research/onsite-env/klee-nme-aeg/glibc-2.27/glibc-2.27/build/ #-Wl,--dynamic-linker=/home/haoxin/haoxin-data/smu-research/onsite-env/klee-nme-aeg/glibc-2.27/glibc-2.27/build/elf/ld.so


[-- Attachment #3: obstack-test.c --]
[-- Type: text/plain, Size: 2308 bytes --]

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

#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

//struct obstack *string_obstack;

int main(){
    struct obstack *string_obstack = (struct obstack *) malloc (sizeof (struct obstack));

    obstack_init (string_obstack);

    printf("address of obstack = %p, chunk_size = %d \n", string_obstack, string_obstack->chunk_size);
    printf("chunk = %p, object_base = %p next_free = %p \n\n", string_obstack->chunk, string_obstack->object_base, string_obstack->next_free);

    // Step 1: allocate the first chunk
    char *s = (char *) obstack_alloc (string_obstack, 4064);
    printf("======First chunk======\n");
    printf("before free: ((void *) lp = %p , (void *) (lp)->limit = %p \n", string_obstack->chunk, (void *) (string_obstack)->chunk->limit);
    printf("before free : prv = %p\n\n", string_obstack->chunk->prev);

    // Step 2: allocate the second chunk
    char *ss = (char *) obstack_alloc (string_obstack, 4064);

    printf("before free : address of s = %p\n", s);
    printf("before free : address of ss = %p\n\n", ss);

    printf("======Second chunk======\n");
    printf("before free: ((void *) lp = %p , (void *) (lp)->limit = %p \n", string_obstack->chunk, (void *) (string_obstack)->chunk->limit);
    printf("before free : prv = %p\n\n", string_obstack->chunk->prev);


    // Step 3: free the second chunk through obj
    printf("======Start to free======\n");
    char *t = s+4177;
    printf("before free : obj (string_obstack->chunk) = %p \n", string_obstack->chunk);
    printf("before free : obj (t) = %p \n\n", t);
    obstack_free (string_obstack, string_obstack->chunk); //problematic
    obstack_free (string_obstack, t);

    printf("======Third chunk======\n");
    printf("after free: ((void *) lp = %p , (void *) (lp)->limit = %p \n", (void *) (string_obstack)->chunk, (void *) (string_obstack)->chunk->limit);
    printf("after free : prv = %p\n", string_obstack->chunk->prev);


    // Step 4: allocate the third chunk in the location of chunk2
    char *sss = (char *) obstack_alloc (string_obstack, 4064);


    printf("after free : address of s = %p\n", s);
    printf("after free : address of ss = %p\n", ss);
    printf("after free : address of sss = %p\n\n", sss);

    return 0;
}

[-- Attachment #4: gdb-log.txt --]
[-- Type: text/plain, Size: 3245 bytes --]

GNU gdb (GDB) 10.0.50.20200724-git
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from obstack...
(gdb) b obstack_free
Breakpoint 1 at 0x1060
(gdb) r
Starting program: /media/haoxin/SeagateData/haoxin-data/smu-research/exp/datasets/ram-paper/klee-mm-benchmarks/m4/build/src/obstack 
address of obstack = 0x555555559260, chunk_size = 4064 
chunk = 0x5555555592c0, object_base = 0x5555555592d0 next_free = 0x5555555592d0 

======First chunk======
before free: ((void *) lp = 0x55555555a6c0 , (void *) (lp)->limit = 0x55555555b713 
before free : prv = (nil)

before free : address of s = 0x55555555a6d0
before free : address of ss = 0x55555555b730

======Second chunk======
before free: ((void *) lp = 0x55555555b720 , (void *) (lp)->limit = 0x55555555c773 
before free : prv = 0x55555555a6c0

======Start to free======
before free : obj (string_obstack->chunk) = 0x55555555b720 
before free : obj (t) = 0x55555555b721 


Breakpoint 1, obstack_free (h=0x555555559260, obj=0x55555555b720) at obstack.c:346
346	{
(gdb) n
350	  lp = h->chunk;
(gdb) l
345	__obstack_free (struct obstack *h, void *obj)
346	{
347	  struct _obstack_chunk *lp;    /* below addr of any objects in this chunk */
348	  struct _obstack_chunk *plp;   /* point to previous chunk if any */
349	
350	  lp = h->chunk;
351	  /* We use >= because there cannot be an object at the beginning of a chunk.
352	     But there can be an empty object at that address
353	     at the end of another chunk.  */
354	  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
(gdb) n
354	  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
(gdb) p lp
$1 = (struct _obstack_chunk *) 0x55555555b720
(gdb) p obj
$2 = (void *) 0x55555555b720
(gdb) n
357	      CALL_FREEFUN (h, lp);
(gdb) n
356	      plp = lp->prev;
(gdb) 
357	      CALL_FREEFUN (h, lp);
(gdb) 
361	      h->maybe_empty_object = 1;
(gdb) 
354	  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
(gdb) p lp
$3 = (struct _obstack_chunk *) 0x55555555a6c0
(gdb) p obj
$4 = (void *) 0x55555555b720
(gdb) n
357	      CALL_FREEFUN (h, lp);
(gdb) 
356	      plp = lp->prev;
(gdb) 
357	      CALL_FREEFUN (h, lp);
(gdb) 
361	      h->maybe_empty_object = 1;
(gdb) 
354	  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
(gdb) p lp
$5 = (struct _obstack_chunk *) 0x0
(gdb) p obj
$6 = (void *) 0x55555555b720
(gdb) n
369	  else if (obj != 0)
(gdb) n
371	    abort ();
(gdb) 

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51	}
(gdb) 


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-12-16  1:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-16  1:09 [Question] How does obstack deal with the specific valid address in obstack_free ? TU Haoxin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).