[splint-discuss] undefined field in my storage
CBFalconer
cbfalconer at yahoo.com
Mon Dec 23 10:14:32 EST 2002
David Evans wrote:
> On Wed, 18 Dec 2002, Bertrand Mollinier Toublet wrote:
>
> > I am a new user of Splint, and of course already ran into my first
> > puzzling issue. From a rapid browse of the list archive, it seems that
> > it is ok to post such issue here. However, if it is *not* ok, please let
> > me know. My issue is related to the following tiny bit of code:
> >
> > #include <stdlib.h>
> >
> > struct node
> > {
> > size_t nchildren;
> > /*@relnull@*/ struct node **children;
> > };
> >
> > static /*@null@*/ struct node *alloc_node(unsigned int, size_t);
> >
> > struct node *alloc_node(size_t nchildren)
> > {
> > struct node *node;
> > size_t i;
> >
> > node = malloc(sizeof *node);
> > if (NULL == node) return NULL;
> >
> > node->nchildren = nchildren;
> > if (0 == nchildren)
> > {
> > node->children = NULL;
> > }
> > else
> > {
> > node->children = malloc(nchildren * sizeof *node->children);
> > if (NULL == node->children)
> > {
> > free(node);
> > return NULL;
> > }
> > for (i = 0; i < nchildren; ++i)
> > {
> > node->children[i] = NULL;
> > }
> > }
> > return node;
> > }
> >
> > The idea is to allocate storage for a single node of a tree with a
> > variable number of children per node. The function tries to allocate
> > storage for the struct itself, and returns NULL if it fails. It then
> > goes on allocating storage for the list of children with the following
> > rules:
> > - if the number of children passed to the function is zero, it is
> > indicated by setting the list to NULL
> > - else, storage is allocated for enough pointers to the children
> > (de-allocating node and returning NULL is case of malloc failure), and
> > all the children are initialized to NULL (I want them to be set later).
> >
> > Now my problem: Splint complains that when returning node, at the last
> > return, the field children is undefined. Here comes the full message:
> >
> > test.c(37,12): Returned storage *node contains 1 undefined field:
> > children
> > Storage derivable from a parameter, return value or global is not
> > defined.
> > Use /*@out@*/ to denote passed or returned storage which need not be
> > defined.
> > (Use -compdef to inhibit warning)
> >
> > It seems to me that node->children is fully defined, either as a NULL
> > pointer if nchildren==0, or as an array of NULL pointer in the opposite
> > case, except if the storage allocation failed, in which case, a NULL
> > pointer is returned.
> >
> > In other words, I do not understand how Splint is able to see the
> > children field as being undefined.
> >
> > Anyone willing to clarify things for me, please ?
>
> The reason splint is reporting a warning about node perhaps not being
> completely defined at line 37, is that it cannot determine that the
> body of the loop which initializes it with node->children[i] = NULL
> actually executes. (A deeper analysis would be able to determine this
> because the else only executes when nchildren > 0, but splint's analyses
> are not deep enough to determine that.)
>
> The way to elimintate the warning is to add a syntactic comment that
> indicates that the loop body always executes:
>
> /*@+forloopexec@*/
> for (i = 0; i < nchildren; ++i)
> {
> node->children[i] = NULL;
> }
> /*@=forloopexec@*/
>
> If you're less paranoid, you could just add +loopexec to the command line
> which would make splint assume all loop bodies are executed.
Let me suggest the following modification to your code, as being
both clearer and possibly more understandable to splint:
/* pasted as quote to avoid line breaks */
> #include <stdlib.h>
>
> struct node {
> size_t nchildren;
> struct node **children;
> };
>
> struct node *alloc_node(size_t nchildren)
> {
> struct node *node;
> size_t i;
>
> if (NULL != (node = malloc(sizeof *node))) {
> node->nchildren = nchildren;
> if (0 == nchildren) node->children = NULL;
> else {
> node->children = malloc(nchildren * sizeof *node->children);
> if (NULL != node->children)
> for (i = 0; i < nchildren; ++i) node->children[i] = NULL;
> else {
> free(node);
> node = NULL;
> }
> }
> }
> return node;
> }
at least IMNSHO :-) No 'peculiar' comments needed, single exit
point, etc. Now I get:
> [1] c:\c\junk>splint tsplint1.c
> Splint 3.0.1.6 --- 11 Feb 2002
>
> tsplint1.c: (in function alloc_node)
> tsplint1.c(26,12): Possibly null storage node returned as non-null: node
> Function returns a possibly null pointer, but is not declared using
> /*@null@*/ annotation of result. If function may return NULL, add /*@null@*/
> annotation to the return value declaration. (Use -nullret to inhibit warning)
> tsplint1.c(13,25): Storage node may become null
> tsplint1.c(26,12): Returned storage *node contains 2 undefined fields:
> nchildren, children
> Storage derivable from a parameter, return value or global is not defined.
> Use /*@out@*/ to denote passed or returned storage which need not be defined.
> (Use -compdef to inhibit warning)
>
> Finished checking --- 2 code warnings
PS: why doesn't the list include a reply-to field in the header?
That would avoid many nuisance direct emails.
--
Chuck F (cbfalconer at yahoo.com) (cbfalconer at worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
More information about the splint-discuss
mailing list