Skip to content

Commit f597038

Browse files
authored
Merge pull request #676 from sanpeqf/feat-guards
Feat guards
2 parents a3773bb + e3f837c commit f597038

7 files changed

Lines changed: 128 additions & 23 deletions

File tree

examples/array/simple.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,21 @@
1414
int
1515
main(int argc, const char *argv[])
1616
{
17-
BFDEV_DEFINE_ARRAY(array, NULL, TEST_SIZE);
17+
BFDEV_CLASS(bfdev_array, array)(NULL, TEST_SIZE);
1818
unsigned int count;
1919

20-
bfdev_array_append(&array, 0, 0);
21-
2220
for (count = 0; count < TEST_LOOP; ++count) {
2321
unsigned int num;
2422
void *buff;
2523

2624
num = rand() % TEST_SIZE;
27-
buff = bfdev_array_push(&array, num);
25+
buff = bfdev_array_push(array, num);
2826
if (!buff)
2927
return 1;
3028

3129
memset(buff, 0, TEST_SIZE * num);
3230
printf("array bfdev_array_push test: %02u: %u\n", count, num);
3331
}
3432

35-
bfdev_array_release(&array);
36-
3733
return 0;
3834
}

examples/guards/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@ add_executable(guards-cleanup cleanup.c)
77
target_link_libraries(guards-cleanup bfdev)
88
add_test(guards-cleanup guards-cleanup)
99

10+
add_executable(guards-class class.c)
11+
target_link_libraries(guards-class bfdev)
12+
add_test(guards-class guards-class)
13+
1014
if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
1115
install(FILES
1216
cleanup.c
17+
class.c
1318
DESTINATION
1419
${CMAKE_INSTALL_DOCDIR}/examples/guards
1520
)
1621

1722
install(TARGETS
1823
guards-cleanup
24+
guards-class
1925
DESTINATION
2026
${CMAKE_INSTALL_DOCDIR}/bin
2127
)

examples/guards/class.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright(c) 2025 John Sanpe <sanpeqf@gmail.com>
4+
*/
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include <bfdev/guards.h>
10+
11+
static const char *
12+
test_ctor(void)
13+
{
14+
return strdup("helloworld");
15+
}
16+
17+
static void
18+
test_dtor(const char *obj)
19+
{
20+
free((void *)obj);
21+
}
22+
23+
BFDEV_DEFINE_CLASS(test, const char *,
24+
test_ctor(),
25+
test_dtor(_T)
26+
)
27+
28+
int
29+
main(int argc, const char *argv[])
30+
{
31+
BFDEV_CLASS(test, str)();
32+
33+
if (!str)
34+
return 1;
35+
printf("%s\n", str);
36+
37+
return 0;
38+
}

examples/guards/cleanup.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,36 @@
77
#include <stdlib.h>
88
#include <bfdev/guards.h>
99

