[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 3.0.1.6 --- 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";
and
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].
--Mark
More information about the splint-discuss
mailing list