From: Julian Smith Date: Tue, 4 Oct 2022 12:19:26 +0000 (+0100) Subject: Improved the use of Memento with C++. X-Git-Tag: 1.21.0-rc1~43 X-Git-Url: https://git.ghostscript.com/?a=commitdiff_plain;h=b0ae7dd4c85a24494d07f78e110ad48ec560c502;p=mupdf.git Improved the use of Memento with C++. We expose a new C API Memento_cpp_new(), Memento_delete() etc, that is always built. This API needs to be called by operator new/delete/new[]/delete[] etc. There are various ways this can happen. If memento.c is built with a C compiler, no global new/delete operators are provided. If memento.c is built with a C++ compiler, and MEMENTO_NO_CPLUSPLUS is not defined global new/delete operators are provided. If memento.h is included by a C++ file, and MEMENTO_NO_CPLUSPLUS is not defined the library user must provide their own. This can be done by copying a bunch of lines from memento.c into a C++ file in the project, or by #including memento.c, with MEMENTO_CPP_EXTRAS_ONLY defined. Work around problems with C++ on Linux; if MEMENTO is defined we #include early on in memento.h to avoid an obscure conflict with strdup() having a `throw()` attribute, unlike Memento_strdup(). Git may get the attribution wrong here; the original work was from Julian Smith, reworked by Robin Watts. Credit to Julian, blame to Robin. --- diff --git a/include/mupdf/memento.h b/include/mupdf/memento.h index 9b513e894..5806fc0b6 100644 --- a/include/mupdf/memento.h +++ b/include/mupdf/memento.h @@ -139,19 +139,49 @@ * Memento has some experimental code in it to trap new/delete (and * new[]/delete[] if required) calls. * - * In order for this to work, either: + * In all cases, Memento will provide a C API that new/delete + * operators can be built upon: + * void *Memento_cpp_new(size_t size); + * void Memento_cpp_delete(void *pointer); + * void *Memento_cpp_new_array(size_t size); + * void Memento_cpp_delete_array(void *pointer); * - * 1) Build memento.c with the c++ compiler. + * There are various ways that actual operator definitions can be + * provided: + * + * 1) If memento.c is built with the c++ compiler, then global new + * and delete operators will be built in to memento by default. + * + * 2) If memento.c is built as normal with the C compiler, then + * no such veneers will be built in. The caller must provide them + * themselves. This can be done either by: + * + * a) Copying the lines between: + * // C++ Operator Veneers - START + * and + * // C++ Operator Veneers - END + * from memento.c into a C++ file within their own project. * * or * - * 2) Build memento.c as normal with the C compiler, then from any - * one of your .cpp files, do: + * b) Add the following lines to a C++ file in the project: + * #define MEMENTO_CPP_EXTRAS_ONLY + * #include "memento.c" * - * #define MEMENTO_CPP_EXTRAS_ONLY - * #include "memento.c" + * 3) For those people that would like to be able to compile memento.c + * with a C compiler, and provide new/delete veneers globally + * within their own C++ code (so avoiding the need for memento.h to + * be included from every file), define MEMENTO_NO_CPLUSPLUS as you + * build, and Memento will not provide any veneers itself, instead + * relying on the library user to provide them. * - * In the case where MEMENTO is not defined, this will not do anything. + * For convenience the lines to implement such veneers can be found + * further down this file between: + * + * Memento's interception of new/delete can be disabled at runtime + * by using Memento_setIgnoreNewDelete(1). Alternatively the + * MEMENTO_IGNORENEWDELETE environment variable can be set to 1 to + * achieve the same result. * * Both Windows and GCC provide separate new[] and delete[] operators * for arrays. Apparently some systems do not. If this is the case for @@ -187,6 +217,14 @@ #include #include +#ifdef __cplusplus + +// Avoids problems with strdup()'s throw() attribute on Linux. +#include + +extern "C" { +#endif + #define MEMENTO_H #ifndef MEMENTO_UNDERLYING_MALLOC @@ -233,6 +271,8 @@ size_t Memento_setMax(size_t); void Memento_stats(void); void *Memento_label(void *, const char *); void Memento_tick(void); +int Memento_setVerbose(int verbose); +int Memento_setIgnoreNewDelete(int ignore); void *Memento_malloc(size_t s); void *Memento_realloc(void *, size_t s); @@ -274,6 +314,12 @@ void Memento_fin(void); void Memento_bt(void); +void *Memento_cpp_new(size_t size); +void Memento_cpp_delete(void *pointer); +void *Memento_cpp_new_array(size_t size); +void Memento_cpp_delete_array(void *pointer); + + #ifdef MEMENTO #ifndef COMPILING_MEMENTO_C @@ -331,6 +377,8 @@ void Memento_bt(void); #define Memento_checkBytePointerOrNull(A) 0 #define Memento_checkShortPointerOrNull(A) 0 #define Memento_checkIntPointerOrNull(A) 0 +#define Memento_setVerbose(v) 0 +#define Memento_setIgnoreNewDelete(v) 0 #define Memento_tick() do {} while (0) #define Memento_startLeaking() do {} while (0) @@ -342,4 +390,8 @@ void Memento_bt(void); #endif /* MEMENTO */ +#ifdef __cplusplus +} +#endif + #endif /* MEMENTO_H */ diff --git a/source/fitz/memento.c b/source/fitz/memento.c index 9e5ed303c..2fea386f5 100644 --- a/source/fitz/memento.c +++ b/source/fitz/memento.c @@ -11,6 +11,8 @@ Novato, CA 94945, U.S.A., +1(415)492-9861, for further information. */ +#ifndef MEMENTO_CPP_EXTRAS_ONLY + /* Inspired by Fortify by Simon P Bullen. */ /* Set the following if you're only looking for leaks, not memory overwrites @@ -108,8 +110,6 @@ int atexit(void (*)(void)); #ifdef MEMENTO -#ifndef MEMENTO_CPP_EXTRAS_ONLY - #ifdef MEMENTO_ANDROID #include @@ -468,6 +468,7 @@ static struct { Memento_range *squeezes; int squeezes_num; int squeezes_pos; + int ignoreNewDelete; } memento; #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize) @@ -1947,6 +1948,9 @@ static void Memento_init(void) env = getenv("MEMENTO_VERBOSE"); memento.verbose = (env ? atoi(env) : 1); + env = getenv("MEMENTO_IGNORENEWDELETE"); + memento.ignoreNewDelete = (env ? atoi(env) : 0); + atexit(Memento_fin); Memento_initMutex(&memento.mutex); @@ -3190,6 +3194,13 @@ int Memento_setVerbose(int verbose) return ret; } +int Memento_setIgnoreNewDelete(int ignore) +{ + int ret = memento.ignoreNewDelete; + memento.ignoreNewDelete = ignore; + return ret; +} + int Memento_paranoidAt(int i) { memento.paranoidAt = i; @@ -3360,18 +3371,16 @@ int Memento_squeezing(void) return memento.squeezing; } -#endif /* MEMENTO_CPP_EXTRAS_ONLY */ - -#ifdef __cplusplus -/* Dumb overrides for the new and delete operators */ - -void *operator new(size_t size) +void *Memento_cpp_new(size_t size) { void *ret; if (!memento.inited) Memento_init(); + if (memento.ignoreNewDelete) + return MEMENTO_UNDERLYING_MALLOC(size); + if (size == 0) size = 1; MEMENTO_LOCK(); @@ -3380,11 +3389,19 @@ void *operator new(size_t size) return ret; } -void operator delete(void *pointer) +void Memento_cpp_delete(void *pointer) { if (!pointer) return; + if (!memento.inited) + Memento_init(); + if (memento.ignoreNewDelete) + { + MEMENTO_UNDERLYING_FREE(pointer); + return; + } + MEMENTO_LOCK(); do_free(pointer, Memento_EventType_delete); MEMENTO_UNLOCK(); @@ -3392,8 +3409,7 @@ void operator delete(void *pointer) /* Some C++ systems (apparently) don't provide new[] or delete[] * operators. Provide a way to cope with this */ -#ifndef MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS -void *operator new[](size_t size) +void *Memento_cpp_new_array(size_t size) { void *ret; if (!memento.inited) @@ -3401,22 +3417,30 @@ void *operator new[](size_t size) if (size == 0) size = 1; + + if (memento.ignoreNewDelete) + return MEMENTO_UNDERLYING_MALLOC(size); + MEMENTO_LOCK(); ret = do_malloc(size, Memento_EventType_newArray); MEMENTO_UNLOCK(); return ret; } -void operator delete[](void *pointer) +void Memento_cpp_delete_array(void *pointer) { + if (memento.ignoreNewDelete) + { + MEMENTO_UNDERLYING_FREE(pointer); + return; + } + MEMENTO_LOCK(); do_free(pointer, Memento_EventType_deleteArray); MEMENTO_UNLOCK(); } -#endif /* MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS */ -#endif /* __cplusplus */ -#else +#else /* MEMENTO */ /* Just in case anyone has left some debugging code in... */ void (Memento_breakpoint)(void) @@ -3592,6 +3616,16 @@ void (Memento_listNewBlocks)(void) { } +int (Memento_setIgnoreNewDelete)(int ignore) +{ + return 0; +} + +int (Memento_setVerbose)(int verbose) +{ + return 0; +} + size_t (Memento_setMax)(size_t max) { return 0; @@ -3631,4 +3665,48 @@ int (Memento_squeezing)(void) return 0; } -#endif +#endif /* MEMENTO */ + +#endif /* MEMENTO_CPP_EXTRAS_ONLY */ + +/* Everything here is only for C++, and then only if we haven't + * disabled it. */ + +#ifndef MEMENTO_NO_CPLUSPLUS +#ifdef __cplusplus + +// C++ Operator Veneers - START +void *operator new(size_t size) +{ + return Memento_cpp_new(size); +} +void operator delete(void *pointer) +{ + Memento_cpp_delete(pointer); +} +void* operator new[](size_t size) +{ + return Memento_cpp_new_array(size); +} +void operator delete[](void *pointer) +{ + Memento_cpp_delete_array(pointer); +} + +/* Some C++ systems (apparently) don't provide new[] or delete[] + * operators. Provide a way to cope with this */ +#ifndef MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS +void *operator new[](size_t size) +{ + return Memento_cpp_new_array(size); +} + +void operator delete[](void *pointer) +{ + Memento_cpp_delete_array(pointer); +} +#endif /* MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS */ +// C++ Operator Veneers - END + +#endif /* __cplusplus */ +#endif /* MEMENTO_NO_CPLUSPLUS */