You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确解读AddressSanitizer报错?C++跨平台服务端内存排查

客户端-服务端程序跨平台ASan报错排查与修复

问题背景

用C++(包含大量C风格代码)编写的小型客户端-服务端程序,在macOS上通过AddressSanitizer(ASan)编译运行无报错,但在Ubuntu Docker环境执行测试时触发ASan报错。ASan提示线程T1对线程T0栈帧中偏移192的newsockfd变量(对应代码第59行)执行非法读操作,但该行代码size_t newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);无明显语法异常。

ASan完整报错日志

# ./single_client.sh
clang -shared -fPIC -ldl -O3 -o monkey.so monkey.c
clang++ single_client.cpp -std=c++17 -g -O3 -Werror -Wall -Wextra -pthread -pedantic -o single_client
clang++ multiple_client.cpp -std=c++17 -g -O3 -Werror -Wall -Wextra -pthread -pedantic -o multiple_client
clang++ random_clients.cpp -std=c++17 -g -O3 -Werror -Wall -Wextra -pthread -pedantic -o random_clients
clang++ simple_server.cpp -std=c++17 -g -O3 -Werror -Wall -Wextra -pthread -pedantic -o simple_server
clang++ server.cpp -std=c++17 -g -O3 -g -fsanitize=address -Werror -Wall -Wextra -pthread -pedantic -o server
clang++ client.cpp -std=c++17 -g -O3 -g -fsanitize=address -Werror -Wall -Wextra -pthread -pedantic -o client
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
[TEST] Send
[TEST] Human readeable: 4 alex
[TEST] Send binary hex: 
00000004 616c6578
[TEST] Send
[TEST] Human readeable: 11 hello world
[TEST] Send binary hex: 
0000000b 68656c6c 6f20776f 726c64
[TEST] Read
=================================================================
==61==ERROR: AddressSanitizer: unknown-crash on address 0xffffd05639c0 at pc 0x00000050a6a4 bp 0xffffabcfe8f0 sp 0xffffabcfe908
READ of size 8 at 0xffffd05639c0 thread T1
    #0 0x50a6a3  (/mess/my_data/artifacts/server+0x50a6a3)
    #1 0xffffaf87d087  (/lib/aarch64-linux-gnu/libpthread.so.0+0x7087)

Address 0xffffd05639c0 is located in stack of thread T0 at offset 192 in frame
    #0 0x50a07b  (/mess/my_data/artifacts/server+0x50a6a3)

  This frame has 6 object(s):
    [32, 36) 'clilen' (line 24)
    [48, 64) 'serv_addr' (line 25)
    [80, 96) 'cli_addr' (line 25)
    [112, 160) 'm1' (line 27)
    [192, 200) 'newsockfd' (line 59) <== Memory access at offset 192 is inside this variable
    [224, 232) 'thread' (line 61)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: unknown-crash (/mess/my_data/artifacts/server+0x50a6a3) 
Shadow bytes around the buggy address:
  0x200ffa0ac6e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac6f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac720: f1 f1 f1 f1 04 f2 00 00 f2 f2 00 00 f2 f2 00 00
=>0x200ffa0ac730: 00 00 00 00 f2 f2 f2 f2[00]f2 f2 f2 f8 f3 f3 f3
  0x200ffa0ac740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ffa0ac780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
Thread T1 created by T0 here:
    #0 0x4441ab  (/mess/my_data/artifacts/server+0x4441ab)
    #1 0x50a33f  (/mess/my_data/artifacts/server+0x50a33f)
    #2 0xffffaf6ed79f  (/lib/aarch64-linux-gnu/libc.so.6+0x2079f)
    #3 0x41f697  (/mess/my_data/artifacts/server+0x41f697)

==61==ABORTING
terminate called after throwing an instance of 'std::runtime_error'
  what():  could not read message from server: Connection reset by peer
single_client_impl.sh: line 23:    63 Aborted                 ./simple-messanger-tests/src/single_client 8081
single_client_impl.sh: line 1: kill: (61) - No such process

字节地址定位错误位置的方法

  • 用addr2line工具:在Docker环境中执行addr2line -e server 0x50a6a3,直接将内存地址映射到代码行(编译时已添加-g调试选项,满足工具要求)
  • 用gdb调试:运行gdb ./server,执行break *0x50a6a3设置断点,启动程序触发报错后,用bt命令查看完整调用栈,定位具体代码位置

报错成因分析

  • 核心问题:线程T1访问了线程T0的栈变量newsockfd,但T0的栈帧可能已被销毁(比如T0创建T1后退出了当前函数,栈内存被系统回收或覆盖)
  • 典型场景:创建线程T1时,将T0栈上的newsockfd地址作为参数传递给T1,但T0后续退出函数,栈内存失效,T1再访问就触发非法读操作
  • 跨平台差异原因:macOS与Linux的栈内存管理策略不同,macOS可能未立即回收栈帧内存,或者ASan在macOS上的检测阈值更宽松,导致问题未被触发

修复建议

  • 内存生命周期调整:将newsockfd从栈变量改为堆分配(用malloc/new),传递指针给线程T1,待线程执行完毕后再释放内存,确保生命周期覆盖线程运行周期
  • 线程同步保障:修改逻辑,确保T0在T1完成所有操作后再退出当前函数,保证栈变量在T1运行期间始终有效
  • 参数传递检查:检查第61行的线程创建代码,确认传递给线程的参数是否为栈上临时变量,若存在此类情况,替换为全局变量或堆分配变量

内容的提问来源于stack exchange,提问作者student422

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:41:26