1 /* CC0 (Public domain) - see LICENSE file for details */ 2 #ifndef CCAN_TAKE_H 3 #define CCAN_TAKE_H 4 #include "config.h" 5 #include <stdbool.h> 6 #include <ccan/str/str.h> 7 8 #ifdef CCAN_TAKE_DEBUG 9 #define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p) 10 #else 11 #define TAKE_LABEL(p) NULL 12 #endif 13 14 /** 15 * TAKES - annotate a formal parameter as being take()-able 16 * 17 * This doesn't do anything, but useful for documentation. 18 * 19 * Example: 20 * void print_string(const char *str TAKES); 21 * 22 */ 23 #define TAKES 24 25 /** 26 * take - record a pointer to be consumed by the function its handed to. 27 * @p: the pointer to mark, or NULL. 28 * 29 * This marks a pointer object to be freed by the called function, 30 * which is extremely useful for chaining functions. It works on 31 * NULL, for pass-through error handling. 32 */ 33 #define take(p) (take_typeof(p) take_((p), TAKE_LABEL(p))) 34 35 /** 36 * taken - check (and un-take) a pointer was passed with take() 37 * @p: the pointer to check. 38 * 39 * A function which accepts take() arguments uses this to see if it 40 * should own the pointer; it will be removed from the take list, so 41 * this only returns true once. 42 * 43 * Example: 44 * // Silly routine to add 1 45 * static int *add_one(const int *num TAKES) 46 * { 47 * int *ret; 48 * if (taken(num)) 49 * ret = (int *)num; 50 * else 51 * ret = malloc(sizeof(int)); 52 * if (ret) 53 * *ret = (*num) + 1; 54 * return ret; 55 * } 56 */ 57 bool taken(const void *p); 58 59 /** 60 * is_taken - check if a pointer was passed with take() 61 * @p: the pointer to check. 62 * 63 * This is like the above, but doesn't remove it from the taken list. 64 * 65 * Example: 66 * // Silly routine to add 1: doesn't handle taken args! 67 * static int *add_one_notake(const int *num) 68 * { 69 * int *ret = malloc(sizeof(int)); 70 * assert(!is_taken(num)); 71 * if (ret) 72 * *ret = (*num) + 1; 73 * return ret; 74 * } 75 */ 76 bool is_taken(const void *p); 77 78 /** 79 * taken_any - are there any taken pointers? 80 * 81 * Mainly useful for debugging take() leaks. With CCAN_TAKE_DEBUG, returns 82 * the label where the pointer was passed to take(), otherwise returns 83 * a static char buffer with the pointer value in it. NULL if none are taken. 84 * 85 * Example: 86 * static void cleanup(void) 87 * { 88 * assert(!taken_any()); 89 * } 90 */ 91 const char *taken_any(void); 92 93 /** 94 * take_cleanup - remove all taken pointers from list. 95 * 96 * This is useful in atexit() handlers for valgrind-style leak detection. 97 * 98 * Example: 99 * static void cleanup2(void) 100 * { 101 * take_cleanup(); 102 * } 103 */ 104 void take_cleanup(void); 105 106 /** 107 * take_allocfail - set function to call if we can't reallocated taken array. 108 * @fn: the function. 109 * 110 * If this is not set, then if the array reallocation fails, the 111 * pointer won't be marked taken(). If @fn returns, it is expected to 112 * free the pointer; we return NULL from take() and the function handles 113 * it like any allocation failure. 114 * 115 * Example: 116 * static void free_on_fail(const void *p) 117 * { 118 * free((void *)p); 119 * } 120 * 121 * static void init(void) 122 * { 123 * take_allocfail(free_on_fail); 124 * } 125 */ 126 void take_allocfail(void (*fn)(const void *p)); 127 128 /* Private functions */ 129 #if HAVE_TYPEOF 130 #define take_typeof(ptr) (__typeof__(ptr)) 131 #else 132 #define take_typeof(ptr) 133 #endif 134 135 void *take_(const void *p, const char *label); 136 #endif /* CCAN_TAKE_H */ 137