(*free)(void *); } SecretDataAllocatorFuncs; NPY_NO_EXPORT void * shift_alloc(void *ctx, size_t sz) { SecretDataAllocatorFuncs *funcs = (SecretDataAllocatorFuncs *)ctx; char *real = (char *)funcs->malloc(sz + 64); if (real == NULL) { return NULL; } snprintf(real, 64, "originally allocated %ld", (unsigned long)sz); return (void *)(real + 64); } NPY_NO_EXPORT void * shift_zero(void *ctx, size_t sz, size_t cnt) { SecretDataAllocatorFuncs *funcs = (SecretDataAllocatorFuncs *)ctx; char *real = (char *)funcs->calloc(sz + 64, cnt); if (real == NULL) { return NULL; } snprintf(real, 64, "originally allocated %ld via zero", (unsigned long)sz); return (void *)(real + 64); } NPY_NO_EXPORT void shift_free(void *ctx, void * p, npy_uintp sz) { SecretDataAllocatorFuncs *funcs = (SecretDataAllocatorFuncs *)ctx; if (p == NULL) { return ; } char *real = (char *)p - 64; if (strncmp(real, "originally allocated", 20) != 0) { fprintf(stdout, "uh-oh, unmatched shift_free, " "no appropriate prefix\n"); /* Make C runtime crash by calling free on the wrong address */ funcs->free((char *)p + 10); /* funcs->free(real); */ } else { npy_uintp i = (npy_uintp)atoi(real +20); if (i != sz) { fprintf(stderr, "uh-oh, unmatched shift_free" "(ptr, %ld) but allocated %ld\n", sz, i); /* This happens in some places, only print */ funcs->free(real); } else { funcs->free(real); } } } NPY_NO_EXPORT void * shift_realloc(void *ctx, void * p, npy_uintp sz) { SecretDataAllocatorFuncs *funcs = (SecretDataAllocatorFuncs *)ctx; if (p != NULL) { char *real = (char *)p - 64; if (strncmp(real, "originally allocated", 20) != 0) { fprintf(stdout, "uh-oh, unmatched shift_realloc\n"); return realloc(p, sz); } return (void *)((char *)funcs->realloc(real, sz + 64) + 64); } else { char *real = (char *)funcs->realloc(p, sz + 64); if (real == NULL) { return NULL; } snprintf(real, 64, "originally allocated " "%ld via realloc", (unsigned long)sz); return (void *)(real + 64); } } /* As an example, we use the standard {m|c|re}alloc/free funcs. */ static SecretDataAllocatorFuncs secret_data_handler_ctx = { malloc, calloc, realloc, free }; static PyDataMem_Handler secret_data_handler = { "secret_data_allocator", 1, { &secret_data_handler_ctx, /* ctx */ shift_alloc, /* malloc */ shift_zero, /* calloc */ shift_realloc, /* realloc */ shift_free /* free */ } }; void warn_on_free(void *capsule) { PyErr_WarnEx(PyExc_UserWarning, "in warn_on_free", 1); void * obj = PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule)); free(obj); }; zimport_array();r