From 40006c00d290cddebcf4373cbd8e6cf80e1f5123 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Mon, 28 Apr 2025 10:32:18 +0800 Subject: [PATCH 01/10] improve list encode/decode --- compiler/capnpc-c.c | 18 ++++++++++-------- examples/book/book.h | 2 +- examples/book/test.c | 11 +++++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 8d98544..87d9c1f 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -1231,14 +1231,14 @@ void mk_struct_list_encoder(capnp_ctx_t *ctx, struct node *n) { str_addf(&(ctx->SRC), "void encode_%s_list(struct capn_segment *cs, %s_list *l,int " - "count,%s *s) {\n", + "count,%s **s) {\n", n->name.str, n->name.str, buf); str_addf(&(ctx->SRC), "\t%s_list lst;\n", n->name.str); str_addf(&(ctx->SRC), "\tint i;\n"); str_addf(&(ctx->SRC), "\tlst = new_%s_list(cs, count);\n", n->name.str); str_addf(&(ctx->SRC), "\tfor(i = 0; i < count; i ++) {\n"); str_addf(&(ctx->SRC), "\t\tstruct %s d;\n", n->name.str); - str_addf(&(ctx->SRC), "\t\tencode_%s(cs, &d, &(s[i]));\n", n->name.str); + str_addf(&(ctx->SRC), "\t\tencode_%s(cs, &d, s[i]);\n", n->name.str); str_addf(&(ctx->SRC), "\t\tset_%s(&d, lst, i);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t(*l) = lst;\n"); @@ -1295,18 +1295,20 @@ void mk_struct_list_decoder(capnp_ctx_t *ctx, struct node *n) { } str_addf(&(ctx->SRC), - "void decode_%s_list(int *pcount, %s **d, %s_list list) {\n", + "void decode_%s_list(int *pcount, %s ***d, %s_list list) {\n", n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "\tint i;\n"); str_addf(&(ctx->SRC), "\tint nc;\n"); - str_addf(&(ctx->SRC), "\t%s *ptr;\n", buf); + str_addf(&(ctx->SRC), "\t%s **ptr;\n", buf); str_addf(&(ctx->SRC), "\tcapn_resolve(&(list.p));\n"); str_addf(&(ctx->SRC), "\tnc = list.p.len;\n"); - str_addf(&(ctx->SRC), "\tptr = (%s *)calloc(nc, sizeof(%s));\n", buf, buf); + str_addf(&(ctx->SRC), "\tptr = (%s **)calloc(nc, sizeof(%s *));\n", buf, buf); str_addf(&(ctx->SRC), "\tfor(i = 0; i < nc; i ++) {\n"); str_addf(&(ctx->SRC), "\t\tstruct %s s;\n", n->name.str); str_addf(&(ctx->SRC), "\t\tget_%s(&s, list, i);\n", n->name.str); - str_addf(&(ctx->SRC), "\t\tdecode_%s(&(ptr[i]), &s);\n", n->name.str); + str_addf(&(ctx->SRC), "\t\tptr[i] = (%s *)calloc(1, sizeof(%s));\n", + buf, buf); + str_addf(&(ctx->SRC), "\t\tdecode_%s(ptr[i], &s);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t(*d) = ptr;\n"); str_addf(&(ctx->SRC), "\t(*pcount) = nc;\n"); @@ -2102,9 +2104,9 @@ static void mk_codec_declares(capnp_ctx_t *ctx, const char *n1, n2); str_addf(&(ctx->HDR), "void decode_%s(%s *, struct %s *);\n", n1, n2, n1); str_addf(&(ctx->HDR), - "void encode_%s_list(struct capn_segment *,%s_list *, int, %s *);\n", + "void encode_%s_list(struct capn_segment *,%s_list *, int, %s **);\n", n1, n1, n2); - str_addf(&(ctx->HDR), "void decode_%s_list(int *, %s **, %s_list);\n", n1, n2, + str_addf(&(ctx->HDR), "void decode_%s_list(int *, %s ***, %s_list);\n", n1, n2, n1); str_addf(&(ctx->HDR), "void encode_%s_ptr(struct capn_segment*, %s_ptr *, %s *);\n", n1, diff --git a/examples/book/book.h b/examples/book/book.h index 2c6bd77..cee7016 100644 --- a/examples/book/book.h +++ b/examples/book/book.h @@ -25,7 +25,7 @@ typedef struct { int n_authors; char **authors; int n_chapters; - chapter_t *chapters_; + chapter_t **chapters_; publish_t *publish; nulldata_t *nulldata; int n_magic1; diff --git a/examples/book/test.c b/examples/book/test.c index 357f918..b2c9f86 100644 --- a/examples/book/test.c +++ b/examples/book/test.c @@ -20,7 +20,7 @@ int encode() { uint32_t magic1[2] = { 1101,1012 }; - chapter_t chapters[3] = { + chapter_t chapters_[3] = { {.caption ="Chapter1", .start =1, .end=99}, @@ -31,6 +31,9 @@ int encode() { .start = 151, .end=199} }; + chapter_t* chapters[3] = { + &chapters_[0], &chapters_[1], &chapters_[2] + }; publish_t publish = { .isbn = 335677, .year =2001 @@ -87,10 +90,10 @@ int decode() { printf("chapters(%d):\n", book->n_chapters); for(i = 0; i < book->n_chapters; i ++) { - printf("\tcaption: %s\n", book->chapters_[i].caption); + printf("\tcaption: %s\n", book->chapters_[i]->caption); printf("\tfrom %d to %d\n", - book->chapters_[i].start, - book->chapters_[i].end); + book->chapters_[i]->start, + book->chapters_[i]->end); } printf("ISBN: %lu year: %u\n", From dd1fbd4043083655ebb5cb545762678c84b2bf98 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Wed, 7 May 2025 18:04:13 +0800 Subject: [PATCH 02/10] auto generate memory free code for decode data --- compiler/capnpc-c.c | 304 ++++++++++++++++++++++++++++++++++++++++--- examples/book/test.c | 3 + xmake.lua | 4 +- 3 files changed, 294 insertions(+), 17 deletions(-) diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 87d9c1f..6fae492 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -921,6 +921,31 @@ static void mk_simple_list_decoder(struct str *func, const char *tab, str_addf(func, "}\n"); } +static void mk_simple_list_free(struct str *func, const char *tab, + const char *list_type, const char *getf, + const char *dvar, const char *cvar, + const char *svar) { + str_add(func, tab, -1); + str_addf(func, "if (1) {\n"); + str_add(func, tab, -1); + str_addf(func, "\tint i_, nc_ = d->%s;\n", cvar); + if (strcmp(list_type, "text") == 0) { + str_add(func, tab, -1); + str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); + str_add(func, tab, -1); + str_addf(func, "\t\tif (d->%s[i_] == NULL) continue;\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t\tfree(d->%s[i_]);\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t}\n"); + } + + str_add(func, tab, -1); + str_addf(func, "\tfree(d->%s);\n", dvar); + str_add(func, tab, -1); + str_addf(func, "}\n"); +} + static void gen_call_list_encoder(capnp_ctx_t *ctx, struct str *func, struct Type *type, const char *tab, const char *var, const char *countvar, @@ -1039,6 +1064,77 @@ static void gen_call_list_decoder(capnp_ctx_t *ctx, struct str *func, } } +static void gen_call_list_free(capnp_ctx_t *ctx, struct str *func, + struct Type *type, const char *tab, + const char *var, const char *countvar, + const char *var2) { + char *t = NULL; + struct node *n = NULL; + + str_add(func, tab, -1); + + switch (type->which) { + case Type__bool: + t = "uint8_t"; + mk_simple_list_free(func, tab, t, "get1", var, countvar, var2); + break; + case Type_int8: + case Type_uint8: + if (type->which == Type_int8) { + t = "int8_t"; + } else { + t = "uint8_t"; + } + mk_simple_list_free(func, tab, t, "get8", var, countvar, var2); + break; + case Type_int16: + case Type_uint16: + if (type->which == Type_int16) { + t = "int16_t"; + } else { + t = "uint16_t"; + } + mk_simple_list_free(func, tab, t, "get16", var, countvar, var2); + break; + case Type_int32: + case Type_uint32: + case Type_float32: + if (type->which == Type_int32) { + t = "int32_t"; + } else if (type->which == Type_uint32) { + t = "uint32_t"; + } else { + t = "float"; + } + mk_simple_list_free(func, tab, t, "get32", var, countvar, var2); + break; + case Type_int64: + case Type_uint64: + case Type_float64: + if (type->which == Type_int64) { + t = "int64_t"; + } else if (type->which == Type_uint64) { + t = "uint64_t"; + } else { + t = "double"; + } + mk_simple_list_free(func, tab, t, "get64", var, countvar, var2); + break; + + case Type_text: + mk_simple_list_free(func, tab, "text", NULL, var, countvar, var2); + break; + case Type__struct: + n = find_node(ctx, type->_struct.typeId); + if (n != NULL) { + char *dtypename = n->name.str; + + str_addf(func, "free_%s_list(d->%s, d->%s);\n", dtypename, countvar, var); + } + break; + } +} + static void encode_member(capnp_ctx_t *ctx, struct str *func, struct field *f, const char *tab, const char *var, const char *var2) { struct Type list_type; @@ -1214,6 +1310,93 @@ static void decode_member(capnp_ctx_t *ctx, struct str *func, struct field *f, } } +static void free_member(capnp_ctx_t *ctx, struct str *func, struct field *f, + const char *tab, const char *var, const char *var2) { + struct Type list_type; + struct node *n = NULL; + + if (f->v.t.which == Type__void) { + return; + } + + if (var2 == NULL) { + var2 = var; + } + + switch (f->v.t.which) { + case Type__bool: + case Type_int8: + case Type_int16: + case Type_int32: + case Type_int64: + case Type_uint8: + case Type_uint16: + case Type_uint32: + case Type_uint64: + case Type_float32: + case Type_float64: + case Type__enum: + break; + case Type_text: + str_add(func, tab, -1); + str_addf(func, "if (d->%s != NULL) {\n", var2); + str_add(func, tab, -1); + str_addf(func, "\tfree(d->%s);\n", var2); + str_add(func, tab, -1); + str_addf(func, "}\n"); + break; + case Type__struct: + n = find_node(ctx, f->v.t._struct.typeId); + if (n != NULL) { + str_add(func, tab, -1); + str_addf(func, "free_%s_ptr(&(d->%s));\n", n->name.str, var2); + } + break; + case Type__list: + read_Type(&list_type, f->v.t._list.elementType); + if (list_type.which != Type__void) { + char *name = NULL; + char *ncount = NULL; + char buf[256]; + + name = (char *)get_mapname(f->f.annotations); + if (name == NULL) { + var2 = var; + } else { + var2 = name; + } + + ncount = (char *)get_maplistcount(f->f.annotations); + if (ncount != NULL) { + sprintf(buf, "%s", ncount); + } else { + char buf2[256]; + char *p; + + strcpy(buf2, var2); + p = strchr(buf2, '.'); + if (p != NULL) { + *p = 0x0; + p++; + } + + strcpy(buf, buf2); + if (p != NULL) { + strcat(buf, "."); + sprintf(&buf[strlen(buf)], "n_%s", p); + } + } + + gen_call_list_free(ctx, func, &list_type, tab, var2, buf, var); + } + break; + default: + str_add(func, tab, -1); + str_addf(func, "\t /* %s %s */\n", var2, var); + break; + } +} + void mk_struct_list_encoder(capnp_ctx_t *ctx, struct node *n) { if (n == NULL) { return; @@ -1302,12 +1485,13 @@ void mk_struct_list_decoder(capnp_ctx_t *ctx, struct node *n) { str_addf(&(ctx->SRC), "\t%s **ptr;\n", buf); str_addf(&(ctx->SRC), "\tcapn_resolve(&(list.p));\n"); str_addf(&(ctx->SRC), "\tnc = list.p.len;\n"); - str_addf(&(ctx->SRC), "\tptr = (%s **)calloc(nc, sizeof(%s *));\n", buf, buf); + str_addf(&(ctx->SRC), "\tptr = (%s **)calloc(nc, sizeof(%s *));\n", buf, + buf); str_addf(&(ctx->SRC), "\tfor(i = 0; i < nc; i ++) {\n"); str_addf(&(ctx->SRC), "\t\tstruct %s s;\n", n->name.str); str_addf(&(ctx->SRC), "\t\tget_%s(&s, list, i);\n", n->name.str); - str_addf(&(ctx->SRC), "\t\tptr[i] = (%s *)calloc(1, sizeof(%s));\n", - buf, buf); + str_addf(&(ctx->SRC), "\t\tptr[i] = (%s *)calloc(1, sizeof(%s));\n", buf, + buf); str_addf(&(ctx->SRC), "\t\tdecode_%s(ptr[i], &s);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t(*d) = ptr;\n"); @@ -1343,6 +1527,61 @@ void mk_struct_ptr_decoder(capnp_ctx_t *ctx, struct node *n) { str_addf(&(ctx->SRC), "}\n"); } +void mk_struct_list_free(capnp_ctx_t *ctx, struct node *n) { + if (n == NULL) { + return; + } + + if (1) { + char *mapname = (char *)get_mapname(n->n.annotations); + char buf[256]; + + if (mapname == NULL) { + sprintf(buf, "struct %s_", n->name.str); + } else { + strcpy(buf, mapname); + } + + str_addf(&(ctx->SRC), "void free_%s_list(int pcount, %s **d) {\n", + n->name.str, buf); + str_addf(&(ctx->SRC), "\tint i;\n"); + str_addf(&(ctx->SRC), "\tint nc = pcount;\n"); + str_addf(&(ctx->SRC), "\t%s **ptr = d;\n", buf); + str_addf(&(ctx->SRC), "\tif (ptr == NULL) return;\n"); + str_addf(&(ctx->SRC), "\tfor(i = 0; i < nc; i ++) {\n"); + str_addf(&(ctx->SRC), "\t\tif(ptr[i] == NULL) continue;\n"); + str_addf(&(ctx->SRC), "\t\tfree_%s(ptr[i]);\n", n->name.str); + str_addf(&(ctx->SRC), "\t\tfree(ptr[i]);\n"); + str_addf(&(ctx->SRC), "\t}\n"); + str_addf(&(ctx->SRC), "\tfree(ptr);\n"); + str_addf(&(ctx->SRC), "}\n"); + } +} + +void mk_struct_ptr_free(capnp_ctx_t *ctx, struct node *n) { + char *mapname; + char buf[256]; + + if (n == NULL) { + return; + } + + mapname = (char *)get_mapname(n->n.annotations); + + if (mapname == NULL) { + sprintf(buf, "struct %s_", n->name.str); + } else { + strcpy(buf, mapname); + } + + str_addf(&(ctx->SRC), "void free_%s_ptr(%s **d){\n", n->name.str, buf); + str_addf(&(ctx->SRC), "\tif((*d) == NULL) return;\n"); + str_addf(&(ctx->SRC), "\tfree_%s(*d);\n", n->name.str); + str_addf(&(ctx->SRC), "\tfree(*d);\n"); + str_addf(&(ctx->SRC), "\t(*d) = NULL;\n"); + str_addf(&(ctx->SRC), "}\n"); +} + struct strings { struct str ftab; struct str dtab; @@ -1350,6 +1589,7 @@ struct strings { struct str set; struct str encoder; struct str decoder; + struct str freeup; struct str enums; struct str decl; struct str var; @@ -1516,6 +1756,8 @@ static void union_block(capnp_ctx_t *ctx, struct strings *s, struct field *f, str_addf(&s->encoder, "%sbreak;\n", s->ftab.str); decode_member(ctx, &s->decoder, f, s->ftab.str, var1, var2); str_addf(&s->decoder, "%sbreak;\n", s->ftab.str); + free_member(ctx, &s->freeup, f, s->ftab.str, var1, var2); + str_addf(&s->freeup, "%sbreak;\n", s->ftab.str); } str_setlen(&s->ftab, s->ftab.len - 1); } @@ -1548,6 +1790,8 @@ static void union_cases(capnp_ctx_t *ctx, struct strings *s, struct node *n, field_name(f)); str_addf(&s->decoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); + str_addf(&s->freeup, "%scase %s_%s:\n", s->ftab.str, n->name.str, + field_name(f)); } if (u) { @@ -1573,11 +1817,13 @@ static void declare_slot(struct strings *s, struct field *f) { static void define_group(capnp_ctx_t *ctx, struct strings *s, struct node *n, const char *group_name, bool enclose_unions, - const char *extattr, const char *extattr_space); + const char *extattr, const char *extattr_space, + const char *uniontag); static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, struct field *first_field, const char *union_name, - const char *extattr, const char *extattr_space) { + const char *extattr, const char *extattr_space, + const char *uniontag) { int tagoff = 2 * n->n._struct.discriminantOffset; struct field *f; static struct str tag = STR_INIT; @@ -1617,6 +1863,7 @@ static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, str_addf(&s->encoder, "%sswitch (%s) {\n", s->ftab.str, var); str_addf(&s->decoder, "%sswitch (%s) {\n", s->ftab.str, tag.str); + str_addf(&s->freeup, "%sswitch (%s) {\n", s->ftab.str, uniontag); } /* if we have a bunch of the same C type with zero defaults, we @@ -1660,12 +1907,13 @@ static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, // own struct so that its members do not overwrite its own // discriminant. define_group(ctx, s, f->group, field_name(f), true, extattr, - extattr_space); + extattr_space, uniontag); str_addf(&s->get, "%sbreak;\n", s->ftab.str); str_addf(&s->set, "%sbreak;\n", s->ftab.str); if (ctx->g_codecgen) { str_addf(&s->encoder, "%sbreak;\n", s->ftab.str); str_addf(&s->decoder, "%sbreak;\n", s->ftab.str); + str_addf(&s->freeup, "%sbreak;\n", s->ftab.str); } str_setlen(&s->ftab, s->ftab.len - 1); break; @@ -1682,6 +1930,8 @@ static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, field_name(f)); str_addf(&s->decoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); + str_addf(&s->freeup, "%scase %s_%s:\n", s->ftab.str, n->name.str, + field_name(f)); } union_block( ctx, s, f, @@ -1713,6 +1963,8 @@ static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, s->ftab.str, s->ftab.str); str_addf(&s->decoder, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, s->ftab.str, s->ftab.str); + str_addf(&s->freeup, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, + s->ftab.str, s->ftab.str); } str_addf(&enums, "\n};\n"); @@ -1736,11 +1988,16 @@ static void define_field(capnp_ctx_t *ctx, struct strings *s, struct field *f, get_mapname(f->f.annotations)); decode_member(ctx, &s->decoder, f, s->ftab.str, field_name(f), get_mapname(f->f.annotations)); + free_member(ctx, &s->freeup, f, s->ftab.str, field_name(f), + get_mapname(f->f.annotations)); } break; case Field_group: if (ctx->g_codecgen) { + char uniontagvar[256]; + + memset(uniontagvar, 0x0, sizeof(uniontagvar)); if (f->group != NULL) { int flen = capn_len(f->group->n._struct.fields); int ulen = f->group->n._struct.discriminantCount; @@ -1760,12 +2017,16 @@ static void define_field(capnp_ctx_t *ctx, struct strings *s, struct field *f, buf); str_addf(&s->decoder, "\td->%s = s->%s_which;\n", buf, field_name(f)); + sprintf(uniontagvar, "d->%s", buf); } } } + define_group(ctx, s, f->group, field_name(f), false, extattr, + extattr_space, uniontagvar); + } else { + define_group(ctx, s, f->group, field_name(f), false, extattr, + extattr_space, NULL); } - define_group(ctx, s, f->group, field_name(f), false, extattr, - extattr_space); break; } } @@ -1814,7 +2075,8 @@ static void define_encode_function(capnp_ctx_t *ctx, struct node *node, const char *extattr_space) {} static void define_group(capnp_ctx_t *ctx, struct strings *s, struct node *n, const char *group_name, bool enclose_unions, - const char *extattr, const char *extattr_space) { + const char *extattr, const char *extattr_space, + const char *uniontag) { struct field *f; int flen = capn_len(n->n._struct.fields); int ulen = n->n._struct.discriminantCount; @@ -1879,7 +2141,7 @@ static void define_group(capnp_ctx_t *ctx, struct strings *s, struct node *n, const bool keep_union_name = named_union && !enclose_unions; do_union(ctx, s, n, f, keep_union_name ? group_name : NULL, extattr, - extattr_space); + extattr_space, uniontag); while (f < n->fields + flen && in_union(f)) f++; @@ -1916,6 +2178,7 @@ static void define_struct(capnp_ctx_t *ctx, struct node *n, const char *extattr, str_reset(&s.set); str_reset(&s.encoder); str_reset(&s.decoder); + str_reset(&s.freeup); str_reset(&s.enums); str_reset(&s.decl); str_reset(&s.var); @@ -1942,7 +2205,7 @@ static void define_struct(capnp_ctx_t *ctx, struct node *n, const char *extattr, } } - define_group(ctx, &s, n, NULL, false, extattr, extattr_space); + define_group(ctx, &s, n, NULL, false, extattr, extattr_space, NULL); str_add(&(ctx->HDR), s.enums.str, s.enums.len); @@ -2043,6 +2306,9 @@ static void define_struct(capnp_ctx_t *ctx, struct node *n, const char *extattr, n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "%s\n", s.decoder.str); str_addf(&(ctx->SRC), "}\n"); + str_addf(&(ctx->SRC), "\nvoid free_%s(%s *d) {\n", n->name.str, buf); + str_addf(&(ctx->SRC), "%s\n", s.freeup.str); + str_addf(&(ctx->SRC), "}\n"); } str_add(&(ctx->SRC), s.pub_get.str, s.pub_get.len); @@ -2103,15 +2369,19 @@ static void mk_codec_declares(capnp_ctx_t *ctx, const char *n1, "void encode_%s(struct capn_segment *,struct %s *, %s *);\n", n1, n1, n2); str_addf(&(ctx->HDR), "void decode_%s(%s *, struct %s *);\n", n1, n2, n1); - str_addf(&(ctx->HDR), - "void encode_%s_list(struct capn_segment *,%s_list *, int, %s **);\n", - n1, n1, n2); - str_addf(&(ctx->HDR), "void decode_%s_list(int *, %s ***, %s_list);\n", n1, n2, - n1); + str_addf(&(ctx->HDR), "void free_%s(%s *);\n", n1, n2); + str_addf( + &(ctx->HDR), + "void encode_%s_list(struct capn_segment *,%s_list *, int, %s **);\n", n1, + n1, n2); + str_addf(&(ctx->HDR), "void decode_%s_list(int *, %s ***, %s_list);\n", n1, + n2, n1); + str_addf(&(ctx->HDR), "void free_%s_list(int, %s **);\n", n1, n2); str_addf(&(ctx->HDR), "void encode_%s_ptr(struct capn_segment*, %s_ptr *, %s *);\n", n1, n1, n2); str_addf(&(ctx->HDR), "void decode_%s_ptr(%s **, %s_ptr);\n", n1, n2, n1); + str_addf(&(ctx->HDR), "void free_%s_ptr(%s **);\n", n1, n2); } static void declare_codec(capnp_ctx_t *ctx, struct node *file_node) { struct node *n; @@ -2434,6 +2704,8 @@ int ctx_gen(capnp_ctx_t *ctx) { mk_struct_ptr_encoder(ctx, n); mk_struct_list_decoder(ctx, n); mk_struct_ptr_decoder(ctx, n); + mk_struct_list_free(ctx, n); + mk_struct_ptr_free(ctx, n); } } diff --git a/examples/book/test.c b/examples/book/test.c index b2c9f86..6e1c560 100644 --- a/examples/book/test.c +++ b/examples/book/test.c @@ -112,6 +112,9 @@ int decode() { printf("%s\n", book->acquire.donation); } + free_Book_ptr(&book); + capn_free(&c); + return 0; } diff --git a/xmake.lua b/xmake.lua index 5c5bbf4..e0cda0f 100644 --- a/xmake.lua +++ b/xmake.lua @@ -49,10 +49,12 @@ target("book") add_files("examples/book/*.c") add_includedirs("compiler","lib","examples/book") add_deps("CapnC_Runtime", "capnpc-c") + add_cflags("-fsanitize=address") + add_ldflags("-fsanitize=address") xpack("capnpc-c") set_formats("targz") set_title("c-capnproto") set_licensefile("COPYING") add_targets("capnpc-c", "CapnC_Runtime") - \ No newline at end of file + From dd651787245d89237ae3d7c0eee0957de22437ae Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Thu, 8 May 2025 09:13:06 +0800 Subject: [PATCH 03/10] fix issue of unused variable --- compiler/capnpc-c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 6fae492..74e1efa 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -929,6 +929,8 @@ static void mk_simple_list_free(struct str *func, const char *tab, str_addf(func, "if (1) {\n"); str_add(func, tab, -1); str_addf(func, "\tint i_, nc_ = d->%s;\n", cvar); + str_add(func, tab, -1); + str_addf(func, "\tcapnp_use(i_);capnp_use(nc_);\n"); if (strcmp(list_type, "text") == 0) { str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); From 6c0fbc4bbd255e82e45c0c37d180612cc82ae62b Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Thu, 8 May 2025 09:42:09 +0800 Subject: [PATCH 04/10] test with nest union --- examples/book/book.capnp | 9 ++++++- examples/book/book.h | 52 +++++++++++++++++++++++----------------- examples/book/test.c | 15 ++++++++++-- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/examples/book/book.capnp b/examples/book/book.capnp index c9c13ac..1e759de 100644 --- a/examples/book/book.capnp +++ b/examples/book/book.capnp @@ -20,6 +20,13 @@ struct Nulldata $C.mapname("nulldata_t") { null @0: UInt32 $C.mapname("null_"); } +struct Buy $C.mapname("buy_t") { + from @0: Text; + u :union $C.mapname("u") $C.mapuniontag("with_recipe") { + norecipe @1: Void; + recipeAddr @2: Text $C.mapname("recipe_addr"); + } +} struct Book $C.mapname("book_t") { title @0: Text; authors @1: List(Text) $C.mapname("authors") $C.maplistcount("n_authors"); @@ -29,7 +36,7 @@ struct Book $C.mapname("book_t") { magic1 @2: List(UInt32) $C.mapname("magic_1") $C.maplistcount("n_magic1"); description @8: Text; acquire :union $C.mapuniontag("acquire_method") { - buy @3: Text; + buy @3: Buy; donation @4: Text; } } diff --git a/examples/book/book.h b/examples/book/book.h index cee7016..91a9b9f 100644 --- a/examples/book/book.h +++ b/examples/book/book.h @@ -6,36 +6,44 @@ #include typedef struct { - char *caption; - int32_t start; - int32_t end; + char *caption; + int32_t start; + int32_t end; } chapter_t; typedef struct { - uint64_t isbn; - uint32_t year; + uint64_t isbn; + uint32_t year; } publish_t; - + typedef struct { - int null_; + int null_; } nulldata_t; typedef struct { - char *title; - int n_authors; - char **authors; - int n_chapters; - chapter_t **chapters_; - publish_t *publish; - nulldata_t *nulldata; - int n_magic1; - uint32_t *magic_1; - char *description; - int acquire_method; - union { - char *buy; - char *donation; - } acquire; + char *from; + int with_recipe; + union { + char *recipe_addr; + } u; +} buy_t; + +typedef struct { + char *title; + int n_authors; + char **authors; + int n_chapters; + chapter_t **chapters_; + publish_t *publish; + nulldata_t *nulldata; + int n_magic1; + uint32_t *magic_1; + char *description; + int acquire_method; + union { + buy_t *buy; + char *donation; + } acquire; } book_t; #endif diff --git a/examples/book/test.c b/examples/book/test.c index 6e1c560..7e6272f 100644 --- a/examples/book/test.c +++ b/examples/book/test.c @@ -38,6 +38,13 @@ int encode() { .isbn = 335677, .year =2001 }; + buy_t buy = { + .from = "Xinghua Book store", + .with_recipe = Buy_u_recipeAddr, + .u = { + .recipe_addr = "Xinghua Street" + } + }; struct capn_segment *cs; struct Book b; Book_ptr p; @@ -53,7 +60,7 @@ int encode() { book.magic_1 = &magic1[0]; book.description = NULL; book.acquire_method = Book_acquire_buy; - book.acquire.buy = "bought from Xinhua book store"; + book.acquire.buy = &buy; capn_init_malloc(&c); cs = capn_root(&c).seg; @@ -106,7 +113,11 @@ int decode() { } if (book->acquire_method == Book_acquire_buy) { - printf("%s\n", book->acquire.buy); + printf("buy from %s\n", book->acquire.buy->from); + if (book->acquire.buy->with_recipe == Buy_u_recipeAddr) { + printf("recipe address %s\n", + book->acquire.buy->u.recipe_addr); + } } else { printf("%s\n", book->acquire.donation); From a86c5ab151d008570eb7321416a0a46dd6e19131 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 9 May 2025 13:48:56 +0800 Subject: [PATCH 05/10] use capn_null than zero filled object for null object --- compiler/capnpc-c.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 74e1efa..7dc79db 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -1453,15 +1453,18 @@ void mk_struct_ptr_encoder(capnp_ctx_t *ctx, struct node *n) { n->name.str, n->name.str, buf); str_addf(&(ctx->SRC), "\t%s_ptr ptr;\n", n->name.str); str_addf(&(ctx->SRC), "\tstruct %s d;\n", n->name.str); - str_addf(&(ctx->SRC), "\t%s zero_ = {0}; \n", buf); str_addf(&(ctx->SRC), "\tptr = new_%s(cs);\n", n->name.str); str_addf(&(ctx->SRC), "\tif (s == NULL) {\n"); - str_addf(&(ctx->SRC), "\t\ts = &zero_;\n"); + str_addf(&(ctx->SRC), "\t\tptr.p = capn_null;\n", + n->name.str); + str_addf(&(ctx->SRC), "\t}\n"); + str_addf(&(ctx->SRC), "\telse{\n"); + str_addf(&(ctx->SRC), "\t\tencode_%s(cs, &d, s);\n", n->name.str); + str_addf(&(ctx->SRC), "\t\twrite_%s(&d, ptr);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); - str_addf(&(ctx->SRC), "\tencode_%s(cs, &d, s);\n", n->name.str); - str_addf(&(ctx->SRC), "\twrite_%s(&d, ptr);\n", n->name.str); str_addf(&(ctx->SRC), "\t(*p) = ptr;\n"); str_addf(&(ctx->SRC), "}\n"); + ctx->g_nullused = 1; } void mk_struct_list_decoder(capnp_ctx_t *ctx, struct node *n) { @@ -1523,10 +1526,17 @@ void mk_struct_ptr_decoder(capnp_ctx_t *ctx, struct node *n) { "%s_ptr p) {\n", n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "\tstruct %s s;\n", n->name.str); + str_addf(&(ctx->SRC), "\tcapn_resolve(&(p.p));\n"); + str_addf(&(ctx->SRC), "\tif (p.p.type == CAPN_NULL) {\n", + n->name.str); + str_addf(&(ctx->SRC), "\t\t(*d) = NULL;\n"); + str_addf(&(ctx->SRC), "\t\treturn;\n"); + str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t*d = (%s *)calloc(1, sizeof(%s));\n", buf, buf); str_addf(&(ctx->SRC), "\tread_%s(&s, p);\n", n->name.str); str_addf(&(ctx->SRC), "\tdecode_%s(*d, &s);\n", n->name.str); str_addf(&(ctx->SRC), "}\n"); + ctx->g_nullused = 1; } void mk_struct_list_free(capnp_ctx_t *ctx, struct node *n) { From c1fe4d4a53b23a751e30bf7334b8abf216ee33e2 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 5 Sep 2025 14:54:01 +0800 Subject: [PATCH 06/10] enhance list decode & provide pkgconfig data --- CMakeLists.txt | 4 ++++ c-capnproto.pc.in | 10 +++++----- compiler/capnpc-c.c | 28 +++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0efb933..b7973d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ else() endif() project(c-capnproto LANGUAGES ${languages}) +configure_file(c-capnproto.pc.in c-capnproto.pc) + include(CTest) # set(CMAKE_C_STANDARD 11) @@ -168,6 +170,8 @@ if(C_CAPNPROTO_ENABLE_INSTALL) NAMESPACE CapnC:: FILE CapnCConfig.cmake) install(FILES lib/capnp_c.h TYPE INCLUDE) + install(FILES c-capnproto.pc + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endif() add_subdirectory(examples/book) diff --git a/c-capnproto.pc.in b/c-capnproto.pc.in index 45bd6c7..901ecbe 100644 --- a/c-capnproto.pc.in +++ b/c-capnproto.pc.in @@ -1,8 +1,8 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -bindir=@bindir@ -includedir=@includedir@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${@CMAKE_INSTALL_LIBDIR@} +bindir=${prefix}/bin +includedir=${@CMAKE_INSTALL_INCLUDEDIR@} codegen=${bindir}/capnpc-c Name: c-capnproto diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 7dc79db..beef152 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -887,6 +887,14 @@ static void mk_simple_list_decoder(struct str *func, const char *tab, str_add(func, tab, -1); str_addf(func, "\tnc_ = s->%s.len;\n", svar); str_add(func, tab, -1); + str_addf(func, "\tif (nc_ == 0) {\n"); + str_add(func, tab, -1); + str_addf(func, "\t\td->%s = NULL;\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t\treturn;\n"); + str_add(func, tab, -1); + str_addf(func, "\t}\n"); + str_add(func, tab, -1); str_addf(func, "\td->%s = (char **)calloc(nc_, sizeof(char *));\n", dvar); str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); @@ -903,7 +911,14 @@ static void mk_simple_list_decoder(struct str *func, const char *tab, str_addf(func, "\tcapn_resolve(&(s->%s.p));\n", svar); str_add(func, tab, -1); str_addf(func, "\tnc_ = s->%s.p.len;\n", svar); - + str_add(func, tab, -1); + str_addf(func, "\tif (nc_ == 0) {\n"); + str_add(func, tab, -1); + str_addf(func, "\t\td->%s = NULL;\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t\treturn;\n"); + str_add(func, tab, -1); + str_addf(func, "\t}\n"); str_add(func, tab, -1); str_addf(func, "\td->%s = (%s *)calloc(nc_, sizeof(%s));\n", dvar, list_type, list_type); @@ -1455,8 +1470,7 @@ void mk_struct_ptr_encoder(capnp_ctx_t *ctx, struct node *n) { str_addf(&(ctx->SRC), "\tstruct %s d;\n", n->name.str); str_addf(&(ctx->SRC), "\tptr = new_%s(cs);\n", n->name.str); str_addf(&(ctx->SRC), "\tif (s == NULL) {\n"); - str_addf(&(ctx->SRC), "\t\tptr.p = capn_null;\n", - n->name.str); + str_addf(&(ctx->SRC), "\t\tptr.p = capn_null;\n"); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\telse{\n"); str_addf(&(ctx->SRC), "\t\tencode_%s(cs, &d, s);\n", n->name.str); @@ -1490,6 +1504,11 @@ void mk_struct_list_decoder(capnp_ctx_t *ctx, struct node *n) { str_addf(&(ctx->SRC), "\t%s **ptr;\n", buf); str_addf(&(ctx->SRC), "\tcapn_resolve(&(list.p));\n"); str_addf(&(ctx->SRC), "\tnc = list.p.len;\n"); + str_addf(&(ctx->SRC), "\tif (nc == 0) {\n"); + str_addf(&(ctx->SRC), "\t\t(*d) = NULL;\n"); + str_addf(&(ctx->SRC), "\t\t(*pcount) = 0;\n"); + str_addf(&(ctx->SRC), "\t\treturn;\n"); + str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\tptr = (%s **)calloc(nc, sizeof(%s *));\n", buf, buf); str_addf(&(ctx->SRC), "\tfor(i = 0; i < nc; i ++) {\n"); @@ -1527,8 +1546,7 @@ void mk_struct_ptr_decoder(capnp_ctx_t *ctx, struct node *n) { n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "\tstruct %s s;\n", n->name.str); str_addf(&(ctx->SRC), "\tcapn_resolve(&(p.p));\n"); - str_addf(&(ctx->SRC), "\tif (p.p.type == CAPN_NULL) {\n", - n->name.str); + str_addf(&(ctx->SRC), "\tif (p.p.type == CAPN_NULL) {\n"); str_addf(&(ctx->SRC), "\t\t(*d) = NULL;\n"); str_addf(&(ctx->SRC), "\t\treturn;\n"); str_addf(&(ctx->SRC), "\t}\n"); From 891355581d65e4f9e3aaffd7079deaef0fa4065d Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 5 Sep 2025 15:35:23 +0800 Subject: [PATCH 07/10] fix missed file for cmake install --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7973d2..a31d809 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ endif() option(C_CAPNPROTO_ENABLE_INSTALL "Add instructions for 'cmake --install' of CapnC_Runtime library and capnpc-c executable" ON) if(C_CAPNPROTO_ENABLE_INSTALL) + set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib) install(TARGETS CapnC_Runtime capnpc-c EXPORT CapnC) install(EXPORT CapnC @@ -170,7 +171,7 @@ if(C_CAPNPROTO_ENABLE_INSTALL) NAMESPACE CapnC:: FILE CapnCConfig.cmake) install(FILES lib/capnp_c.h TYPE INCLUDE) - install(FILES c-capnproto.pc + install(FILES build/c-capnproto.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endif() From a8a0da6ced0a4925aeec6833beab238aa1290326 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 5 Sep 2025 15:49:06 +0800 Subject: [PATCH 08/10] fix pkgconfig data --- CMakeLists.txt | 2 +- c-capnproto.pc.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a31d809..a6c0313 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ else() endif() project(c-capnproto LANGUAGES ${languages}) -configure_file(c-capnproto.pc.in c-capnproto.pc) +configure_file(c-capnproto.pc.in c-capnproto.pc @ONLY) include(CTest) diff --git a/c-capnproto.pc.in b/c-capnproto.pc.in index 901ecbe..8924d17 100644 --- a/c-capnproto.pc.in +++ b/c-capnproto.pc.in @@ -1,8 +1,8 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=${@CMAKE_INSTALL_LIBDIR@} +libdir=${prefix}/lib bindir=${prefix}/bin -includedir=${@CMAKE_INSTALL_INCLUDEDIR@} +includedir=${prefix}/include codegen=${bindir}/capnpc-c Name: c-capnproto From 94af71fa0b3169e79d37e14ea8336a14b49b9e36 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Fri, 5 Sep 2025 15:58:36 +0800 Subject: [PATCH 09/10] fix pkg data --- c-capnproto.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c-capnproto.pc.in b/c-capnproto.pc.in index 8924d17..c5409b5 100644 --- a/c-capnproto.pc.in +++ b/c-capnproto.pc.in @@ -8,5 +8,5 @@ codegen=${bindir}/capnpc-c Name: c-capnproto Description: Cap'n Proto C bindings Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lcapnp_c +Libs: -L${libdir} -lCapnC_Runtime Cflags: -I${includedir} From 7484693df13ed0c2f246ff51b9855804c071b8a6 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Mon, 22 Sep 2025 17:34:58 +0800 Subject: [PATCH 10/10] fix decode issue of structure with zero length list --- compiler/capnpc-c.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index beef152..c8eb6f4 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -891,19 +891,21 @@ static void mk_simple_list_decoder(struct str *func, const char *tab, str_add(func, tab, -1); str_addf(func, "\t\td->%s = NULL;\n", dvar); str_add(func, tab, -1); - str_addf(func, "\t\treturn;\n"); - str_add(func, tab, -1); str_addf(func, "\t}\n"); str_add(func, tab, -1); - str_addf(func, "\td->%s = (char **)calloc(nc_, sizeof(char *));\n", dvar); + str_addf(func, "\telse {\n"); str_add(func, tab, -1); - str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); + str_addf(func, "\t\td->%s = (char **)calloc(nc_, sizeof(char *));\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); str_add(func, tab, -1); str_addf(func, - "\t\tcapn_text text_ = capn_get_text(s->%s, i_, capn_val0);\n", + "\t\t\tcapn_text text_ = capn_get_text(s->%s, i_, capn_val0);\n", svar); str_add(func, tab, -1); - str_addf(func, "\t\td->%s[i_] = strdup(text_.str);\n", dvar); + str_addf(func, "\t\t\td->%s[i_] = strdup(text_.str);\n", dvar); + str_add(func, tab, -1); + str_addf(func, "\t\t}\n"); str_add(func, tab, -1); str_addf(func, "\t}\n"); } else { @@ -916,16 +918,18 @@ static void mk_simple_list_decoder(struct str *func, const char *tab, str_add(func, tab, -1); str_addf(func, "\t\td->%s = NULL;\n", dvar); str_add(func, tab, -1); - str_addf(func, "\t\treturn;\n"); - str_add(func, tab, -1); str_addf(func, "\t}\n"); str_add(func, tab, -1); - str_addf(func, "\td->%s = (%s *)calloc(nc_, sizeof(%s));\n", dvar, + str_addf(func, "\telse {\n"); + str_add(func, tab, -1); + str_addf(func, "\t\td->%s = (%s *)calloc(nc_, sizeof(%s));\n", dvar, list_type, list_type); str_add(func, tab, -1); - str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); + str_addf(func, "\t\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); str_add(func, tab, -1); - str_addf(func, "\t\td->%s[i_] = capn_%s(s->%s, i_);\n", dvar, getf, svar); + str_addf(func, "\t\t\td->%s[i_] = capn_%s(s->%s, i_);\n", dvar, getf, svar); + str_add(func, tab, -1); + str_addf(func, "\t\t}\n"); str_add(func, tab, -1); str_addf(func, "\t}\n"); }