Skip to content

Tip: Debugging Memory Bugs (Only for macOS and Linux)

Wonsup Yoon edited this page Nov 2, 2021 · 1 revision

In KENS, which is a C++-based project, memory bugs are one of the major sources of failures (segmentation fault, data race, memory corruption, etc.). However, fixing memory bugs is not an easy task even for experienced programmers.

KENS provides an address sanitizer option for memory debugging (only for macOS/Linux).

You can try address sanitizer using the below instructions.

$ mkdir build && cd build
$ cmake -DSANITIZER=address ..
$ make -j
$ ./app/kens/kens-part1

If there is a memory bug, address sanitizer prints like below. You can use this output (stack traces, address) to debug memory bugs.

=================================================================
==12125==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000006d8 at pc 0x00010c4db291 bp 0x7ff7b3aa3390 sp 0x7ff7b3aa3388
READ of size 4 at 0x6020000006d8 thread T0
    #0 0x10c4db290 in E::TCPAssignment::initialize() TCPAssignment.cpp:27
    #1 0x10c4775d1 in E::Host::initializeHostModule(char const*) E_Host.hpp:409
    #2 0x10c460bf7 in TestEnv1<E::TCPAssignmentProvider>::SetUp() testenv.hpp:139
    #3 0x10c6d69bd in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) gtest.cc:2433
    #4 0x10c64f028 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) gtest.cc:2469
    #5 0x10c64e961 in testing::Test::Run() gtest.cc:2503
    #6 0x10c6518cb in testing::TestInfo::Run() gtest.cc:2684
    #7 0x10c654038 in testing::TestSuite::Run() gtest.cc:2816
    #8 0x10c672342 in testing::internal::UnitTestImpl::RunAllTests() gtest.cc:5338
    #9 0x10c6e55a5 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) gtest.cc:2433
    #10 0x10c671292 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) gtest.cc:2469
    #11 0x10c670d1c in testing::UnitTest::Run() gtest.cc:4925
    #12 0x10c628610 in RUN_ALL_TESTS() gtest.h:2473
    #13 0x10c628584 in main gtest_main.cc:45
    #14 0x1142794fd in start+0x1cd (dyld:x86_64+0x54fd)

0x6020000006d8 is located 4 bytes to the right of 4-byte region [0x6020000006d0,0x6020000006d4)
allocated by thread T0 here:
    #0 0x10cf734c0 in wrap_malloc+0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x484c0)
    #1 0x10c4db235 in E::TCPAssignment::initialize() TCPAssignment.cpp:26
    #2 0x10c4775d1 in E::Host::initializeHostModule(char const*) E_Host.hpp:409
    #3 0x10c460bf7 in TestEnv1<E::TCPAssignmentProvider>::SetUp() testenv.hpp:139
    #4 0x10c6d69bd in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) gtest.cc:2433
    #5 0x10c64f028 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) gtest.cc:2469
    #6 0x10c64e961 in testing::Test::Run() gtest.cc:2503
    #7 0x10c6518cb in testing::TestInfo::Run() gtest.cc:2684
    #8 0x10c654038 in testing::TestSuite::Run() gtest.cc:2816
    #9 0x10c672342 in testing::internal::UnitTestImpl::RunAllTests() gtest.cc:5338
    #10 0x10c6e55a5 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) gtest.cc:2433
    #11 0x10c671292 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) gtest.cc:2469
    #12 0x10c670d1c in testing::UnitTest::Run() gtest.cc:4925
    #13 0x10c628610 in RUN_ALL_TESTS() gtest.h:2473
    #14 0x10c628584 in main gtest_main.cc:45
    #15 0x1142794fd in start+0x1cd (dyld:x86_64+0x54fd)

SUMMARY: AddressSanitizer: heap-buffer-overflow TCPAssignment.cpp:27 in E::TCPAssignment::initialize()
Shadow bytes around the buggy address:
  0x1c0400000080: fa fa fd fa fa fa 00 00 fa fa fd fd fa fa fd fa
  0x1c0400000090: fa fa 00 00 fa fa fd fd fa fa fd fd fa fa fd fa
  0x1c04000000a0: fa fa 00 00 fa fa fd fd fa fa fd fd fa fa fd fd
  0x1c04000000b0: fa fa fd fa fa fa 00 00 fa fa fd fd fa fa fd fd
  0x1c04000000c0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
=>0x1c04000000d0: fa fa fd fd fa fa fd fd fa fa 04[fa]fa fa fa fa
  0x1c04000000e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c04000000f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0400000120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==12125==