diff --git a/include/common/buf.h b/include/common/buf.h index 1051229a..2cd97e35 100644 --- a/include/common/buf.h +++ b/include/common/buf.h @@ -34,7 +34,7 @@ void buf_expand_shell_variables(struct buf *s); /** * buf_init - allocate NULL-terminated C string buffer * @s: buffer - * Note: use free(s->buf) to free it + * Note: use buf_finish(buf) to free it */ void buf_init(struct buf *s); @@ -55,13 +55,41 @@ void buf_add_char(struct buf *s, char data); /** * buf_clear - clear the buffer, internal allocations are preserved * @s: buffer + * + * This is the appropriate function to call to re-use the buffer + * in a loop or similar situations as it simply reuses the already + * existing heap allocations. */ void buf_clear(struct buf *s); /** * buf_reset - reset the buffer, internal allocations are free'd * @s: buffer + * + * The buffer will automatically be re-initialized so can be used again. + * + * This function should not be used in loops as it will free and then + * re-allocate heap memory. However, if the buffer becomes too big + * and the internal allocation should be free'd this is the correct + * function to use. */ void buf_reset(struct buf *s); +/** + * buf_finish - free all internal allocations + * @s: buffer + * + * The state of the buffer after this call is undefined. + * It can be re-initalized via buf_init() however. + * + * Use this for the usual case of a stack allocated buf instance: + * struct buf buf; + * buf_init(&buf); + * buf_add(&buf, "some"); + * buf_add(&buf, "thing"); + * do_something_with(buf.buf); + * buf_finish(&buf); + */ +void buf_finish(struct buf *s); + #endif /* LABWC_BUF_H */ diff --git a/src/action.c b/src/action.c index 3723e42b..25281ab1 100644 --- a/src/action.c +++ b/src/action.c @@ -709,7 +709,7 @@ actions_run(struct view *activator, struct server *server, buf_add(&cmd, action_get_str(action, "command", NULL)); buf_expand_tilde(&cmd); spawn_async_no_shell(cmd.buf); - free(cmd.buf); + buf_finish(&cmd); } break; case ACTION_TYPE_EXIT: diff --git a/src/common/buf.c b/src/common/buf.c index f6bde97f..37505d5f 100644 --- a/src/common/buf.c +++ b/src/common/buf.c @@ -69,7 +69,7 @@ buf_expand_shell_variables(struct buf *s) buf_add_char(&new, s->buf[i]); } } - free(environment_variable.buf); + buf_finish(&environment_variable); free(s->buf); s->buf = new.buf; s->len = new.len; @@ -79,7 +79,10 @@ buf_expand_shell_variables(struct buf *s) void buf_init(struct buf *s) { - /* we can't assert(!s->buf) here because struct may be uninitialized */ + /* + * We can't assert(!s->buf) here because + * the supplied struct may be uninitialized. + */ s->alloc = 256; s->buf = xmalloc(s->alloc); @@ -130,6 +133,21 @@ buf_clear(struct buf *s) void buf_reset(struct buf *s) { - zfree(s->buf); + assert(s->buf); + + buf_finish(s); buf_init(s); } + +void +buf_finish(struct buf *s) +{ + assert(s->buf); + + /* + * Using zfree rather than free ensures that the + * asserts will be triggered whenever something + * other than buf_init() is called on the buffer. + */ + zfree(s->buf); +} diff --git a/src/common/dir.c b/src/common/dir.c index 59db4104..d474c313 100644 --- a/src/common/dir.c +++ b/src/common/dir.c @@ -100,7 +100,7 @@ find_dir(struct ctx *ctx) char *pfxenv = getenv(d.prefix); buf_add(&prefix, pfxenv ? pfxenv : d.default_prefix); if (!prefix.len) { - free(prefix.buf); + buf_finish(&prefix); continue; } @@ -130,7 +130,7 @@ find_dir(struct ctx *ctx) wl_list_append(ctx->list, &path->link); } g_strfreev(prefixes); - free(prefix.buf); + buf_finish(&prefix); } } diff --git a/src/config/rcxml.c b/src/config/rcxml.c index d6a926d0..c1ed4801 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -1539,7 +1539,7 @@ rcxml_read(const char *filename) zfree(line); fclose(stream); rcxml_parse_xml(&b); - zfree(b.buf); + buf_finish(&b); if (!should_merge_config) { break; } diff --git a/src/config/session.c b/src/config/session.c index ee56b548..3da3898b 100644 --- a/src/config/session.c +++ b/src/config/session.c @@ -55,7 +55,7 @@ process_line(char *line) buf_expand_shell_variables(&value); buf_expand_tilde(&value); setenv(key, value.buf, 1); - free(value.buf); + buf_finish(&value); } /* return true on successful read */ diff --git a/src/menu/menu.c b/src/menu/menu.c index 822f5932..37bcef51 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -543,7 +543,7 @@ parse(struct server *server, FILE *stream) xmlFreeDoc(d); xmlCleanupParser(); err: - free(b.buf); + buf_finish(&b); } static void diff --git a/src/osd.c b/src/osd.c index 85e9f433..b66a9eb2 100644 --- a/src/osd.c +++ b/src/osd.c @@ -442,7 +442,7 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h, y += theme->osd_window_switcher_item_height; } - free(buf.buf); + buf_finish(&buf); g_object_unref(layout); cairo_surface_flush(surf);