David Evans
Tue, 23 Jul 2002 12:39:05 -0700
Hi,
The first warning is:
widget.h:18:103: Released storage x->name reachable from parameter at
return point
for,
/*@null@*/ extern inline char *widgetName(/*@null@*/ widget *x) { return
(x != NULL) ? x->name : NULL; }
What you need here is an /*@observer@*/ annotation to indicate that the
caller should not modify the result (even though it is a mutable object).
This will override the implicit only on the function result.
This leaves 2 warnings in widgetNew:
widget.c:9:49: Only storage str not released before return
widget.c:6:22: Storage str becomes only
widget.c:13:32: Fresh storage str not released before return
widget.c:10:5: Fresh storage str allocated
The first results from the /*@only@*/ annotation on the local variable
declaration. This isn't necessary --- splint should be able to figure out
there is no memory leak anyway, but it doesn't (there should probably be a
warning for memory annotations on local declarations, since local
declarations are permitted to change state, it doesn't really make sense
to annotate them).
The warning for line 13 is a legitimate memory leak --- we should free str
before returning.
The warnings for widgetInit are similar:
widget.c:26:52: Only storage str not released before return
Since str is declared with /*@only@*/ in widget.h, the implementation of
widgetInit is responsible for its storage. We should free it before
returning. Similarly, for x for the next return.
After these changes, splint doesn't produce any warnings. The modified
code is below.
Best,
--- Dave
widget *widgetNew(const size_t size) {
char *str;
widget *x;
if (size < 1) { errno = EINVAL; return NULL; }
str = (char *) malloc(size);
if (str == NULL) return NULL; /* malloc sets errno */
x = (widget *) malloc(sizeof(struct widget));
if (x == NULL)
{
free (str);
return NULL; /* malloc sets errno */
}
if (widgetInit(x,str,1) == NULL) return NULL;
x->flags |= WIDGET_MALLOCED;
return x;
}
widget *widgetInit(widget *x, const char *str, const
unsigned int initialize) {
if (x == NULL) {
errno = EINVAL;
if (str != NULL) free (str);
return NULL;
}
if (str == NULL) { errno = EINVAL; widgetFree (x); return NULL; }
x->name = (char *) str;
if (initialize != 0) *x->name = '\0';
x->flags = 0;
return x;
}
On Tue, 23 Jul 2002 [EMAIL PROTECTED] wrote:
> Hello all,
>
> First let me say thank you for splint. When I use it, I
> feel like I
> have an experienced and meticulous C coder looking over
> my shoulder.
> Lately, I've tried something a little more ambitious, and
> either
> I don't understand what is wrong with my code or I'm
> failing to
> annotate it properly, so I'm coming to you for help.
> I've made
> a small example to show what approach I'm using and what
> messages
> splint is generating. Essentially I want to malloc
> memory for
> a structure and a string component of the structure, use
> it, and
> later free all the memory. Optionally, I want to be able
> to use
> a non-dynamically allocated structure and string. I'm
> including
> below the .splintrc file, widget.h, widget.c, and the splint
> messages. I'd be very grateful to anyone who can help me
> understand
> what I need to do here. Thanks. -Dan Good
>
>
> __.splintrc_________________________________________________
>
> -unrecog
> #-mustfreefresh
> #-usereleased
> -compdef
> #-mustfreeonly
> #-compmempass
> -exportlocal
>
>
> __widget.h__________________________________________________
>
> #ifndef _WIDGET_H
> #define _WIDGET_H 1
>
> #define WIDGET_MALLOCED 1
>
> struct widget {
> /*@only@*/ char *name;
> unsigned int flags;
> };
> typedef /*@abstract@*/ struct widget widget;
>
> /*@null@*/ /*@only@*/ widget *widgetNew(const size_t size);
>
> /*@null@*/ widget *widgetInit(/*@null@*/ /*@partial@*/
> /*@only@*/ widget *x, /*@null@*/ /*@only@*/ const char
> *str, const unsigned int initialize);
>
> void widgetFree(/*@null@*/ /*@only@*/ widget *x);
>
> /*@null@*/ extern inline char *widgetName(/*@null@*/
> widget *x) { return (x != NULL) ? x->name : NULL; }
>
> #endif
>
>
> __widget.c__________________________________________________
>
> #include <stdlib.h>
> #include <errno.h>
> #include "widget.h"
>
> widget *widgetNew(const size_t size) {
> /*@only@*/ char *str;
> widget *x;
>
> if (size < 1) { errno = EINVAL; return NULL; }
> str = (char *) malloc(size);
> if (str == NULL) return NULL; /* malloc sets errno */
> x = (widget *) malloc(sizeof(struct widget));
> if (x == NULL) return NULL; /* malloc sets errno */
>
> if (widgetInit(x,str,1) == NULL) return NULL;
> x->flags |= WIDGET_MALLOCED;
> return x;
> }
>
> widget *widgetInit(widget *x, const char *str, const
> unsigned int initialize) {
> if (x == NULL) { errno = EINVAL; return NULL; }
> if (str == NULL) { errno = EINVAL; return NULL; }
> x->name = (char *) str;
> if (initialize != 0) *x->name = '\0';
> x->flags = 0;
> return x;
> }
>
> void widgetFree(widget *x) {
> if (x != NULL && (x->flags & WIDGET_MALLOCED) != 0) {
> free(x->name);
> free(x);
> }
> }
>
> /*@null@*/ char *widgetName(/*@null@*/ widget *x) {
> return (x != NULL) ? x->name : NULL; }
>
>
> __splint widget.c___________________________________________
>
> Splint 3.0.1.6 --- 19 Jul 2002
>
> widget.h: (in function widgetName)
> widget.h:18:103: Released storage x->name reachable from
> parameter at return
> point
> Memory is used after it has been released (either by
> passing as an only param
> or assigning to an only global). (Use -usereleased to
> inhibit warning)
> widget.h:18:74: Storage x->name is released
> widget.c: (in function widgetNew)
> widget.c:9:49: Only storage str not released before return
> A memory leak has been detected. Only-qualified storage
> is not released
> before the last reference to it is lost. (Use
> -mustfreeonly to inhibit
> warning)
> widget.c:6:22: Storage str becomes only
> widget.c:13:32: Fresh storage str not released before return
> A memory leak has been detected. Storage allocated
> locally is not released
> before the last reference to it is lost. (Use
> -mustfreefresh to inhibit
> warning)
> widget.c:10:5: Fresh storage str allocated
> widget.c: (in function widgetInit)
> widget.c:21:52: Only storage str not released before return
> widget.c:20:43: Storage str becomes only
> widget.c:22:52: Only storage x not released before return
> widget.c:20:28: Storage x becomes only
> widget.c: (in function widgetName)
> widget.c:36:89: Released storage x->name reachable from
> parameter at return
> point
> widget.c:36:60: Storage x->name is released
>
> Finished checking --- 6 code warnings
>
>