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
>
>


Reply via email to