Skip to content

Commit 9e8b341

Browse files
committed
Mark allocation functions with their deallocator
Mark allocation functions in C support libraries with their corresponding deallocation functions so that GCC 11 and later can diagnose memory deallocation bugs.
1 parent 633cba8 commit 9e8b341

File tree

11 files changed

+106
-54
lines changed

11 files changed

+106
-54
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ rra-c-util 10.2 (unreleased)
2121
handles read-only directories correctly. Optionally depend on
2222
Perl::Critic::Community instead of Perl::Critic::Freenode.
2323

24+
Mark allocation functions in C support libraries with their
25+
corresponding deallocation functions so that GCC 11 and later can
26+
diagnose memory deallocation bugs.
27+
2428
Document the dependency some Autoconf macros have on the macros
2529
provided by pkg-config.
2630

pam-util/vector.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
2121
*
2222
* Written by Russ Allbery <[email protected]>
23+
* Copyright 2022 Russ Allbery <[email protected]>
2324
* Copyright 2010-2011, 2014
2425
* The Board of Trustees of the Leland Stanford Junior University
2526
*
@@ -51,15 +52,18 @@ BEGIN_DECLS
5152
/* Default to a hidden visibility for all util functions. */
5253
#pragma GCC visibility push(hidden)
5354

55+
/* Free the vector and all resources allocated for it. */
56+
void vector_free(struct vector *);
57+
5458
/* Create a new, empty vector. Returns NULL on memory allocation failure. */
55-
struct vector *vector_new(void) __attribute__((__malloc__));
59+
struct vector *vector_new(void) __attribute__((__malloc__(vector_free)));
5660

5761
/*
5862
* Create a new vector that's a copy of an existing vector. Returns NULL on
5963
* memory allocation failure.
6064
*/
6165
struct vector *vector_copy(const struct vector *)
62-
__attribute__((__malloc__, __nonnull__));
66+
__attribute__((__malloc__(vector_free), __nonnull__));
6367

6468
/*
6569
* Add a string to a vector. Resizes the vector if necessary. Returns false
@@ -82,9 +86,6 @@ bool vector_resize(struct vector *, size_t size) __attribute__((__nonnull__));
8286
*/
8387
void vector_clear(struct vector *) __attribute__((__nonnull__));
8488

