Merge pull request #26555 from poettering/cleanup-array

add gcc cleanup attribute based logic to destroy arrays
This commit is contained in:
Yu Watanabe
2023-02-23 15:08:56 +09:00
committed by GitHub
10 changed files with 139 additions and 96 deletions
+1
View File
@@ -15,6 +15,7 @@
typedef void (*free_func_t)(void *p);
typedef void* (*mfree_func_t)(void *p);
typedef void (*free_array_func_t)(void *p, size_t n);
/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
* proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
+34
View File
@@ -111,3 +111,37 @@ static inline void erase_and_freep(void *p) {
static inline void erase_char(char *p) {
explicit_bzero_safe(p, sizeof(char));
}
/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */
struct ArrayCleanup {
void **parray;
size_t *pn;
free_array_func_t pfunc;
};
static inline void array_cleanup(struct ArrayCleanup *c) {
assert(c);
assert(!c->parray == !c->pn);
if (!c->parray)
return;
if (*c->parray) {
assert(c->pfunc);
c->pfunc(*c->parray, *c->pn);
*c->parray = NULL;
}
*c->pn = 0;
}
#define CLEANUP_ARRAY(array, n, func) \
_cleanup_(array_cleanup) _unused_ struct ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \
.parray = (void**) &(array), \
.pn = &(n), \
.pfunc = (free_array_func_t) ({ \
void (*_f)(typeof(array[0]) *a, size_t b) = func; \
_f; \
}), \
}
+8 -11
View File
@@ -2335,6 +2335,8 @@ static int reply_install_changes_and_free(
bool bad = false, good = false;
int r;
CLEANUP_ARRAY(changes, n_changes, install_changes_free);
if (install_changes_have_modification(changes, n_changes)) {
r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
if (r < 0)
@@ -2343,17 +2345,17 @@ static int reply_install_changes_and_free(
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
goto fail;
return r;
if (carries_install_info >= 0) {
r = sd_bus_message_append(reply, "b", carries_install_info);
if (r < 0)
goto fail;
return r;
}
r = sd_bus_message_open_container(reply, 'a', "(sss)");
if (r < 0)
goto fail;
return r;
for (size_t i = 0; i < n_changes; i++) {
@@ -2368,7 +2370,7 @@ static int reply_install_changes_and_free(
changes[i].path,
changes[i].source);
if (r < 0)
goto fail;
return r;
good = true;
}
@@ -2376,18 +2378,13 @@ static int reply_install_changes_and_free(
/* If there was a failed change, and no successful change, then return the first failure as proper
* method call error. */
if (bad && !good)
return install_error(error, 0, changes, n_changes);
return install_error(error, 0, TAKE_PTR(changes), n_changes);
r = sd_bus_message_close_container(reply);
if (r < 0)
goto fail;
return r;
install_changes_free(changes, n_changes);
return sd_bus_send(NULL, reply, NULL);
fail:
install_changes_free(changes, n_changes);
return r;
}
static int method_enable_unit_files_generic(
+36 -54
View File
@@ -692,8 +692,8 @@ static int match_component_compare(const struct bus_match_component *a, const st
return CMP(a->type, b->type);
}
void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
for (unsigned i = 0; i < n_components; i++)
void bus_match_parse_free(struct bus_match_component *components, size_t n_components) {
for (size_t i = 0; i < n_components; i++)
free(components[i].value_str);
free(components);
@@ -702,20 +702,22 @@ void bus_match_parse_free(struct bus_match_component *components, unsigned n_com
int bus_match_parse(
const char *match,
struct bus_match_component **ret_components,
unsigned *ret_n_components) {
size_t *ret_n_components) {
struct bus_match_component *components = NULL;
unsigned n_components = 0;
size_t n_components = 0;
int r;
assert(match);
assert(ret_components);
assert(ret_n_components);
CLEANUP_ARRAY(components, n_components, bus_match_parse_free);
while (*match != '\0') {
const char *eq, *q;
enum bus_match_node_type t;
unsigned j = 0;
size_t j = 0;
_cleanup_free_ char *value = NULL;
bool escaped = false, quoted;
uint8_t u;
@@ -724,16 +726,12 @@ int bus_match_parse(
match += strspn(match, " ");
eq = strchr(match, '=');
if (!eq) {
r = -EINVAL;
goto fail;
}
if (!eq)
return -EINVAL;
t = bus_match_node_type_from_string(match, eq - match);
if (t < 0) {
r = -EINVAL;
goto fail;
}
if (t < 0)
return -EINVAL;
quoted = eq[1] == '\'';
@@ -741,14 +739,12 @@ int bus_match_parse(
if (*q == '\0') {
if (quoted) {
r = -EINVAL;
goto fail;
} else {
if (value)
value[j] = '\0';
break;
}
if (quoted)
return -EINVAL;
if (value)
value[j] = '\0';
break;
}
if (!escaped) {
@@ -772,10 +768,8 @@ int bus_match_parse(
}
}
if (!GREEDY_REALLOC(value, j + 2)) {
r = -ENOMEM;
goto fail;
}
if (!GREEDY_REALLOC(value, j + 2))
return -ENOMEM;
value[j++] = *q;
escaped = false;
@@ -783,25 +777,21 @@ int bus_match_parse(
if (!value) {
value = strdup("");
if (!value) {
r = -ENOMEM;
goto fail;
}
if (!value)
return -ENOMEM;
}
if (t == BUS_MATCH_MESSAGE_TYPE) {
r = bus_message_type_from_string(value, &u);
if (r < 0)
goto fail;
return r;
value = mfree(value);
} else
u = 0;
if (!GREEDY_REALLOC(components, n_components + 1)) {
r = -ENOMEM;
goto fail;
}
if (!GREEDY_REALLOC(components, n_components + 1))
return -ENOMEM;
components[n_components++] = (struct bus_match_component) {
.type = t,
@@ -812,10 +802,8 @@ int bus_match_parse(
if (q[quoted] == 0)
break;
if (q[quoted] != ',') {
r = -EINVAL;
goto fail;
}
if (q[quoted] != ',')
return -EINVAL;
match = q + 1 + quoted;
}
@@ -824,23 +812,17 @@ int bus_match_parse(
typesafe_qsort(components, n_components, match_component_compare);
/* Check for duplicates */
for (unsigned i = 0; i+1 < n_components; i++)
if (components[i].type == components[i+1].type) {
r = -EINVAL;
goto fail;
}
for (size_t i = 0; i+1 < n_components; i++)
if (components[i].type == components[i+1].type)
return -EINVAL;
*ret_components = components;
*ret_components = TAKE_PTR(components);
*ret_n_components = n_components;
return 0;
fail:
bus_match_parse_free(components, n_components);
return r;
}
char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
char *bus_match_to_string(struct bus_match_component *components, size_t n_components) {
_cleanup_free_ char *buffer = NULL;
size_t size = 0;
int r;
@@ -854,7 +836,7 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com
if (!f)
return NULL;
for (unsigned i = 0; i < n_components; i++) {
for (size_t i = 0; i < n_components; i++) {
char buf[32];
if (i != 0)
@@ -882,7 +864,7 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com
int bus_match_add(
struct bus_match_node *root,
struct bus_match_component *components,
unsigned n_components,
size_t n_components,
struct match_callback *callback) {
int r;
@@ -890,7 +872,7 @@ int bus_match_add(
assert(root);
assert(callback);
for (unsigned i = 0; i < n_components; i++) {
for (size_t i = 0; i < n_components; i++) {
r = bus_match_add_compare_value(root,
components[i].type,
components[i].value_u8,
@@ -1038,7 +1020,7 @@ void bus_match_dump(FILE *out, struct bus_match_node *node, unsigned level) {
bus_match_dump(out, c, level + 1);
}
enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) {
enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, size_t n_components) {
bool found_driver = false;
if (n_components <= 0)
@@ -1052,7 +1034,7 @@ enum bus_match_scope bus_match_get_scope(const struct bus_match_component *compo
* local messages, then we check if it only matches on the
* driver. */
for (unsigned i = 0; i < n_components; i++) {
for (size_t i = 0; i < n_components; i++) {
const struct bus_match_component *c = components + i;
if (c->type == BUS_MATCH_SENDER) {
+5 -5
View File
@@ -65,7 +65,7 @@ enum bus_match_scope {
int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, struct match_callback *callback);
int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, size_t n_components, struct match_callback *callback);
int bus_match_remove(struct bus_match_node *root, struct match_callback *callback);
void bus_match_free(struct bus_match_node *node);
@@ -75,8 +75,8 @@ void bus_match_dump(FILE *out, struct bus_match_node *node, unsigned level);
const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l);
enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n);
int bus_match_parse(const char *match, struct bus_match_component **ret_components, unsigned *ret_n_components);
void bus_match_parse_free(struct bus_match_component *components, unsigned n_components);
char *bus_match_to_string(struct bus_match_component *components, unsigned n_components);
int bus_match_parse(const char *match, struct bus_match_component **ret_components, size_t *ret_n_components);
void bus_match_parse_free(struct bus_match_component *components, size_t n_components);
char *bus_match_to_string(struct bus_match_component *components, size_t n_components);
enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components);
enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, size_t n_components);
+4 -4
View File
@@ -54,7 +54,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
offset = end ? (size_t) (end - (char*) data + 1) : size;
struct bus_match_component *components;
unsigned n_components;
size_t n_components;
r = bus_match_parse(line, &components, &n_components);
if (IN_SET(r, -EINVAL, -ENOMEM)) {
log_debug_errno(r, "Failed to parse line: %m");
@@ -62,11 +62,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
assert_se(r >= 0); /* We only expect EINVAL and ENOMEM errors, or success. */
log_debug("Parsed %u components.", n_components);
CLEANUP_ARRAY(components, n_components, bus_match_parse_free);
log_debug("Parsed %zu components.", n_components);
_cleanup_free_ char *again = bus_match_to_string(components, n_components);
if (!again) {
bus_match_parse_free(components, n_components);
log_oom();
break;
}
@@ -75,7 +76,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fprintf(g, "%s\n", again);
r = bus_match_add(&root, components, n_components, &slot.match_callback);
bus_match_parse_free(components, n_components);
if (r < 0) {
log_error_errno(r, "Failed to add match: %m");
break;
+1 -1
View File
@@ -3505,7 +3505,7 @@ static int bus_add_match_full(
void *userdata) {
struct bus_match_component *components = NULL;
unsigned n_components = 0;
size_t n_components = 0;
sd_bus_slot *s = NULL;
int r = 0;
+7 -7
View File
@@ -38,7 +38,7 @@ static bool mask_contains(unsigned a[], unsigned n) {
static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char *match, int value) {
struct bus_match_component *components;
unsigned n_components;
size_t n_components;
sd_bus_slot *s;
int r;
@@ -48,22 +48,22 @@ static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char
if (r < 0)
return r;
CLEANUP_ARRAY(components, n_components, bus_match_parse_free);
s->userdata = INT_TO_PTR(value);
s->match_callback.callback = filter;
r = bus_match_add(root, components, n_components, &s->match_callback);
bus_match_parse_free(components, n_components);
return r;
return bus_match_add(root, components, n_components, &s->match_callback);
}
static void test_match_scope(const char *match, enum bus_match_scope scope) {
struct bus_match_component *components = NULL;
unsigned n_components = 0;
size_t n_components = 0;
CLEANUP_ARRAY(components, n_components, bus_match_parse_free);
assert_se(bus_match_parse(match, &components, &n_components) >= 0);
assert_se(bus_match_get_scope(components, n_components) == scope);
bus_match_parse_free(components, n_components);
}
int main(int argc, char *argv[]) {
+6 -14
View File
@@ -574,7 +574,6 @@ static int normalize_portable_changes(
PortableChange *changes = NULL;
size_t n_changes = 0;
int r = 0;
assert(ret_n_changes);
assert(ret_changes);
@@ -586,12 +585,13 @@ static int normalize_portable_changes(
if (!changes)
return -ENOMEM;
CLEANUP_ARRAY(changes, n_changes, portable_changes_free);
/* Corner case: only detached, nothing attached */
if (n_changes_attached == 0) {
memcpy(changes, changes_detached, sizeof(PortableChange) * n_changes_detached);
*ret_changes = TAKE_PTR(changes);
*ret_n_changes = n_changes_detached;
return 0;
}
@@ -608,17 +608,13 @@ static int normalize_portable_changes(
_cleanup_free_ char *path = NULL, *source = NULL;
path = strdup(changes_detached[i].path);
if (!path) {
r = -ENOMEM;
goto fail;
}
if (!path)
return -ENOMEM;
if (changes_detached[i].source) {
source = strdup(changes_detached[i].source);
if (!source) {
r = -ENOMEM;
goto fail;
}
if (!source)
return -ENOMEM;
}
changes[n_changes++] = (PortableChange) {
@@ -633,10 +629,6 @@ static int normalize_portable_changes(
*ret_changes = TAKE_PTR(changes);
return 0;
fail:
portable_changes_free(changes, n_changes);
return r;
}
int bus_image_common_reattach(
+37
View File
@@ -15,4 +15,41 @@ TEST(eqzero) {
assert_se(!eqzero(longer));
}
static void my_destructor(struct iovec *iov, size_t n) {
/* not really a destructor, just something we can use to check if the destruction worked */
memset(iov, 'y', sizeof(struct iovec) * n);
}
TEST(cleanup_array) {
struct iovec *iov, *saved_iov;
size_t n, saved_n;
n = 7;
iov = new(struct iovec, n);
assert_se(iov);
memset(iov, 'x', sizeof(struct iovec) * n);
saved_iov = iov;
saved_n = n;
{
assert_se(memeqbyte('x', saved_iov, sizeof(struct iovec) * saved_n));
assert_se(iov);
assert_se(n > 0);
CLEANUP_ARRAY(iov, n, my_destructor);
assert_se(memeqbyte('x', saved_iov, sizeof(struct iovec) * saved_n));
assert_se(iov);
assert_se(n > 0);
}
assert_se(memeqbyte('y', saved_iov, sizeof(struct iovec) * saved_n));
assert_se(!iov);
assert_se(n == 0);
free(saved_iov);
}
DEFINE_TEST_MAIN(LOG_INFO);