名もなき未知

エンジニアリングとか、日常とかそういうのをまとめる場所。アクセス解析のためGAを利用、Googleに情報を送信しています。商品紹介のためAmazonアフィリエイトを利用、Amazonに情報を送信しています。記事に関しては私が書いていない引用文を除いて自由にご利用ください。

C++ コンパイラオプションメモ

qranch が終わると聞いたので、移してなかった記事を移植する

いわゆるプログラミングコンテストというものにたまに出ている者だが、実行速度の制約上、未だにこの世界ではC++が主流であり、C++の周辺技術を抑えておくことにより、効率的なデバッグ、コーディングができると私は考えている。

普段からDEBUGマクロ仕込むとかでやってきたが、なんかTL見ていたらいろいろ情報があって、この記事に至ったが、なんか別の方法があるよとツイッターで言われたので調べた。

環境

  • OS: MacOS 10.14.1
  • GCC: g++-8 (Homebrew GCC 8.2.0) 8.2.0

結論

こんな感じのalias貼ることにした。

alias g++='g++-8 -Wall -std=c++14 -fsanitize=undefined '
alias gg++='g++-8 -g -DDEBUG -Wall -std=c++14 -fsanitize=undefined,address '

もともとデバッグ時に出したいときだけ -DDEBUG を書いて、マクロに入れるようにしていたが、 -fsanitize を追加した。

経緯

配列外参照の検出のため、 -D_GLIBCXX_DEBUG 入れるか、あるいはソースコード上に定義するかしようとした。

だが、 -fsanitize と一緒に使おうとしたところ、どうもコンパイル時に大量のログが出てきて気持ちが悪くなってしまったので、ログがたくさんでない方法を回避しようとする。

そこで、 -fsanitize=undefined,address として、上記のマクロを消すとうまくいくことがわかった。

ちなみにオーバーフロー時のログはこんな感じ。

test.cpp:72:17: runtime error: signed integer overflow: 10000000 * 10000000 cannot be represented in type 'int'
276447232

ちなみに配列外の参照の際はこんな感じに出る。

=================================================================
==28518==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6040000003b8 at pc 0x000102fd95bf bp 0x7ffeecc26ea0 sp 0x7ffeecc26e98
WRITE of size 4 at 0x6040000003b8 thread T0
    #0 0x102fd95be in main test.cpp:7
    #1 0x7fff6a31c08c in start (libdyld.dylib:x86_64+0x1708c)

0x6040000003b8 is located 0 bytes to the right of 40-byte region [0x604000000390,0x6040000003b8)
allocated by thread T0 here:
    #0 0x1033673d0 in wrap__Znwm (libasan.5.dylib:x86_64+0x6e3d0)
    #1 0x102fda954 in __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) new_allocator.h:111
    #2 0x102fda75a in std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) alloc_traits.h:436
    #3 0x102fda67f in std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) stl_vector.h:296
    #4 0x102fda308 in std::_Vector_base<int, std::allocator<int> >::_M_create_storage(unsigned long) stl_vector.h:311
    #5 0x102fd9cb9 in std::_Vector_base<int, std::allocator<int> >::_Vector_base(unsigned long, std::allocator<int> const&) stl_vector.h:260
    #6 0x102fd9801 in std::vector<int, std::allocator<int> >::vector(unsigned long, std::allocator<int> const&) stl_vector.h:416
    #7 0x102fd9504 in main test.cpp:5
    #8 0x7fff6a31c08c in start (libdyld.dylib:x86_64+0x1708c)

SUMMARY: AddressSanitizer: heap-buffer-overflow test.cpp:7 in main
Shadow bytes around the buggy address:
  0x1c0800000020: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
  0x1c0800000030: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
  0x1c0800000040: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 07
  0x1c0800000050: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
  0x1c0800000060: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
=>0x1c0800000070: fa fa 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa
  0x1c0800000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0800000090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c08000000a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c08000000b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c08000000c0: 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
==28518==ABORTING
zsh: abort      ./test

今度からのデバッグ速度向上に役立つといいなと思う。

参照