Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: A glitch regarding the usual malloc() idiom Date: Wed, 20 Jul 2016 11:28:18 -0700 Organization: None to speak of Lines: 68 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="945944de09706c9b4e29b53c9d2efdc2"; logging-data="6666"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+rmOyfDYpiD228LgH1CO2y" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:F+xBZBGCSw/Bt31d9Oq9FK2u+Hg= sha1:D95KjLm2JIM3+OA3H3sksj26Whw= Xref: csiph.com comp.lang.c:90678 Tim Rentsch writes: > Keith Thompson writes: >> The widely (but not universally) accepted idiom for calling malloc() in >> C is: >> >> some_type *ptr = malloc(sizeof *ptr); >> >> or, if you want to allocate an array: >> >> some_type *ptr = malloc(N * sizeof *ptr); >> >> The expression `*ptr` dereferences an uninitialized pointer, but it's >> safe because the operand of `sizeof` is not evaluated. >> >> Well, almost. As I've just realized while following up to a post in >> another thread by BartC, the operand *is* evaluated if it's of a >> variably modified type. [...] > > Please excuse a small correction. A sizeof operand is evaluated > if (and only if) it has variable length array type. All variable > length array types are variably modified types, but not all > variably modified types are variable length array types. Quite right. I hadn't realized that. Which means, for example, that a structure or union cannot have a member whose type is a pointer to a VLA type. I can't think of any good reason for that particular restriction (such a pointer type must have a fixed size, even for an implementation that uses fat pointers), and I wonder if it was intended. On the other hand, such a structure or union would rarely be useful, since variably modified types can be defined and used only within a single function. [...] >> To avoid the UB, you could write something like: >> >> #include >> int main(void) { >> int n = 10; >> typedef int vla[n]; >> vla *p = malloc(sizeof (vla)); >> } > > Another way is to ensure the evaluation has defined behavior, as > for example: > > #include > > void *valid_all; > > int main(void) { > valid_all = malloc(1); // and check for success... > int n = 10; > typedef int vla[n]; > vla *p = malloc(sizeof *(p = valid_all)); > } > > At level O1 (and above, presumably), gcc is smart enough to > optimize away the redundant assignment in such cases. Sure. It seems a bit convoluted, though. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"