10-
BFDEV_CLEAN_TEMPLATE(malloc, void *,
10+
BFDEV_DEFINE_CLEAN(malloc, void *,
1111
if (_T) {
1212
printf("cleanup %p\n", _T);
1313
free(_T);
1414
}
1515
)
1616

1717
static void
18-
test_gc_cleanup(void)
18+
test_clean_gc(void)
1919
{
20-
bfdev_clean(malloc) void *block;
20+
BFDEV_CLEAN(malloc) void *block;
2121
block = malloc(8);
2222
(void)block;
2323
}
2424

2525
static void *
26-
test_gc_lasting(void)
26+
test_clean_keep(void)
2727
{
28-
bfdev_clean(malloc) void *block;
28+
BFDEV_CLEAN(malloc) void *block;
2929
block = malloc(8);
30-
bfdev_clean_return(block);
30+
bfdev_return(block);
3131
}
3232

3333
int
3434
main(int argc, const char *argv[])
3535
{
3636
void *block;
3737

38-
test_gc_cleanup();
39-
block = test_gc_lasting();
38+
test_clean_gc();
39+
block = test_clean_keep();
4040
free(block);
4141

4242
return 0;

include/bfdev/allocator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <bfdev/config.h>
1111
#include <bfdev/types.h>
1212
#include <bfdev/stddef.h>
13+
#include <bfdev/guards.h>
14+
#include <bfdev/errptr.h>
1315

1416
BFDEV_BEGIN_DECLS
1517

@@ -125,6 +127,11 @@ bfdev_realloc_array(const bfdev_alloc_t *alloc,
125127
return bfdev_realloc(alloc, block, size * nr);
126128
}
127129

130+
BFDEV_DEFINE_CLEAN(bfdev_free, void *,
131+
if (!BFDEV_IS_INVAL(_T))
132+
bfdev_free(BFDEV_NULL, _T);
133+
)
134+
128135
BFDEV_END_DECLS
129136

130137
#endif /* _BFDEV_ALLOCATOR_H_ */

include/bfdev/array.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <bfdev/stddef.h>
1313
#include <bfdev/string.h>
1414
#include <bfdev/allocator.h>
15+
#include <bfdev/guards.h>
1516

1617
BFDEV_BEGIN_DECLS
1718

@@ -207,6 +208,32 @@ bfdev_array_reserve(bfdev_array_t *array, unsigned long num);
207208
extern void
208209
bfdev_array_release(bfdev_array_t *array);
209210

211+
static inline bfdev_array_t *
212+
bfdev_array_create(const bfdev_alloc_t *alloc, bfdev_size_t cells)
213+
{
214+
bfdev_array_t *obj;
215+
216+
obj = bfdev_malloc(alloc, sizeof(*obj));
217+
if (bfdev_unlikely(!obj))
218+
return BFDEV_NULL;
219+
bfdev_array_init(obj, alloc, cells);
220+
221+
return obj;
222+
}
223+
224+
static inline void
225+
bfdev_array_destroy(bfdev_array_t *obj)
226+
{
227+
bfdev_array_release(obj);
228+
bfdev_free(obj->alloc, obj);
229+
}
230+
231+
BFDEV_DEFINE_CLASS(bfdev_array, bfdev_array_t *,
232+
bfdev_array_create(alloc, cells),
233+
bfdev_array_destroy(_T),
234+
const bfdev_alloc_t *alloc, bfdev_size_t cells
235+
)
236+
210237
BFDEV_END_DECLS
211238

212239
#endif /* _BFDEV_ARRAY_H_ */

include/bfdev/guards.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,55 @@
1212

1313
BFDEV_BEGIN_DECLS
1414

15-
#define BFDEV_CLEAN_TEMPLATE(name, type, free) \
15+
/**
16+
* Guards:
17+
*
18+
* The "goto error" pattern is notorious for introducing subtle resource
19+
* leaks. It is tedious and error prone to add new resource acquisition
20+
* constraints into code paths that already have several unwind
21+
* conditions. The "cleanup" helpers enable the compiler to help with
22+
* this tedium and can aid in maintaining LIFO (last in first out)
23+
* unwind ordering to avoid unintentional leaks.
24+
*/
25+
26+
#define BFDEV_DEFINE_CLEAN(name, type, free) \
1627
static inline void \
1728
__bfdev_cleanup_##name(void *object) \
1829
{ \
1930
type _T = *(type *)object; \
2031
free; \
2132
}
2233

23-
#define bfdev_clean_lasting(object) ({ \
24-
__auto_type __ptr = (object); \
25-
(object) = BFDEV_NULL; __ptr; \
26-
})
27-
28-
#define bfdev_clean(name) \
34+
#define BFDEV_CLEAN(name) \
2935
__bfdev_cleanup(__bfdev_cleanup_##name)
3036

31-
#define bfdev_clean_return(object) \
32-
return bfdev_clean_lasting(object)
37+
#define BFDEV_DEFINE_CLASS(name, type, ctor, dtor, args...) \
38+
typedef type __bfdev_class_##name##_t; \
39+
static inline type \
40+
__bfdev_class_##name##_constructor(args) \
41+
{ \
42+
type __tmp = ctor; \
43+
return __tmp; \
44+
} \
45+
static inline void \
46+
__bfdev_class_##name##_destructor(type *p) \
47+
{ \
48+
type _T = *p; \
49+
dtor; \
50+
}
51+
52+
#define BFDEV_CLASS(name, var) \
53+
__bfdev_class_##name##_t var \
54+
__bfdev_cleanup(__bfdev_class_##name##_destructor) = \
55+
__bfdev_class_##name##_constructor
56+
57+
#define bfdev_lasting(object) ({ \
58+
__auto_type __ptr = (object); \
59+
(object) = BFDEV_NULL; __ptr; \
60+
})
61+
62+
#define bfdev_return(object) \
63+
return bfdev_lasting(object)
3364

3465
BFDEV_END_DECLS
3566

0 commit comments

Comments
 (0)