Matthew DeVore <matvore@xxxxxxxxxxx> writes: >> convention, and it may even be a useful one (i.e. it allows you to >> calloc() a structure with an embedded strbuf in it and the "if >> .buf==NULL, call strbuf_init() lazily" can become an established >> pattern), but at the same time it feels a bit brittle. > > Is it brittle because a strbuf may be initialized to non-zero memory, and so > the "if (buf.buf == NULL)" may evaluate to false, and then go on treating > garbage like a valid buffer? It is brittle because callers are bound to forget doing "if (!x->buf.buf) lazy_init(&x->buf)" at some point, and blindly use an uninitialized x->buf. Making sure x->buf is always initialized before any caller touches is the only way to solve it, and as you said, there are two possible ways to make that happen. One way that does not violate the current API contract is to make sure whoever allocates and/or initializes the surrounding struct that embeds a strbuf does strbuf_init(&x->buf) before any user sees the struct. Another would be to update strbuf API so that strbuf_init() does not even have to use slopbuf. But that is a much larger change that potentially breaks existing users of strbuf API. When you have a strbuf that has been prepared to be usable, the current API contract allows its users to expect buf.buf is never NULL, so they assume that they can safely write "if (!buf.buf)", so auditing strbuf.c and making sure a strbuf with buf==NULL gets lazily initialized is not enough.