splint: where is the memory leak?

K

kevin

Hi everyone. I'm scratching my head and can't understand why I'm
getting a warning from splint on this bit of code:

1 #include <stdio.h>
2 #include <ctype.h>
3
4 static char *strtolower( char *str )
5 {
6 char *s;
7
8 for ( s = str; *s; ++s )
9 *s = tolower( *s );
10
11 return str;
12 }
13
14 int main( void )
15 {
16 char msg[] = "Hello world";
17
18 printf( "%s\n", strtolower( msg ) );
19 return 0;
20 }

$ splint test.c
Splint 3.1.1 --- 03 Sep 2009

test.c: (in function strtolower)
test.c:8:20: Test expression for for not boolean, type char: *s
Test expression type is not boolean. (Use -predboolothers to inhibit warning)
test.c:11:12: Implicitly temp storage str returned as implicitly only: str
Temp storage (associated with a formal parameter) is transferred to a
non-temporary reference. The storage may be released or new aliases created.
(Use -temptrans to inhibit warning)
test.c: (in function main)
test.c:18:21: New fresh storage (type char *) passed as implicitly temp (not
released): strtolower(msg)
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)

Finished checking --- 3 code warnings
$ gcc -ansi -pedantic -Wall test.c -o test
$ ./test
hello world
$

Okay, so splint warns me that it has detected a memory leak in the
printf call, which
itself calls the function strtolower. I can't see it - I am only
returning the same address
that was passed to the function as a parameter. No new memory is being
allocated, so I
cannot understand why there would be a memory leak?

Can any one guide me on why there's a memory leak here? How do I
correct it or code
around it?

Or is splint in error?

TIA-
Kevin
 
K

Kaz Kylheku

Hi everyone. I'm scratching my head and can't understand why I'm
getting a warning from splint on this bit of code:

Splint is a program that, on unadorned C source, produces reams and reams of
false positives about imaginary situations.

To use splint properly, you have to write your programs in a special language
which consists of C, plus splint annotations written C comments.

The C implementation discards the comments, but they are part of the splint+C
language.

Splint is almost totally useless when applied to unannotated C source.

To learn about this Splint annotation language, you have to---surprise!---read
the Splint manual.
1 #include <stdio.h>
2 #include <ctype.h>
3
4 static char *strtolower( char *str )

By the way, don't do this. Identifiers beginning with "str" are reserved
for use as external names by the C standard, for the library.
5 {
6 char *s;
7
8 for ( s = str; *s; ++s )
9 *s = tolower( *s );
10
11 return str;
12 }
13
14 int main( void )
15 {
16 char msg[] = "Hello world";
17
18 printf( "%s\n", strtolower( msg ) );
19 return 0;
20 }

So here, by default, this situation looks like a leak:

printf( "%s\n", strtolower( msg ) );

The reason is that strtolower(msg) suspiciously looks like a function that
allocates and returns new storage. In fact, a strtolower function could work by
leaving the origianl string alone and returning a lower-case version, in which
case you would have a memory leak.

splint will not analyze your C code to confirm or refute its suspicion; it
relies on the annotations. You must somehow tell it that strtolower does not
allocate new memory.

Annotations suck, but one useful thing about them is that (like C
declarations), they allow translation units of the program to be checked
without access to other translation units.

Imagine if strtolower was in a third party library, for which you have only a
header and binary code. How can the static checker decide whether or not
that printf has a memory leak? Only in two possible ways: analyze the compiled
binary code, or rely on special annotations added to the header.
 
E

Eric Sosman

Hi everyone. I'm scratching my head and can't understand why I'm getting
a warning from splint on this bit of code:

1 #include <stdio.h>
2 #include <ctype.h>
3
4 static char *strtolower( char *str )
5 {
6 char *s;
7
8 for ( s = str; *s; ++s )
9 *s = tolower( *s );
10
11 return str;
12 }
13
14 int main( void )
15 {
16 char msg[] = "Hello world";
17
18 printf( "%s\n", strtolower( msg ) );
19 return 0;
20 }

$ splint test.c
Splint 3.1.1 --- 03 Sep 2009

test.c: (in function strtolower)
test.c:8:20: Test expression for for not boolean, type char: *s
Test expression type is not boolean. (Use -predboolothers to inhibit
warning)

Translation: "splint is a style tyrant."
test.c:11:12: Implicitly temp storage str returned as implicitly only: str
Temp storage (associated with a formal parameter) is transferred to a
non-temporary reference. The storage may be released or new aliases
created.
(Use -temptrans to inhibit warning)

Translation: [beyond my power to translate; I can find no
meaning and no sense in this message].
test.c: (in function main)
test.c:18:21: New fresh storage (type char *) passed as implicitly temp
(not
released): strtolower(msg)
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)

Translation: "splint is wrong."
Finished checking --- 3 code warnings

Translation: "splint overlooked both the infringement of
the implementation's name space and the code's only ACTUAL ERROR
in line 9."
Or is splint in error?

I'm not familiar with splint, but on the evidence presented
here it deserves to be, er, cast aside.
 
S

Stefan Ram

Eric Sosman said:
4 static char *strtolower( char *str )
Translation: [beyond my power to translate; I can find no
meaning and no sense in this message].

It might mean that a naïve author might write:

if( a = malloc( 10 ))
{ strcpy( a, "hi!" );
b = strtolower( a );
free( a );
puts( b ); }

I.e., it needs to be documented that the result is
/the same pointer/ as the argument.
 
R

Rich Webb

On Fri, 08 Jan 2010 15:35:31 -0500, Eric Sosman

[snippety snip]
I'm not familiar with splint, but on the evidence presented
here it deserves to be, er, cast aside.

An int-arresting pun for a Friday afternoon. Touché, sir!
 
I

Ian Collins

Rich said:
On Fri, 08 Jan 2010 15:35:31 -0500, Eric Sosman

[snippety snip]
I'm not familiar with splint, but on the evidence presented
here it deserves to be, er, cast aside.

An int-arresting pun for a Friday afternoon. Touché, sir!

Or a static Saturday morning!
 
K

kevin

Thank you everyone for your reply. I'm glad I didn't completely
misunderstand. I appreciate your comments.

Kevin
 
K

katmac

Kaz said:
Splint is almost totally useless when applied to unannotated C source.

Yes, but "splint -weak" is actually pretty useful on code without
annotations.
 
R

Richard Bos

Dann Corbit said:
22g2000yqr.googlegroups.com>, (e-mail address removed) says...

Even the default setting is fine if you know when to ignore it.

Myeah, but that doesn't say much. Even Dubya's speeches are fine if you
know when to ignore them. When "when" becomes "always", it is useless.

Richard
 
K

Kaz Kylheku

Myeah, but that doesn't say much. Even Dubya's speeches are fine if you
know when to ignore them. When "when" becomes "always", it is useless.

The person who might be presumed to be the world's expert in knowing what to
ignore from splint output (when splint is run on an un-annotated program)
wasn't happy with the default setting; he encoded his knowledge in the machine,
in the form of the -weak option.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top