@@ -3420,6 +3420,130 @@ test_pyobject_setallocators(PyObject *self)
3420
3420
return test_setallocators (PYMEM_DOMAIN_OBJ );
3421
3421
}
3422
3422
3423
+ /* Most part of the following code is inherited from the pyfailmalloc project
3424
+ * written by Victor Stinner. */
3425
+ static struct {
3426
+ int installed ;
3427
+ PyMemAllocatorEx raw ;
3428
+ PyMemAllocatorEx mem ;
3429
+ PyMemAllocatorEx obj ;
3430
+ } FmHook ;
3431
+
3432
+ static struct {
3433
+ int start ;
3434
+ int stop ;
3435
+ Py_ssize_t count ;
3436
+ } FmData ;
3437
+
3438
+ static int
3439
+ fm_nomemory (void )
3440
+ {
3441
+ FmData .count ++ ;
3442
+ if (FmData .count > FmData .start &&
3443
+ (FmData .stop <= 0 || FmData .count <= FmData .stop )) {
3444
+ return 1 ;
3445
+ }
3446
+ return 0 ;
3447
+ }
3448
+
3449
+ static void *
3450
+ hook_fmalloc (void * ctx , size_t size )
3451
+ {
3452
+ PyMemAllocatorEx * alloc = (PyMemAllocatorEx * )ctx ;
3453
+ if (fm_nomemory ()) {
3454
+ return NULL ;
3455
+ }
3456
+ return alloc -> malloc (alloc -> ctx , size );
3457
+ }
3458
+
3459
+ static void *
3460
+ hook_fcalloc (void * ctx , size_t nelem , size_t elsize )
3461
+ {
3462
+ PyMemAllocatorEx * alloc = (PyMemAllocatorEx * )ctx ;
3463
+ if (fm_nomemory ()) {
3464
+ return NULL ;
3465
+ }
3466
+ return alloc -> calloc (alloc -> ctx , nelem , elsize );
3467
+ }
3468
+
3469
+ static void *
3470
+ hook_frealloc (void * ctx , void * ptr , size_t new_size )
3471
+ {
3472
+ PyMemAllocatorEx * alloc = (PyMemAllocatorEx * )ctx ;
3473
+ if (fm_nomemory ()) {
3474
+ return NULL ;
3475
+ }
3476
+ return alloc -> realloc (alloc -> ctx , ptr , new_size );
3477
+ }
3478
+
3479
+ static void
3480
+ hook_ffree (void * ctx , void * ptr )
3481
+ {
3482
+ PyMemAllocatorEx * alloc = (PyMemAllocatorEx * )ctx ;
3483
+ alloc -> free (alloc -> ctx , ptr );
3484
+ }
3485
+
3486
+ static void
3487
+ fm_setup_hooks (void )
3488
+ {
3489
+ PyMemAllocatorEx alloc ;
3490
+
3491
+ if (FmHook .installed ) {
3492
+ return ;
3493
+ }
3494
+ FmHook .installed = 1 ;
3495
+
3496
+ alloc .malloc = hook_fmalloc ;
3497
+ alloc .calloc = hook_fcalloc ;
3498
+ alloc .realloc = hook_frealloc ;
3499
+ alloc .free = hook_ffree ;
3500
+ PyMem_GetAllocator (PYMEM_DOMAIN_RAW , & FmHook .raw );
3501
+ PyMem_GetAllocator (PYMEM_DOMAIN_MEM , & FmHook .mem );
3502
+ PyMem_GetAllocator (PYMEM_DOMAIN_OBJ , & FmHook .obj );
3503
+
3504
+ alloc .ctx = & FmHook .raw ;
3505
+ PyMem_SetAllocator (PYMEM_DOMAIN_RAW , & alloc );
3506
+
3507
+ alloc .ctx = & FmHook .mem ;
3508
+ PyMem_SetAllocator (PYMEM_DOMAIN_MEM , & alloc );
3509
+
3510
+ alloc .ctx = & FmHook .obj ;
3511
+ PyMem_SetAllocator (PYMEM_DOMAIN_OBJ , & alloc );
3512
+ }
3513
+
3514
+ static void
3515
+ fm_remove_hooks (void )
3516
+ {
3517
+ if (FmHook .installed ) {
3518
+ FmHook .installed = 0 ;
3519
+ PyMem_SetAllocator (PYMEM_DOMAIN_RAW , & FmHook .raw );
3520
+ PyMem_SetAllocator (PYMEM_DOMAIN_MEM , & FmHook .mem );
3521
+ PyMem_SetAllocator (PYMEM_DOMAIN_OBJ , & FmHook .obj );
3522
+ }
3523
+ }
3524
+
3525
+ static PyObject *
3526
+ set_nomemory (PyObject * self , PyObject * args )
3527
+ {
3528
+ /* Memory allocation fails after 'start' allocation requests, and until
3529
+ * 'stop' allocation requests except when 'stop' is negative or equal
3530
+ * to 0 (default) in which case allocation failures never stop. */
3531
+ FmData .count = 0 ;
3532
+ FmData .stop = 0 ;
3533
+ if (!PyArg_ParseTuple (args , "i|i" , & FmData .start , & FmData .stop )) {
3534
+ return NULL ;
3535
+ }
3536
+ fm_setup_hooks ();
3537
+ Py_RETURN_NONE ;
3538
+ }
3539
+
3540
+ static PyObject *
3541
+ remove_mem_hooks (PyObject * self )
3542
+ {
3543
+ fm_remove_hooks ();
3544
+ Py_RETURN_NONE ;
3545
+ }
3546
+
3423
3547
PyDoc_STRVAR (docstring_empty ,
3424
3548
""
3425
3549
);
@@ -4287,6 +4411,10 @@ static PyMethodDef TestMethods[] = {
4287
4411
(PyCFunction )test_pymem_setallocators , METH_NOARGS },
4288
4412
{"test_pyobject_setallocators" ,
4289
4413
(PyCFunction )test_pyobject_setallocators , METH_NOARGS },
4414
+ {"set_nomemory" , (PyCFunction )set_nomemory , METH_VARARGS ,
4415
+ PyDoc_STR ("set_nomemory(start:int, stop:int = 0)" )},
4416
+ {"remove_mem_hooks" , (PyCFunction )remove_mem_hooks , METH_NOARGS ,
4417
+ PyDoc_STR ("Remove memory hooks." )},
4290
4418
{"no_docstring" ,
4291
4419
(PyCFunction )test_with_docstring , METH_NOARGS },
4292
4420
{"docstring_empty" ,
0 commit comments