From ead3df255f79f60257ae9626e7d52838de3caa67 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 5 Jan 2022 15:14:32 +0100 Subject: Added docs on checkauto util program. Renamed (mainly internal) c_rawstr type to crawstr. --- docs/ccommon_api.md | 51 ++++++++++++++++++++++++++++++++++++++------------ docs/cmap_api.md | 10 ++++------ docs/cstr_api.md | 6 ------ examples/runall.sh | 2 +- include/stc/cbox.h | 29 ++++++++++++++-------------- include/stc/ccommon.h | 11 ++++------- include/stc/template.h | 4 ++-- 7 files changed, 64 insertions(+), 49 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 10404a32..9fc33dc1 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -6,11 +6,6 @@ The following handy macros are safe to use, i.e. have no side-effects. General ***defer*** mechanics for resource acquisition. These macros allows to specify the release of the resource where the resource acquisition takes place. Makes it easier to verify that resources are released. -**NB**: These macros are one-time executed **for-loops**. Use ***only*** `c_breakauto` in order to break out -of these `c_auto*`-blocks! ***Do not*** use `return` or `goto` (or `break`) inside them, as they will -prevent the `end`-statement to be executed when leaving scope. This is not particular to the `c_auto*()` -macros, as one must always make sure to unwind temporary allocated resources before a `return` in C. - | Usage | Description | |:---------------------------------------|:-----------------------------------------------------| | `c_auto (Type, var...)` | `c_autovar (Type var=Type_init(), Type_drop(&var))` | @@ -78,6 +73,36 @@ int main() printf("%s\n", i.ref->str); } ``` +### The checkauto utility program (for RAII) +The **checkauto** program will check the source code for any misuses of the `c_auto*` macros that +will lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, +so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable +the cleanup/drop method to be called. However, a `break` may (originally) been intended to break an immediate +loop/switch outside the `c_auto` scope, so it would not work as intended in any case. The **checkauto** +tool will report any such misusages. In general, one should therefore first break out of any inner loops +with `break`, then use `c_breakauto` to break out of the `c_auto` scope(s). After this `return` may be used. + +Note that this is not a particular issue with the `c_auto*`-macros, as one must always make sure to unwind +temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, +- it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. +- it prevent forgetting to call the destructor at the end. +```c +for (int i = 0; i -typedef struct { cstr name, last; } Person; +typedef struct { cstr name, email; } Person; -Person Person_new(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; +Person Person_from(const char* name, const char* email) { + return (Person){.name = cstr_from(name), .email = cstr_from(email)}; } Person Person_clone(Person p) { p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); + p.email = cstr_clone(p.email); return p; } void Person_drop(Person* p) { - printf("drop: %s %s\n", p->name.str, p->last.str); - c_drop(cstr, &p->name, &p->last); + printf("drop: %s %s\n", p->name.str, p->email.str); + c_drop(cstr, &p->name, &p->email); } -#define i_val Person -#define i_valdrop Person_drop -#define i_valfrom Person_clone +#define i_val_bind Person // bind Person clone+drop fn's #define i_opt c_no_cmp // compare by .get addresses only -#define i_tag prs +#define i_type PBox #include int main() { - c_autovar (cbox_prs p = cbox_prs_new(Person_new("John", "Smiths")), cbox_prs_drop(&p)) - c_autovar (cbox_prs q = cbox_prs_clone(p), cbox_prs_drop(&q)) + c_auto (PBox, p, q) { - cstr_assign(&q.get->name, "Joe"); + p = PBox_from(Person_from("John Smiths", "josmiths@gmail.com")); + q = PBox_clone(p); + cstr_assign(&q.get->name, "Joe Smiths"); - printf("%s %s.\n", p.get->name.str, p.get->last.str); - printf("%s %s.\n", q.get->name.str, q.get->last.str); + printf("%s %s.\n", p.get->name.str, p.get->email.str); + printf("%s %s.\n", q.get->name.str, q.get->email.str); } } */ diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 60e12433..2b1f38a2 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -106,13 +106,10 @@ typedef const char c_strlit[]; /* Generic algorithms */ -typedef char* c_mutstr; -typedef const char* c_rawstr; -#define c_rawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) -#define c_rawstr_eq(xp, yp) (!strcmp(*(xp), *(yp))) -#define c_rawstr_hash(p, dummy) c_strhash(*(p)) -#define c_rawstr_clone(s) strcpy((char*)c_malloc(strlen(s) + 1), s) -#define c_rawstr_drop(p) c_free((char *) &**(p)) +typedef const char* crawstr; +#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) +#define crawstr_eq(xp, yp) (!strcmp(*(xp), *(yp))) +#define crawstr_hash(p, dummy) c_strhash(*(p)) #define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/template.h b/include/stc/template.h index 16218ecb..7670ec92 100644 --- a/include/stc/template.h +++ b/include/stc/template.h @@ -57,7 +57,7 @@ #ifdef i_key_str #define i_key_bind cstr - #define i_keyraw c_rawstr + #define i_keyraw crawstr #ifndef i_tag #define i_tag str #endif @@ -116,7 +116,7 @@ #ifdef i_val_str #define i_val_bind cstr - #define i_valraw c_rawstr + #define i_valraw crawstr #if !defined i_tag && !defined i_key #define i_tag str #endif -- cgit v1.2.3