低メモリ状態でのアプリケーションのテスト

何が返ってくるのかをチェックする必要があるかどうかという問題mallocは議論の余地があり、常に白熱した議論を引き起こします



一部の人々は、私たちがあらゆる種類のランタイムエラーを処理しようとすべきだと考えています。とOOMの状況。他の人は、OOMでできることはまだほとんどないと信じており、アプリケーションをクラッシュさせる方がよいでしょう。2番目のグループの人々の側では、追加のOOM処理ロジックをテストするのが難しいという事実もあります。そして、コードがテストされていない場合、それはほぼ確実に機能しません。



テストしないエラー処理ロジックを実装するべきではないことに完全に同意します。それはほぼ確実に何も改善しないでしょう、あるいはさらに悪いことに、それはすべてを台無しにするでしょう。



ライブラリ/アプリケーションでOOMの状況を処理しようとするかどうかの問題は議論の余地があるため、ここでは触れません。この出版物の一部として、C / C ++で記述されたアプリケーションでOOM状況を処理するために実装されたロジックをテストする方法の私の経験を共有したいと思います。会話はLinuxとmacOSオペレーティングシステムについてです。いくつかの理由で、Windowsはバイパスされます。



前書き



OOMが発生しないことを私たちは皆望んでいますが、実際には、次の理由により、これが常に可能であるとは限りません。



  • RAMは常に制限されています。
  • SWAPが常に有効になっているとは限りません。
  • アプリケーションは常に適切に動作するとは限らず、非現実的に大量のメモリを割り当てようとして、アプリケーション自体や他のアプリケーションに干渉することがあります。
  • 32ビットアプリケーションはまだ存在します。
  • オーバーコミットは常に有効になっているわけではありません。
  • ulimitたとえば、を使用してメモリ消費を制限できます
  • LD_PRELOAD .


, , , OOM . , , :



  • , - .
  • OOM . .
  • . , .


, , SQLite. , . . SQLite .



, , , . OOM Killer, , . , C++, .



1.



, OOM . my_malloc my_free malloc free.



my_free . my_realloc.



my_malloc malloc . my_malloc , NULL .



, :



  • 3rd party .
  • malloc . - strdup.
  • malloc’ , , .
  • C++ malloc free.


- .



2.



Linux LD_PRELOAD. . malloc. , malloc/realloc/free (weak). , macOS LD_PRELOAD, DYLD_INSERT_LIBRARIES.



, , LD_PRELOAD DYLD_INSERT_LIBRARIES malloc/realloc NULL .



, "" . , .



, "" , , . :



  • main. , .
  • Runtime macOS " ". , , , .
  • printf macOS SIGSEGV/SIGBUS.
  • , std::bad_alloc, . , , , OOM. std::terminate. .
  • std::thread std::terminate macOS.


UPDATE: Travis CI , macOS / Xcode , std::bad_alloc , std::thread std::terminate.



Overthrower. - malloc NULL. Overthrower - , .



3.



main



, main , main runtime . main, , .. - main.



, main . Overthrower, OOM . Overthrower , .



:



  • activateOverthrower
  • deactivateOverthrower


:



#ifdef __cplusplus
extern "C" {
#endif
void activateOverthrower() __attribute__((weak));
unsigned int deactivateOverthrower() __attribute__((weak));
#ifdef __cplusplus
}
#endif


.



Overthrower LD_PRELOAD, NULL, , .



, , :



int main(int argc, char** argv)
{
    activateOverthrower();
    // Some code we want to test ...
    deactivateOverthrower();
}


activateOverthrower/deactivateOverthrower , :



TEST(Foo, Bar)
{
    activateOverthrower();
    // Some code we want to test ...
    deactivateOverthrower();
}


, -, , Overthrower , :



#ifdef __cplusplus
extern "C" {
#endif
void pauseOverthrower(unsigned int duration) __attribute__((weak));
void resumeOverthrower() __attribute__((weak));
#ifdef __cplusplus
}
#endif


:



TEST(Foo, Bar)
{
    activateOverthrower();
    // Some code we want to test ...
    pauseOverthrower(0);
    // Some fragile code we can not fix ...
    resumeOverthrower();
    // Some code we want to test ...
    deactivateOverthrower();
}


Overthrower .





__cxa_allocate_exception, , , malloc, NULL. , Linux, malloc, __cxa_allocate_exception (emergency buffer), , . .



macOS , , , , std::bad_alloc, std::terminate.



UPDATE: , macOS / Xcode .



, , , __cxa_allocate_exception malloc. - Overthrower’ malloc. Overthrower malloc __cxa_allocate_exception.



, , , macOS __cxa_atexit, Linux dlerror. .



Overthrower , malloc free. Overthrower’ , activateOverthrower deactivateOverthrower , :



overthrower got deactivation signal.
overthrower will not fail allocations anymore.
overthrower has detected not freed memory blocks with following addresses:
0x0000000000dd1e70  -       2  -         128
0x0000000000dd1de0  -       1  -         128
0x0000000000dd1030  -       0  -         128
^^^^^^^^^^^^^^^^^^  |  ^^^^^^  |  ^^^^^^^^^^
      pointer       |  malloc  |  block size
                    |invocation|
                    |  number  |


Overthrower , , .



Overthrower’, , valgrind. , OOM. , , Overthrower . Overthrower , , deactivateOverthrower , stderr .





Overthrower 3 :



  • Random — rand() % duty_cycle == 0. duty_cycle, .
  • Step — (malloc_seq_num >= delay), delay .


<--- delay --->
--------------+
              |
              | All further allocations fail
              |
              +------------------------------


  • Pulse — (malloc_seq_num > delay && malloc_seq_num <= delay + duration), delay duration .


<--- delay --->
--------------+                +------------------------------
              |                |
              |                | All further allocations pass
              |                |
              +----------------+
              <--- duration --->


:



  • OVERTHROWER_STRATEGY
  • OVERTHROWER_SEED
  • OVERTHROWER_DUTY_CYCLE
  • OVERTHROWER_DELAY
  • OVERTHROWER_DURATION


activateOverthrower. , Overthrower , /dev/urandom.



README.md.





  • Overthrower malloc /.
  • .
  • Overthrower .
  • Overthrower .
  • Overthrower , .
  • Overthrower’ .
  • Overthrower Overthrower-aware . , .
  • Overthrower自体は、Ubuntu(14.04以降)およびmacOS(Sierra(10.12)およびXcode 8.3以降)でテストされています。テスト中、Overthrowerは自分自身をドロップしようとします。
  • 実際のOOMがシステムに表示された場合、Overthrowerは自分自身に落ちないように可能な限りのことを行います。



All Articles