==44088==错误:AddressSanitizer:堆栈缓冲区溢出

3
我的项目仅支持Swift(至少我所编写的代码如此)。在应用程序启动时,我下载一些JSON以显示内容。我使用Swift 4 Coder protocol反序列化此内容。这已经运作了一段时间,但现在我收到了一个意外的堆栈缓冲区溢出错误:==44088==ERROR: AddressSanitizer: stack-buffer-overflow,是在其中一个后台线程中反序列化对象时发生的。
基于此,我有两个问题:
1. 如何确保这不会再次发生? 2. 是否有一种方法可以重现它?
更多信息: 我有这个摘要,但我不确定该如何解释它:
SUMMARY: AddressSanitizer: stack-buffer-overflow JsonClass.swift in _T06MyApp11JsonClassVACs7Decoder_p4from_tKcfC 错误地址附近的影子字节: 0x100026a904d0: 00 02 f2 f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 0x100026a904e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a904f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a90500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a90510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x100026a90520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[f2]f2 0x100026a90530: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 00 00 0x100026a90540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a90550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a90560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x100026a90570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 影子字节图例(一个影子字节代表8个应用程序字节): 可寻址: 00 部分可寻址: 01 02 03 04 05 06 07 堆左边界红区: fa 已释放的堆区域: fd 栈左边界红区: f1 栈中间红区: f2 栈右边界红区: f3 返回后的栈: f5 范围之外使用的栈: f8 全局红区: f9 全局初始化顺序: f6 用户污染: f7 容器溢出: fc 数组cookie: ac 对象内部红区: bb ASan内部: fe 左alloca红区: ca 右alloca红区: cb

编辑:

在模拟器中每次都会出现这个问题。然后我清理了构建并删除了派生数据文件夹,从那以后就没有再出现了。但我仍然想知道是否需要担心生产环境中的错误。


我想不出清理和重建实际上如何修复任何问题。当Asan触发时,它应该在调试器中暂停,并提供它发生的行甚至是最初分配对象的行。听起来你正在将堆栈变量传递到某个地方,并在帧被销毁后使用它。 - Brad Allred
它也可能尝试访问基于堆栈的数组越界。 - Brad Allred
它发生在json对象反序列化期间,更具体地说是在init方法中。我正在使用一种技术,以允许基于其属性之一的多态对象数组的反序列化。 - invalidArgument
仍然,没有代码的情况下没有人能够告诉你很多。 - Brad Allred
抱歉回复晚了。我感觉代码太多了,不值得去做。你详细的回答提供了很多见解,我会研究你建议的不同解决方案。谢谢! - invalidArgument
2个回答

12

首先,我会简要回答你的问题。

如何确保这不会再次发生?

您可以修复此特定缺陷并编写单元测试以防止出现回归。但是,总的来说,错误是难以避免的;您只能减少它们的影响。使用工具和警告来尽早识别它们。您已经采用了Address Sanitizer(您还应该查看Undefined Behavior Sanitizer和Thread Sanitizer),这是一个好习惯。

有没有办法重现它呢?

如果发生了,Address Sanitizer将100%报告它。不幸的是,听起来像它取决于您正在处理的数据。可以尝试一些格式不正确的数据,以试图诱发它的发生。您可以编写各种数据类型的单元测试(请务必启用Asan构建您的测试)。没有看到代码之前无法给予更多帮助。

问题是什么?

您肯定有一个错误。Asan不会报告虚警。听起来可能只会在错误数据下发生,但您永远不应该信任您始终拥有正确的数据。

没有看到代码很难帮助您解决问题。在我的经验中,Asan报告堆栈缓冲区溢出通常只会发生以下情况之一:

  1. 在堆栈上分配变量并保留对它的引用。当分配它的堆栈帧被销毁时,引用将不再有效。
  2. 在堆栈上有一个数组并越界访问。
  3. (很少见)将堆栈对象不当地强制转换为更大的对象大小,并访问超出堆栈顶部的“成员”。

如果您正在运行Xcode,则应在Asan中断时中断。您应该能够看到堆栈跟踪并找到代码中发生此情况的位置。

其他帮助识别问题的工具

  1. 编译器警告

打开并尽可能多地增加这些警告。通常,当您对具有自动存储期的某些内容进行引用时,编译器可以对其发出警告。

  1. Clang静态分析器

这也内置于Xcode中,可以通过Product-> Analyize菜单运行。这应该会在Xcode的左列“问题导航器”中填充它发现的问题。 Clang非常擅长识别内存错误。


1
在我的情况下,我遇到了这个错误,因为我定义了两个不同的类,但是它们的名称相同,但位于不同的翻译单元中。因此,在编译时没有任何问题,但在运行时,程序使用了另一个同名对象,该对象没有其他类具有的某些成员变量。 - Ruurd Adema

-1
31==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcfa87e770 

at pc 0x000000344049 bp 0x7ffcfa87e6b0 sp 0x7ffcfa87e6a8

READ of size 1 at 0x7ffcfa87e770 thread T0

    #3 0x7f35b846e0b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

Address 0x7ffcfa87e770 is located in stack of thread T0 at offset 80 in frame

这个框架有3个对象:

[32, 33) 'ref.tmp'

[48, 80) 'agg.tmp' <== Memory access at offset 80 overflows this variable

[112, 144) 'agg.tmp8'

提示:如果您的程序使用了一些自定义堆栈、取消机制、swapcontext 或 vfork,则这可能是一个错误的正面。
  (longjmp and C++ exceptions *are* supported)

错误地址周围的影子字节:

  0x10001f507c90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507cc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

=>0x10001f507ce0: 00 00 00 00 f1 f1 f1 f1 01 f2 00 00 00 00[f2]f2

  0x10001f507cf0: f2 f2 00 00 00 00 f3 f3 f3 f3 f3 f3 00 00 00 00

  0x10001f507d00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1

  0x10001f507d10: 04 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10001f507d30: 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

  Shadow gap:  cc

==31==ABORTING

我在力扣(LeetCode)中也遇到了同样的问题。


如果你有问题,应该把它作为一个问题发布,而不是作为一个答案。 - Nathan Mills

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接