[splint-discuss] HOWTO query

Mark Johnson mhjohnson at mac.com
Sat Mar 8 17:21:18 EST 2003

On Saturday, March 8, 2003, at 11:45  AM, CBFalconer wrote:

> Mark Johnson wrote:
>> [snip - request for FAQ]
I would still like an answer to this part.

>> A function like fopen can return NULL. So a function like
>> void log_on(void)
>> {
>>    static char *logfile = "logfile"; /* name of log file */
>>    if ((fecho = fopen(logfile, "w")) == NULL)
>>      {
>>        logging = 0;
>>      }
>>    else
>>      {
>>        (void)fprintf(fecho, "Roman log file.\n\n");
>>        logging = 1;
>>      }
>> }
>> will generate warnings such as
>> % splint player.c io.c
>> Splint --- 03 Mar 2003
>> io.c: (in function log_on)
>> io.c:69:36: Observer storage assigned to unqualified reference:
>>                 char * logfile = "logfile" = "logfile"
>>    Observer storage is transferred to a non-observer reference. (Use
>>    -observertrans to inhibit warning)
>>     io.c:69:26: Storage becomes observer
>> io.c:80:2: Function returns with non-null global fecho referencing 
>> null
>> storage
>>    A global variable does not satisfy its annotations when control is
>>    transferred. (Use -globstate to inhibit warning)
>>     io.c:71:16: Storage fecho may become null
>> Finished checking --- 2 code warnings
> In this case I think you should review your code, and splint is
> telling you so.  To start with, what possible purpose can the
> logfile variable serve?  You could better eliminate it and write:
>          if ((fecho = fopen("logfile", "w")) == NULL)
> or even
>          #define logfile "logfile"
Either of these methods hardwire the name of the log file and I don't 
want to do that. I do want a default value for the name of the log file 
and if the user overrides it - then use that instead. The example I 
provided is a far simpler version of what is really being done.

My question is more general - how do you define a character string and 
assign an initial value to it without requiring annotations? If you 
cannot - what is the correct annotation to use? I want to be able to 
use forms like
   char x[] = "xxx";
   char *x = "xxx";
the former allocates storage & initializes it (and can be modified, so 
the observer annotation is not suitable).

> secondly, you would be better off defining the function to return
> a FILE*, and arrange for the caller to place that where it
> wishes.  Similarly you would be better off passing in a pointer to
> the logging variable.  This would make the prototype:
>    FILE* logon(int *success);
> with fecho a local variable of type FILE*.
That is certainly feasible but I would rather hide the existence of 
FILE* fecho in a single source file. Callers to log_on, log_text, and 
others would then not have to handle the FILE* pointer. See also the 
next comment.

> You can do all this with NO modifications to your existing code,
> except for the calls to logon(), which would become:
>     fecho = logon(&logging);
> and give the reader a clear idea of what is going on, without
> having to refer to the logon coding.  Meanwhile logon() stands by
> itself, and can be modified and embellished without worrying about
> affecting other code, provided that the prototype is unaltered.
As I understand this situation, that merely moves the problem to the 
caller. Since fecho may be NULL after returning from log_on() the 
problem moves from log_on() to every caller of log_on(). That combined 
with the reasons listed above sound like a lose to me.

Let me repeat my question - how can this code be annotated to eliminate 
the warning for fecho [and not every global / static variable I use].

More information about the splint-discuss mailing list