85-
/* Free the vector and all resources allocated for it. */
86-
void vector_free(struct vector *);
87-
8889
/*
8990
* Split functions build a vector from a string. vector_split_multi splits on
9091
* a set of characters. If the vector argument is NULL, a new vector is

portable/macros.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
66
*
77
* Written by Russ Allbery <[email protected]>
8-
* Copyright 2015 Russ Allbery <[email protected]>
8+
* Copyright 2015, 2022 Russ Allbery <[email protected]>
99
* Copyright 2008, 2011-2012
1010
* The Board of Trustees of the Leland Stanford Junior University
1111
*
@@ -45,6 +45,16 @@
4545
# endif
4646
#endif
4747

48+
/*
49+
* Suppress the argument to __malloc__ in Clang (not supported in at least
50+
* version 13) and GCC versions prior to 11.
51+
*/
52+
#if !defined(__attribute__) && !defined(__malloc__)
53+
# if defined(__clang__) || __GNUC__ < 11
54+
# define __malloc__(dalloc) __malloc__
55+
# endif
56+
#endif
57+
4858
/*
4959
* LLVM and Clang pretend to be GCC but don't support all of the __attribute__
5060
* settings that GCC does. For them, suppress warnings about unknown

tests/runtests.c

+16-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* should be sent to the e-mail address below. This program is part of C TAP
99
* Harness <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
1010
*
11-
* Copyright 2000-2001, 2004, 2006-2019 Russ Allbery <[email protected]>
11+
* Copyright 2000-2001, 2004, 2006-2019, 2022 Russ Allbery <[email protected]>
1212
*
1313
* Permission is hereby granted, free of charge, to any person obtaining a
1414
* copy of this software and associated documentation files (the "Software"),
@@ -280,6 +280,16 @@ Failed Set Fail/Total (%) Skip Stat Failing Tests\n\
280280
# endif
281281
#endif
282282

283+
/*
284+
* Suppress the argument to __malloc__ in Clang (not supported in at least
285+
* version 13) and GCC versions prior to 11.
286+
*/
287+
#if !defined(__attribute__) && !defined(__malloc__)
288+
# if defined(__clang__) || __GNUC__ < 11
289+
# define __malloc__(dalloc) __malloc__
290+
# endif
291+
#endif
292+
283293
/*
284294
* LLVM and Clang pretend to be GCC but don't support all of the __attribute__
285295
* settings that GCC does. For them, suppress warnings about unknown
@@ -296,15 +306,15 @@ static void die(const char *, ...)
296306
static void sysdie(const char *, ...)
297307
__attribute__((__nonnull__, __noreturn__, __format__(printf, 1, 2)));
298308
static void *x_calloc(size_t, size_t, const char *, int)
299-
__attribute__((__alloc_size__(1, 2), __malloc__, __nonnull__));
309+
__attribute__((__alloc_size__(1, 2), __malloc__(free), __nonnull__));
300310
static void *x_malloc(size_t, const char *, int)
301-
__attribute__((__alloc_size__(1), __malloc__, __nonnull__));
311+
__attribute__((__alloc_size__(1), __malloc__(free), __nonnull__));
302312
static void *x_reallocarray(void *, size_t, size_t, const char *, int)
303-
__attribute__((__alloc_size__(2, 3), __malloc__, __nonnull__(4)));
313+
__attribute__((__alloc_size__(2, 3), __malloc__(free), __nonnull__(4)));
304314
static char *x_strdup(const char *, const char *, int)
305-
__attribute__((__malloc__, __nonnull__));
315+
__attribute__((__malloc__(free), __nonnull__));
306316
static char *x_strndup(const char *, size_t, const char *, int)
307-
__attribute__((__malloc__, __nonnull__));
317+
__attribute__((__malloc__(free), __nonnull__));
308318

309319

310320
/*

tests/tap/basic.h

+16-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* documentation is at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
66
*
77
* Written by Russ Allbery <[email protected]>
8-
* Copyright 2009-2019 Russ Allbery <[email protected]>
8+
* Copyright 2009-2019, 2022 Russ Allbery <[email protected]>
99
* Copyright 2001-2002, 2004-2008, 2011-2012, 2014
1010
* The Board of Trustees of the Leland Stanford Junior University
1111
*
@@ -129,17 +129,20 @@ void diag_file_remove(const char *file) __attribute__((__nonnull__));
129129

130130
/* Allocate memory, reporting a fatal error with bail on failure. */
131131
void *bcalloc(size_t, size_t)
132-
__attribute__((__alloc_size__(1, 2), __malloc__, __warn_unused_result__));
133-
void *bmalloc(size_t)
134-
__attribute__((__alloc_size__(1), __malloc__, __warn_unused_result__));
132+
__attribute__((__alloc_size__(1, 2), __malloc__(free),
133+
__warn_unused_result__));
134+
void *bmalloc(size_t) __attribute__((__alloc_size__(1), __malloc__(free),
135+
__warn_unused_result__));
135136
void *breallocarray(void *, size_t, size_t)
136-
__attribute__((__alloc_size__(2, 3), __malloc__, __warn_unused_result__));
137+
__attribute__((__alloc_size__(2, 3), __malloc__(free),
138+
__warn_unused_result__));
137139
void *brealloc(void *, size_t)
138-
__attribute__((__alloc_size__(2), __malloc__, __warn_unused_result__));
140+
__attribute__((__alloc_size__(2), __malloc__(free),
141+
__warn_unused_result__));
139142
char *bstrdup(const char *)
140-
__attribute__((__malloc__, __nonnull__, __warn_unused_result__));
143+
__attribute__((__malloc__(free), __nonnull__, __warn_unused_result__));
141144
char *bstrndup(const char *, size_t)
142-
__attribute__((__malloc__, __nonnull__, __warn_unused_result__));
145+
__attribute__((__malloc__(free), __nonnull__, __warn_unused_result__));
143146

144147
/*
145148
* Macros that cast the return value from b* memory functions, making them
@@ -153,16 +156,18 @@ char *bstrndup(const char *, size_t)
153156
* Find a test file under C_TAP_BUILD or C_TAP_SOURCE, returning the full
154157
* path. The returned path should be freed with test_file_path_free().
155158
*/
156-
char *test_file_path(const char *file)
157-
__attribute__((__malloc__, __nonnull__, __warn_unused_result__));
158159
void test_file_path_free(char *path);
160+
char *test_file_path(const char *file)
161+
__attribute__((__malloc__(test_file_path_free), __nonnull__,
162+
__warn_unused_result__));
159163

