La question de savoir s'il est nécessaire de vérifier quels retours malloc
est controversée et suscite toujours un débat animé.
Certaines personnes pensent que nous devrions essayer de gérer toutes sortes d'erreurs d'exécution, y compris. et les situations du MOO. D'autres pensent qu'il y a encore peu de choses à faire avec MOO, et il vaut mieux laisser l'application planter. Du côté du deuxième groupe de personnes, il y a aussi le fait que la logique de traitement supplémentaire du MOO est difficile à tester. Et si le code n'est pas testé, cela ne fonctionne presque certainement pas.
Je suis tout à fait d'accord que vous ne devriez pas implémenter une logique de gestion des erreurs que vous n'allez pas tester. Cela n'améliorera presque certainement rien, et peut-être même pire - tout gâcher.
La question de savoir s'il faut ou non essayer de gérer les situations MOO dans les bibliothèques / applications est controversée et nous n'y reviendrons pas ici. Dans le cadre de cette publication, je souhaite simplement partager mon expérience sur la façon dont vous pouvez tester la logique implémentée pour gérer les situations MOO dans les applications écrites en C / C ++. La conversation portera sur les systèmes d'exploitation Linux et macOS. Pour un certain nombre de raisons, Windows sera contourné.
introduction
Nous souhaitons tous que MOO ne se produise jamais, mais dans la vraie vie, cela n'est pas toujours possible pour les raisons suivantes:
- La RAM est toujours limitée.
- SWAP n'est pas toujours activé.
- Les applications ne se comportent pas toujours correctement et tentent parfois d'allouer des quantités de mémoire irréalistes, interférant avec elles-mêmes et avec les autres.
- Les applications 32 bits existent toujours.
- overcommit n'est pas toujours activé.
- La consommation de mémoire peut être limitée en utilisant
ulimit
, par exemple. -
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
macOSSIGSEGV
/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();
}
__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
.
- Overthrower
malloc
/. - .
- Overthrower .
- Overthrower .
- Overthrower , .
- Overthrower’ .
- Overthrower Overthrower-aware . , .
- Overthrower lui-même est testé sur Ubuntu (depuis 14.04) et macOS (depuis Sierra (10.12) et Xcode 8.3). Pendant les tests, Overthrower essaie de se laisser tomber, entre autres.
- Si un véritable MOO apparaît dans le système, Overthrower fait tout son possible pour ne pas tomber.