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