160164
/*
161165
* Create a temporary directory relative to C_TAP_BUILD and return the path.
162166
* The returned path should be freed with test_tmpdir_free().
163167
*/
164-
char *test_tmpdir(void) __attribute__((__malloc__, __warn_unused_result__));
165168
void test_tmpdir_free(char *path);
169+
char *test_tmpdir(void)
170+
__attribute__((__malloc__(test_tmpdir_free), __warn_unused_result__));
166171

167172
/*
168173
* Register a cleanup function that is called when testing ends. All such

tests/tap/kerberos.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
1616
*
1717
* Written by Russ Allbery <[email protected]>
18-
* Copyright 2017 Russ Allbery <[email protected]>
18+
* Copyright 2017, 2022 Russ Allbery <[email protected]>
1919
* Copyright 2006-2007, 2009-2014
2020
* The Board of Trustees of the Leland Stanford Junior University
2121
*
@@ -211,9 +211,11 @@ kerberos_kinit(void)
211211
* process so that test programs that fork don't remove the ticket cache still
212212
* used by the main program.
213213
*/
214-
static void
215-
kerberos_free(void)
214+
void
215+
kerberos_free(struct kerberos_config *config_arg)
216216
{
217+
if (config_arg != config)
218+
bail("invalid argument to kerberos_free");
217219
test_tmpdir_free(tmpdir_ticket);
218220
tmpdir_ticket = NULL;
219221
if (config != NULL) {
@@ -257,7 +259,7 @@ kerberos_cleanup(void)
257259
unlink(path);
258260
free(path);
259261
}
260-
kerberos_free();
262+
kerberos_free(config);
261263
}
262264

263265

@@ -273,7 +275,7 @@ kerberos_cleanup_handler(int success UNUSED, int primary)
273275
if (primary)
274276
kerberos_cleanup();
275277
else
276-
kerberos_free();
278+
kerberos_free(config);
277279
}
278280

279281

tests/tap/kerberos.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
66
*
77
* Written by Russ Allbery <[email protected]>
8-
* Copyright 2017, 2020 Russ Allbery <[email protected]>
8+
* Copyright 2017, 2020, 2022 Russ Allbery <[email protected]>
99
* Copyright 2006-2007, 2009, 2011-2014
1010
* The Board of Trustees of the Leland Stanford Junior University
1111
*
@@ -76,6 +76,8 @@ BEGIN_DECLS
7676
* them in a Kerberos ticket cache, sets KRB5_KTNAME and KRB5CCNAME. It also
7777
* loads the principal and password from config/password, if it exists, and
7878
* stores the principal, password, username, and realm in the returned struct.
79+
* The returned struct is also saved statically to allow for easier cleanup
80+
* and thus cleaner valgrind output in tests.
7981
*
8082
* If there is no config/keytab file, KRB5_KTNAME and KRB5CCNAME won't be set
8183
* and the keytab field will be NULL. If there is no config/password file,
@@ -87,9 +89,14 @@ BEGIN_DECLS
8789
* however, be called directly if for some reason the caller needs to delete
8890
* the Kerberos environment again. However, normally the caller can just call
8991
* kerberos_setup again.
92+
*
93+
* kerberos_free is an alternate way of calling kerberos_cleanup that
94+
* satisfies the __malloc__ annotation requirements. There is normally no
95+
* need to call it.
9096
*/
97+
void kerberos_free(struct kerberos_config *);
9198
struct kerberos_config *kerberos_setup(enum kerberos_needs)
92-
__attribute__((__malloc__));
99+
__attribute__((__malloc__(kerberos_free)));
93100
void kerberos_cleanup(void);
94101

