How to use backtrace() safely in signal handler.
Adhemerval Zanella
adhemerval.zanella@linaro.org
Fri Dec 6 17:24:00 GMT 2019
On 05/12/2019 23:47, Paul Guo wrote:
> On Thu, Dec 5, 2019 at 10:35 PM Florian Weimer <fweimer@redhat.com> wrote:
>
>> * Paul Guo:
>>
>>> 1. what is "init" in the AS-Unsafe words? It is not explained in the
>> above
>>> URL.
>>
>> I think it refers to the first call which performs initialization.
>>
>>> 2. heap
>>>
>>> The doc says "Functions marked with heap may call heap memory management
>>> functions from the malloc/free family of functions and are only as safe
>> as
>>> those functions"
>>
>> If objects have GNU-style unwinding data and nothing calls
>> __register_frame_info, the libgcc unwinder will not use malloc AFAICS.
>> But I'm not entirely sure what this annotation is about.
>>
>>> But https://sourceware.org/ml/libc-alpha/2015-02/msg00659.html
>>> <https://sourceware.org/ml/libc-alpha/2015-02/msg00659.html>says
>>> backtrace() trigger malloc() only when dynamically loading libgcc. Does
>>> that mean if libgcc was preloaded in the application we do not need to
>>> worry about that?
>>
>> This no longer applies to current glibc for a whole bunch of reasons.
>>
>
> OK. Do you mean with current glibc, if a program is calling malloc() and
> gets a signal,
> and if the signal handler calls backtrace(), backtrace() won't be safe?
Yes, dlopen on generic backtrace.c will call malloc and glibc malloc
implementation is not async-signal-safe.
>
>
>>> 2. dlopen: preloading libgcc could work around this limitation, right?
>>
>> No, libgcc_s calls _dl_iterate_phdr, which needs the loader lock. I'm
>> guessing the annotation refers to that.
>>
>>> 3. plugin: I do not know how backtrace() is affected by this but it seems
>>> that it does not affect backtrace()?
>>
>> It refers to libgcc_s. libgcc_s has its own locking to support
>> __register_frame_info, but it is skipped if nothing calls this function.
>> It does however rely on the loader lock via _dl_iterate_phdr.
>>
>>> 4. lock: I've seen a self deadlock (in backtrace()) case in my
>> environment
>>> (backtrace()-ing in one signal handler and then gets another signal and
>>> that signal handler calls backtrace() again). The lock should
>>> be __gthread_mutex_lock. For this we could use a wrapper of backtrace()
>> to
>>> prevent reentrance of backtrace() to work around this issue (Yes of
>> course
>>> the final backtrace() will return nothing but this scenario is rare so it
>>> should be fine, right?).
>>
>> With __register_frame_info, you can get other deadlocks on the internal
>> libgcc unwinder lock.
>>
>> Nowadays, the loader write lock is recursive, so if the signal handler
>> interrupts certain dynamic loader operations, there won't be a deadlock
>> due to _dl_iterate_phdr, but you could get crashes because the signal
>> handler observes a temporarily corrupted list.
>>
>> To fix this, we would have to change the dynamic linker to provide an
>> async-signal-safe function which returns the loaded object for an
>> address and its unwinding data. Then we'd have to patch libgcc_s to use
>> that, in preference of its own caches. This would be useful for C++
>> code which wants to catch exceptions in an asynchronous signal handler,
>> without letting them escape from the signal handler.
>>
>>
> OK. Can I summarize like this after reading replies for questions 2 & 3 & 4:
>
> If the application is preloading some libraries, then if it gets a signal
> and then
> backtrace() in the signal handler won't not safe. Other signal unsafe issues
> include 1) reentrance of backtrace() due to various possible locks or even
> data
> corruption. 2) the "heap" issue(If I understand correctly. See reply above),
> In other cases backtrace() is ok as a signal handler?
If you mean by 'preloading' the concept that if the thread issue
dlopen, dlclose, or dlmopen then yes, dl_iterate_phdr will see corrupted
data. The reentracy of backtrace() is essentially the same reentracy
issue for malloc and dl_iterate_phdr. Another possible issue is a stack
overflow on signal handler due calling backtrace itself (due dlopen and/or
libgcc calls).
These are the known issues with backtrace on signal handler.
>
> If this is just for a crash reporter, you really need to move this
>> out-of-process because in-process crash handlers will always be prone to
>> deadlocks and can obscure the actual source of the crash.
>>
>
> What is the usual "out-of-process" practice?
> /proc/sys/kernel/core_pattern + abrt kind of configuration (take
> rhel/centos distribution as an example)?
The abrt afaik just setup and handle the generated core file by
configuring the system required parameters. You will still need
a tool to read and process the core file, gdb for instance.
>
> Thanks you and Carlos (previous replier) for response. -- Paul
>
More information about the Libc-help
mailing list