Prueba de aplicaciones en condiciones de poca memoria

La cuestión de si es necesario comprobar qué retornos malloces controvertida y siempre genera un acalorado debate.



Algunas personas piensan que deberíamos intentar manejar todo tipo de errores de tiempo de ejecución, incluido. y situaciones OOM. Otros creen que todavía es poco lo que se puede hacer con OOM y que es mejor dejar que la aplicación se bloquee. Del lado del segundo grupo de personas, también está el hecho de que la lógica de procesamiento OOM adicional es difícil de probar. Y si el código no se prueba, es casi seguro que no funcione.



Estoy totalmente de acuerdo en que no debe implementar la lógica de manejo de errores que no va a probar. Es casi seguro que no mejorará nada, y tal vez incluso peor: arruinará todo.



La cuestión de si intentar o no manejar situaciones OOM en bibliotecas / aplicaciones es controvertida y no la tocaremos aquí. Como parte de esta publicación, solo quiero compartir mi experiencia de cómo puede probar la lógica implementada para manejar situaciones OOM en aplicaciones escritas en C / C ++. La conversación versará sobre los sistemas operativos Linux y macOS. Por varias razones, se omitirá Windows.



Introducción



Todos deseamos que OOM nunca sucedió, pero en la vida real esto no siempre es posible debido a las siguientes razones:



  • La RAM siempre es limitada.
  • SWAP no siempre está habilitado.
  • Las aplicaciones no siempre se comportan de manera adecuada y, a veces, intentan asignar cantidades de memoria grandes y poco realistas, lo que interfiere con ellas mismas y con los demás.
  • Todavía existen aplicaciones de 32 bits.
  • la sobrecomisión no siempre está habilitada.
  • El consumo de memoria se puede limitar usando ulimit, por ejemplo.
  • 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 en sí se prueba en Ubuntu (desde 14.04) y macOS (desde Sierra (10.12) y Xcode 8.3). Durante las pruebas, Overthrower intenta soltarse, entre otras cosas.
  • Si aparece un OOM real en el sistema, Overthrower hace todo lo posible para no caerse.



All Articles