95102
/*

tests/tap/macros.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* This file is part of C TAP Harness. The current version plus supporting
99
* documentation is at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
1010
*
11-
* Copyright 2008, 2012-2013, 2015 Russ Allbery <[email protected]>
11+
* Copyright 2008, 2012-2013, 2015, 2022 Russ Allbery <[email protected]>
1212
*
1313
* Permission is hereby granted, free of charge, to any person obtaining a
1414
* copy of this software and associated documentation files (the "Software"),
@@ -69,6 +69,16 @@
6969
# endif
7070
#endif
7171

72+
/*
73+
* Suppress the argument to __malloc__ in Clang (not supported in at least
74+
* version 13) and GCC versions prior to 11.
75+
*/
76+
#if !defined(__attribute__) && !defined(__malloc__)
77+
# if defined(__clang__) || __GNUC__ < 11
78+
# define __malloc__(dalloc) __malloc__
79+
# endif
80+
#endif
81+
7282
/*
7383
* LLVM and Clang pretend to be GCC but don't support all of the __attribute__
7484
* settings that GCC does. For them, suppress warnings about unknown

util/buffer.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
1717
*
1818
* Written by Russ Allbery <[email protected]>
19-
* Copyright 2014-2015 Russ Allbery <[email protected]>
19+
* Copyright 2014-2015, 2022 Russ Allbery <[email protected]>
2020
* Copyright 2011-2012
2121
* The Board of Trustees of the Leland Stanford Junior University
2222
* Copyright 2004-2006 Internet Systems Consortium, Inc. ("ISC")
@@ -62,13 +62,13 @@ BEGIN_DECLS
6262
/* Default to a hidden visibility for all util functions. */
6363
#pragma GCC visibility push(hidden)
6464

65-
/* Allocate a new buffer and initialize its contents. */
66-
struct buffer *buffer_new(void)
67-
__attribute__((__warn_unused_result__, __malloc__));
68-
6965
/* Free an allocated buffer. */
7066
void buffer_free(struct buffer *);
7167

68+
/* Allocate a new buffer and initialize its contents. */
69+
struct buffer *buffer_new(void)
70+
__attribute__((__warn_unused_result__, __malloc__(buffer_free)));
71+
7272
/*
7373
* Resize a buffer to be at least as large as the provided size. Invalidates
7474
* pointers into the buffer.

util/vector.h

+13-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
1313
*
1414
* Written by Russ Allbery <[email protected]>
15-
* Copyright 2001-2006 Russ Allbery <[email protected]>
15+
* Copyright 2001-2006, 2022 Russ Allbery <[email protected]>
1616
* Copyright 2005-2006, 2008-2011, 2013-2014
1717
* The Board of Trustees of the Leland Stanford Junior University
1818
*
@@ -31,6 +31,7 @@
3131
#include <portable/macros.h>
3232

3333
#include <stddef.h>
34+
#include <stdlib.h>
3435

3536
struct vector {
3637
size_t count;
@@ -49,11 +50,18 @@ BEGIN_DECLS
4950
/* Default to a hidden visibility for all util functions. */
5051
#pragma GCC visibility push(hidden)
5152

53+
/*
54+
* Free the vector and all resources allocated for it. NULL may be passed in
55+
* safely and will be ignored.
56+
*/
57+
void vector_free(struct vector *);
58+
void cvector_free(struct cvector *);
59+
5260
/* Create a new, empty vector. */
5361
struct vector *vector_new(void)
54-
__attribute__((__warn_unused_result__, __malloc__));
62+
__attribute__((__warn_unused_result__, __malloc__(vector_free)));
5563
struct cvector *cvector_new(void)
56-
__attribute__((__warn_unused_result__, __malloc__));
64+
__attribute__((__warn_unused_result__, __malloc__(cvector_free)));
5765

5866
/* Add a string to a vector. Resizes the vector if necessary. */
5967
void vector_add(struct vector *, const char *string)
@@ -81,13 +89,6 @@ void cvector_resize(struct cvector *, size_t size)
8189
void vector_clear(struct vector *) __attribute__((__nonnull__));
8290
void cvector_clear(struct cvector *) __attribute__((__nonnull__));
8391

84-
/*
85-
* Free the vector and all resources allocated for it. NULL may be passed in
86-
* safely and will be ignored.
87-
*/
88-
void vector_free(struct vector *);
89-
void cvector_free(struct cvector *);
90-
9192
/*
9293
* Split functions build a vector from a string. vector_split splits on a
9394
* specified character, vector_split_multi splits on a set of characters, and
@@ -125,9 +126,9 @@ struct cvector *cvector_split_space(char *string, struct cvector *)
125126
* responsible for freeing.
126127
*/
127128
char *vector_join(const struct vector *, const char *separator)
128-
__attribute__((__malloc__, __nonnull__, __warn_unused_result__));
129+
__attribute__((__malloc__(free), __nonnull__, __warn_unused_result__));
129130
char *cvector_join(const struct cvector *, const char *separator)
130-
__attribute__((__malloc__, __nonnull__, __warn_unused_result__));
131+
__attribute__((__malloc__(free), __nonnull__, __warn_unused_result__));
131132

132133
/*
133134
* Exec the given program with the vector as its arguments. Return behavior

0 commit comments

Comments
 (0)