> On Feb 5, 2025, at 07:46, Richard Biener <richard.guent...@gmail.com> wrote: > > On Tue, Feb 4, 2025 at 10:12 PM Qing Zhao <qing.z...@oracle.com> wrote: >> >> Hi, >> >> One of our big application segv in libgcc code while unwinding the stack. >> >> This is a random crash while the application throws a c++ exception and >> unwinds the stack. Incidents are random and never can be reproduced by any >> test case. >> >> The libgcc that is used is based on GCC 8. >> >> Fortunately, we got some information through the stack trace, and narrowed >> down the crash is in the routine "init_object" of libgcc/unwind-dw2-pde.c: >> >> 777 count = classify_object_over_fdes (ob, ob->u.single); >> >> when loading the 2nd parameter of the call to "classify_object_over_fdes". >> i.e, the address that is pointed by "ob->u.single" is invalid. >> >> And the outer caller we can track back is the following line 1066 of the >> routine >> "_Unwind_Find_FDE": >> >> 1060 /* Classify and search the objects we've not yet processed. */ >> 1061 while ((ob = unseen_objects)) >> 1062 { >> 1063 struct object **p; >> 1064 >> 1065 unseen_objects = ob->next; >> 1066 f = search_object (ob, pc); >> >> Then we suspected that the construction of the static variable >> "unseen_objects" >> might have some bug. >> >> Then after studying the source code that constructs "unseen_objects" in >> libgcc/unwind-dw2-pde.c, I found an issue in the routines "__register_frame" >> and "__register_frame_table" as following: >> >> 127 void >> 128 __register_frame (void *begin) >> 129 { >> 130 struct object *ob; >> 131 >> 132 /* If .eh_frame is empty, don't register at all. */ >> 133 if (*(uword *) begin == 0) >> 134 return; >> 135 >> 136 ob = malloc (sizeof (struct object)); >> 137 __register_frame_info (begin, ob); >> 138 } >> >> 181 void >> 182 __register_frame_table (void *begin) >> 183 { >> 184 struct object *ob = malloc (sizeof (struct object)); >> 185 __register_frame_info_table (begin, ob); >> 186 } >> 187 >> >> In the above, one obvious issue in the source code is at line 136, line 137, >> and line 184 and line 185: the return value of call to "malloc" is not >> checked >> against NULL before it was passed as the second parameter of the follwoing >> call. >> >> This might cause unpredicted random behavior. >> >> I checked the latest trunk GCC libgcc, the same issue is there too. >> >> This patch is for the latest trunk GCC. >> >> Please let me know any comments on this? > > I think I've seen this elsewhere —
Do you mean that you saw this problem (malloc return NULL during register_frame) previously? > the issue is the unwind register API does > not allow for failures but I also think calling abort() is bad. Okay, I see. > > Are you calling this from a JIT context or so? I will ask the bug submitter on this to make sure. > We're assuming that at program > start malloc() will not fail. So, the routine __register_frame is only called at the _start_ of a program? > > The proper solution is probably to add an alternate ABI which has a way to > fail > during registration. Any suggestion on this (or any other routine I can refer to?) Thanks a lot for the help. Qing > > Richard. > >> thanks. >> >> Qing >> >> >> ======================= >> >> Fix two issues in libgcc/unwind-dw2-fde.c: >> >> A. The returned value of call to malloc is not checked against NULL. >> This might cause unpredicted behavior during stack unwinding. >> >> B. Check for null begin parameter (as well as pointer to null) in >> __register_frame_info_table_bases and __register_frame_table. >> >> libgcc/ChangeLog: >> >> * unwind-dw2-fde.c (__register_frame): Check the return value of call >> to malloc. >> (__register_frame_info_table_bases): Check for null begin parameter. >> (__register_frame_table): Check the return value of call to malloc, >> Check for null begin parameter. >> --- >> libgcc/unwind-dw2-fde.c | 12 ++++++++++++ >> 1 file changed, 12 insertions(+) >> >> diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c >> index cdfd3974c99..f0bc29d682a 100644 >> --- a/libgcc/unwind-dw2-fde.c >> +++ b/libgcc/unwind-dw2-fde.c >> @@ -169,6 +169,8 @@ __register_frame (void *begin) >> return; >> >> ob = malloc (sizeof (struct object)); >> + if (ob == NULL) >> + abort (); >> __register_frame_info (begin, ob); >> } >> >> @@ -180,6 +182,10 @@ void >> __register_frame_info_table_bases (void *begin, struct object *ob, >> void *tbase, void *dbase) >> { >> + /* If .eh_frame is empty, don't register at all. */ >> + if ((const uword *) begin == 0 || *(const uword *) begin == 0) >> + return; >> + >> ob->pc_begin = (void *)-1; >> ob->tbase = tbase; >> ob->dbase = dbase; >> @@ -210,7 +216,13 @@ __register_frame_info_table (void *begin, struct object >> *ob) >> void >> __register_frame_table (void *begin) >> { >> + /* If .eh_frame is empty, don't register at all. */ >> + if (*(uword *) begin == 0) >> + return; >> + >> struct object *ob = malloc (sizeof (struct object)); >> + if (ob == NULL) >> + abort (); >> __register_frame_info_table (begin, ob); >> } >> >> -- >> 2.31.1