Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

[bug] apply_reg_state may crash on entering and exiting stack frames on Aarch64

Abierto
#792 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 4 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
8/100
Tipo de issue
Error
Claridad
Necesita aclaración
Estado de actividad
Estancado
Stack tecnológico
c

Línea de trabajo

The crash is in apply_reg_state in src/dwarf/Gparser.c, where the return-address slot is dereferenced via dwarf_get on c->loc[rs->ret_addr_column]. Start by reading how find_reg_state and the CFA computation feed that location, and check the aarch64 signal-frame handling in the libunwind source. Done would mean the cursor walks past the sigreturn frame without reading an unmapped address, which the reporter could not reproduce in a minimal case.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

aarch64 bug

Environment

  • libunwind version: master (2024-07-23 14:17 e3f88e8e)
  • architecture: Aarch64 - ARMv8 Processor rev 1 (v8l)
  • OS: Nvidia Orin Drive system - Ubuntu 20.04.5 LTS
  • crossing-compiled using clang 8.0.1-9 from x86_64-pc-linux-gnu platform
  • here's my config.h: I disabled libgcc mode and enabled UNW_LOCAL_ONLY. libunwind_config.zip

Description

  • In src/dwarf/Gparser.c, apply_reg_state calls dwarf_get (c, c->loc[rs->ret_addr_column], &ip);.
  • But in some rare cases c->loc[rs->ret_addr_column] may be wrong and point to unmapped memory, like 0x18 or 0xd555...555d
  • Then it can crash on dereferencing the pointer.

Reproduction Steps

Background: I want to use cpu-profiler in gperftools 2.15 to collect CPU performance data, but it almost always crashes at apply_reg_state.

During my tests, libunwind often fails to get a correct "next CFA / next IP" in its apply_reg_state, especially for the below function (see the snapshot below - sorry I can not provide a minimized reproducer):

  • malloc is a customized wrapper which calls jemalloc and and replaces the default one in glibc
  • libunwind gets wrong CFA / IP if SIGPERF hits 0xa163194, 0xa163198, 0xa16319c and 0xa163250
    • once a CFA is wrong, it often reports more wrong IPs on further unw_step, or just reports a same IP and then stops with some errors.
  • sometimes libunwind fails on triggering SIGPERF at a few other functions
    • their IP can be something like 0xffff993160ac
    • usually the malloc function are called from operator new () at an address of 0xffff9f3eab4c
    • sorry but I don't know how to dump ASM code of such sections
  • FYI, during the test above, 0xffff9f58f7c0 is the IP of a sigreturn frame

I've noticed that all the IPs of my customized malloc share a same keypoint - their LR, SP and stack values do not "match".
But I know little about DWARF, and although I spent tens of hours on src/dwarf/ I still failed when tried to understand what find_reg_state does.

image

My tests and logs

I compiled libunwind by myself, so that I may add syscall(SYS_write) to log something and debug it. Here is the crashing scene:

[gperf] ==== start get stack trace ====
[step] input: child-cfa=0xfffde41c31d0 , ip=0x4cc0c7c , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c3dd0) + 16
 > 0xfffde41c31d8 [30] = 0xfffde41c3b58
  - [30]: where[]=CFAREL ; 0xfffde41c3dd8 == (new-cfa=0xfffde41c3de0) + -8, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c3dd8
[step] input: child-cfa=0xfffde41c3de0 , ip=0x4cc05c8 , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c3e10) + 16
 > 0xfffde41c31d8 [30] = 0xfffde41c3dd8
  - [30]: where[]=CFAREL ; 0xfffde41c3e18 == (new-cfa=0xfffde41c3e20) + -8, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c3e18
[step] input: child-cfa=0xfffde41c3e20 , ip=0x4cbf50c , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c4740) + 16
 > 0xfffde41c31d8 [30] = 0xfffde41c3e18
  - [30]: where[]=CFAREL ; 0xfffde41c4748 == (new-cfa=0xfffde41c4750) + -8, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c4748
[step] input: child-cfa=0xfffde41c4750 , ip=0x4cbc494 , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c4790) + 16
 > 0xfffde41c31d8 [30] = 0xfffde41c4748
  - [30]: where[]=CFAREL ; 0xfffde41c4798 == (new-cfa=0xfffde41c47a0) + -8, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c4798
[step] input: child-cfa=0xfffde41c47a0 , ip=0xffff9f58f7c0 , ip.is_signal_frame=1
[step] input: child-cfa=0xfffde41c5a00 , ip=0xa16319c , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=31 , regnum=31 , ret=0 , (cfa=0xfffde41c5a00) + 0
 > 0xfffde41c31d8 [30] = 0xfffde41c49c8
  - [30]: where[]=1 ; 0xfffde41c49c8 == (new-cfa=0xfffde41c5a00) + 0, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c49c8
[step] input: child-cfa=0xfffde41c5a00 , ip=0xffff9f3eab4c , ip.is_signal_frame=0
 - cfa @ sp := (c->cfa=0xfffde41c5a00) + 32
 > 0xfffde41c31d8 [30] = 0xfffde41c49c8
  - [30]: where[]=CFAREL ; 0xfffde41c5a08 == (new-cfa=0xfffde41c5a20) + -24, cfa_type=3
 << ip . operator& () = loc[30] = 0xfffde41c5a08
[step] input: child-cfa=0xfffde41c5a20 , ip=0xa144544 , ip.is_signal_frame=0
 - cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0x8) + 16
 > 0xfffde41c31d8 [30] = 0xfffde41c5a08
  - [30]: where[]=CFAREL ; 0x10 == (new-cfa=0x18) + -8, cfa_type=3
 << ip . operator& () = loc[30] = 0x10
*** SIGSEGV received at time=1722648362 on cpu 2 ***
PC: @          0x4cc6c38  (unknown)  apply_reg_state
    @          0x9f5b404        208  absl::lts_20230125::WriteFailureInfo()
    @          0x9f5b118         64  absl::lts_20230125::AbslFailureSignalHandler()
    @     0xffff9f58f7c0       5952  (unknown)
    @          0x4cc65f4       2048  _ULaarch64_dwarf_step
    @          0x4cc5b78        384  _ULaarch64_step
    @          0x4cc0ce8       3088  GetStackTraceWithContext_libunwind()
    @          0x4cc05c8         64  GetStackTraceWithContext()
    @          0x4cbf50c       2352  CpuProfiler::prof_handler()
    @          0x4cbc494         80  ProfileHandler::SignalHandler()
    @     0xffff9f58f7c0       4704  (unknown)
    @     0xffff9f3eab4c         64  operator new()
    @          0xa02acb4         48  google::protobuf::Arena::CreateMaybeMessage<>()
    @          0x5b644ec         64  google::protobuf::internal::RepeatedPtrFieldBase::MergeFromInnerLoop<>()

Explain:

  • [step] input above is logged in unw_step and just next to unw_is_signal_frame(cursor)
  • cfa @ ... is logged in src/dwarf/Gparser.c#apply_reg_state
  • [30]: where is in the switch(reg.where[i])) of apply_reg_state
    image
    image
Lenguaje dominante
C
Estrellas
1.3k
Forks
353
Merge medio
3 d 19 h
PR fusionados (30 d)
11

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de libunwind/libunwind

Todos los issues de libunwind/libunwind

Issues similares

Más issues de C

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.