Hi, It would seem that this issue is responsible for the crash I've seen randomly happening with gconf (2.6.36-rc6, before my generalization's branch). So far, I've traced it to the following line in menu_finalize(): sym->dir_dep.expr = expr_transform(expr_copy(parent->dir_dep)); The crash happen in expr_copy(). expr_transform() is never being called. The trace is the following: Program received signal SIGSEGV, Segmentation fault. 0xbb1f085c in ?? () from /usr/lib/libc.so.12 (gdb) bt #0 0xbb1f085c in ?? () from /usr/lib/libc.so.12 #1 0xbb1f0e4b in malloc () from /usr/lib/libc.so.12 #2 0x0805277f in expr_copy (org=0xba790fd0) at scripts/kconfig/expr.c:79 #3 0x080527e9 in expr_copy (org=0xba790fd0) at scripts/kconfig/expr.c:86 #4 0x00000001 in ?? () #5 0x00000000 in ?? () however, with the small patch attached, we get a bit more information: (gdb) print expr_copy_nest $1 = 43391 After reducing the stack size from 2048k (default) to 1024k: (gdb) print expr_copy_nest $1 = 21545 and bumping it to 4096k: (gdb) print expr_copy_nest $1 = 87081 so we're dying from stack exhaustion, because expr_copy() is given a really nasty symbol: (gdb) print org $5 = (struct expr *) 0xba790fd0 (gdb) print *org $6 = {type = E_NOT, left = {expr = 0xba790fd0, sym = 0xba790fd0}, right = {expr = 0x0, sym = 0x0}} Reverting 246cf9c26bf11f2bffbecea6e5bd222eee7b1df8 fixes the crash. - Arnaud On Sun, Sep 19, 2010 at 12:56 AM, Arnaud Lacombe <lacombar@xxxxxxxxx> wrote: > Hi, > > I've been experiencing a use-after-free with the current kconfig (from > for-next, but I believe mainline is affected too), related to the > introduction of commit 246cf9c26bf11f2bffbecea6e5bd222eee7b1df8. The > symptoms with the attached test case and patch to highlight the > problem is the following: > > % scripts/kconfig/mconf Kconfig.testcase > [...] > Invalid expr 0xbb9124a0 at scripts/kconfig/menu.c:295 in > menu_finalize(): 41414141 > zsh: abort (core dumped) scripts/kconfig/mconf Kconfig.testcase > > The backtrace is not really surprising: > > #2 0xbbb9fbd6 in abort () from /usr/lib/libc.so.12 > #3 0x0804f23a in menu_finalize (parent=0xbb911e20) at > scripts/kconfig/menu.c:295 > #4 0x0804eb6d in menu_finalize (parent=0xbb911df0) at > scripts/kconfig/menu.c:292 > #5 0x0804f166 in menu_finalize (parent=0xbb911d60) at > scripts/kconfig/menu.c:320 > #6 0x0804eb6d in menu_finalize (parent=0xbb911c10) at > scripts/kconfig/menu.c:292 > #7 0x0804eb6d in menu_finalize (parent=0x8069ea0) at scripts/kconfig/menu.c:292 > #8 0x080535d7 in conf_parse (name=0x804aa61 "Ç\004$") at > scripts/kconfig/zconf.tab.c:2242 > #9 0x0804aa61 in main (ac=Cannot access memory at address 0x0 > > (gdb) frame 3 > #3 0x0804f23a in menu_finalize (parent=0xbb911e20) at > scripts/kconfig/menu.c:295 > 295 EXPR_CHECK(parent->dir_dep); > > So far, I tracked this issue down to the faulty expression being freed > by expr_eliminate_dups1() in the previous iteration of > menu_initialize(), on the following line > > basedep = expr_eliminate_dups(basedep); > > The testcase is a stripped down Kconfig from the tree. > > - Arnaud >
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index ccd6563..e2b7f01 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -63,12 +59,18 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; } +int expr_copy_nest = 0; + struct expr *expr_copy(struct expr *org) { struct expr *e; - if (!org) - return NULL; + expr_copy_nest++; + + if (!org) { + e = NULL; + goto bail_out; + } e = malloc(sizeof(*org)); memcpy(e, org, sizeof(*org)); @@ -97,6 +99,9 @@ struct expr *expr_copy(struct expr *org) break; } +bail_out: + expr_copy_nest--; + return e; }