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 (an API in 
obstack, which is widely used in various gnu libraries, e.g.c Glibc, more 
details in 
https://gcc.gnu.org/onlinedocs/libiberty<https://gcc.gnu.org/onlinedocs/libiberty/>),
 and want to request your suggestions.
Top (GNU libiberty)<https://gcc.gnu.org/onlinedocs/libiberty/>
Introduction. The libiberty library is a collection of subroutines used by 
various GNU programs. It is available under the Library General Public License; 
for more information, see Library Copying. • Using:
gcc.gnu.org


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

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) 

#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;
}
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

Reply via email to