3

My project is swift-only (for the code I wrote, at least). At the start of the app, I download some json to show content. I deserialize this content with swift 4 Coder protocol. This has worked for some time, but just now I got an unexpected stack-buffer-overflow error:

==44088==ERROR: AddressSanitizer: stack-buffer-overflow

while deserializing one of the objects, in one of the background threads.

Based on this, I have 2 questions:

How can I ensure this doesn't happen again?

Is there a way to reproduce it?

More info:

I have this summary, but I'm not sure what to make of it:

SUMMARY: AddressSanitizer: stack-buffer-overflow JsonClass.swift in _T06MyApp11JsonClassVACs7Decoder_p4from_tKcfC Shadow bytes around the buggy address: 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 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

EDIT:

It reproduced every time (in the simulator). Then I cleaned the build and deleted the derived data folder and it didn't happen since. I'd still like to know if I need to worry for a bug in production...

invalidArgument
  • 2,289
  • 4
  • 24
  • 35
  • I can't think of how cleaning and rebuilding would have actually fixed anything. When Asan trips it should pause in the debugger and provide the line it happens on and even the lines where the object was originally allocated. It sounds like you are passing a stack variable somewhere and using it after the frame is destroyed. – Brad Allred Jun 26 '18 at 17:40
  • it could also be trying to access a stack based array out of bounds. – Brad Allred Jun 26 '18 at 17:52
  • It happened during the deserialization of a json object, more specifically in the init method. I'm using a [technique](https://stackoverflow.com/a/48263781/873436) to allow deserialization of a polymorphic array of objects, based on one of its properties. – invalidArgument Jun 26 '18 at 19:06
  • still, nobody is going to be able to tell you much without code – Brad Allred Jun 26 '18 at 20:04
  • Sorry for my delay. I feel like there would be too much code for it to be worthwhile. Your thorough answer provides a lot of insights and I will look into the different solutions you suggest. Thank you! – invalidArgument Jun 27 '18 at 18:09

1 Answers1

12

First I'll briefly answer your questions

How can I ensure this doesn't happen again?

This specific defect you can fix and write unit tests for to prevent having a regression. In general, however, mistakes happen; you cannot prevent them, only mitigate them. Use tools and warnings to try and identify them early on. You are already doing a good thing by employing Address Sanitizer (you should also check out Undefined Behavior Sanitizer and Thread Sanitizer).

Is there a way to reproduce it?

Address Sanitizer will report it 100% of the time it happens. Unfortunately, it sounds like it depends on what data you are working with. Maybe try some malformed data to try and coax it into happening. You can write Unit Tests (be sure to build your tests with Asan enabled) with various types of data. Can't say more without seeing code.

What is the problem?

You definitely have a bug. Asan does not report false positives. It sounds like it might only happen for bad data, but you should never trust you will always have good data.

It is not easy to help you fix your problem without seeing code. Asan reporting a stack buffer overflow is usually one of these things (in my experience):

  1. Allocating a variable on the stack and keeping a reference to it. When the stack frame it was allocated in is destroyed the reference is no longer valid.
  2. Having an array on the stack and going out of bounds.
  3. (rarely) An improper cast of a stack object to an object larger size and accessing a "member" that is beyond the stack top.

If you are running though Xcode it should break when Asan aborts. you should be able to see the stack trace and find where in your code this is happening.

Additional tools to help identify the problem

  1. Compiler warnings

Turn these on and up as much as possible. Often when you do things like take a reference to something with automatic storage duration the compiler can warn you about it.

  1. Clang Static Analyzer

This is also built into Xcode and can be ran by the Product -> Analyize menu. This should populate issues it find in the "issue navigator" on the left column of Xcode. Clang is pretty good at identifying memory errors

Community
  • 1
  • 1
Brad Allred
  • 7,323
  • 1
  • 30
  • 49
  • 1
    In my case I ran into this error because I had defined 2 different classes with the same name but in different translation units. So at compile time there was nothing wrong, but at runtime the program used the other other equally named object which didn't have some member variables which the other class did have. – Ruurd Adema Feb 11 '22 at 09:11