annotation to the return value declaration. (-nullret will suppress message)

Thanks for your valuable assistance, -mike.h --

Thu, 13 Feb 2003 03:00:00 GMT

Hans-Bernhard Broeke#2 / 13

allocating memory with functions

[...]

Quote:

> lclint produced long lists of 33 and 39 errors. > Most errors are related to functions which return pointers to memory > they allocate or which accept NULL pointer arguments and return pointers > to freshly allocated memory. > question: what (if anything) is wrong with this function?

Nothing in particular, except that 'lclint' is not restricting itself to doing the work of a classic 'lint'. Actually, its imitation of 'lint' is more like a nice by-product than part of the original idea.

The errors you list are generated by code not instrumented with

the way a particular pointer is supposed to be used. The C language alone (until the recent addition of the 'restrict' keyword in C99) had no means to express such "usage contracts", but lclint wants them to give it a way of checking pointer usage.

E.g., lclint will complain whenever you assign NULL to a pointer

comment, or a globally active lclint option that make that flag the default status for any pointer. In its default state, it will also complain if you ever have two pointer variables of the same scope holding the same pointer, suspecting you might loose overview and introduce dangling pointers later, when you might 'free()' one of them, but forget the other.

The details are all in the long and rather instructive manual for lclint. --

Even if all the snow were burnt, ashes would remain. --

Fri, 14 Feb 2003 03:00:00 GMT

Peter Burk#3 / 13

allocating memory with functions

Quote:

> Expert Opinions wanted.

> I wrote 2 C programs to test a hypothesis. Although the programs compile > (gcc), run and produce correct output, (proving my hypothesis wrong), > lclint produced long lists of 33 and 39 errors.

> Most errors are related to functions which return pointers to memory > they allocate or which accept NULL pointer arguments and return pointers > to freshly allocated memory.

Most coding conventions dictate that the function's contract be described above the function, and that its implementation be described within the body. Your comment describes the contract, so I'd put it above the function. It's a matter of personal taste, though.

to tell it that you know it might return null. This is a lint convention, and probably isn't a bad idea.

/peter --

Fri, 14 Feb 2003 03:00:00 GMT

Michiel Salter#4 / 13

allocating memory with functions

Quote:

> Expert Opinions wanted. > I wrote 2 C programs to test a hypothesis. Although the programs compile > (gcc), run and produce correct output, (proving my hypothesis wrong), > lclint produced long lists of 33 and 39 errors.

I've yet to meet a version of lint which doesn't spit out long lists of "errors" for code which in fact is perfectly well defined, only a bit unusual. Of course, this is because looking at the broader scope of a program is quite hard.

Quote:

> Most errors are related to functions which return pointers to memory > they allocate or which accept NULL pointer arguments and return pointers > to freshly allocated memory. > question: what (if anything) is wrong with this function?

What's "wrong" is that it uses a coding style not known to the lclint authors.

You could modify a node by passing in a pointer, that's how C does pass by reference. Apparently lclint expects you to assign to *pmfhcp when you pass in a pointer. This is of course not the expected behavior for list-management functions.

Quote:

> Temp storage (associated with a formal parameter) is transferred to a > non-temporary reference. The storage may be released or new aliases > created. > (-temptrans will suppress message)

This is pointing to a _possible_ memory management issue. Who is managing the memory pointed to by pmfhcp? When the list goes out of scope, should it be deleted? If so, the caller of push will probably not free the memory itself. But it should, if push returns NULL. OTOH, if no responsibilities are transferred, this is a bogus warning. But you can't determine that from this function, ergo this should be a warning.

This looks like a particular annoying lint message, especially for people with some C++ knowledge. I assume that a function returning a pointer can return NULL, unless explicitly stating otherwise. lclint has another idea, if you want to be able to return NULL you should state so, using the provided syntax.

Still, I would code the function slightly different:

/* * Function: push * Arguments: 2 pointers, 1st to top of stack, * 2nd to a coordinate pair to be stored; * Functionality: * creates storage for and returns pointer * to new node (top of stack = head of linked list) */

Remember your scope rules. The pointer you create (pNewTop) is deallocated at the return. What your pointing at is in heap space is nice and malloc'd, but your pointer is freed and can be corrupted. Here's how.

Instead of using your pointer try to log it's location in memory, not where it's pointing, inside the push call. After the return from push then create a function that calls a function. This will cause stack frames to be pushed for each func call. This may or may not corrupt your pointer, but I think you have the gist.

Try declaring the new pointer before the push and then pass it in as a parm and then use the return value for error checking of your malloc etc.

Another way would be when you enter push declare a temp *, that points at pTop. Let pTop point at newly alloced memory and then you can link the new top to the old top using the the temp*. I reversed your logic for the malloc because I prefer well defined exit routines So

That looks like perfectly valid code to me. The pointer pNewTop is an automatic variable, but that's fine because its value is being returned on the stack as the return value of the function. It's pointing to valid space in the heap which isn't freed.

Am I missing some problem here?

Quote:

> Instead of using your pointer try to log it's location in memory, not > where it's pointing, inside the push call. After the return from push > then create a function that calls a function. This will cause stack > frames to be pushed for each func call. This may or may not corrupt your > pointer, but I think you have the gist.

This didn't make any sense to me at all. push looks to me like a fairly standard sort of function that allocates a struct and returns a pointer to the newly allocated struct, passing along responsibility to the caller to free it when it's done. You certainly shouldn't need to play any games with stack frames to get this to work fine.

--

--

Wed, 19 Feb 2003 00:39:57 GMT

Michiel Salter#7 / 13

allocating memory with functions

Quote:

> > Most errors are related to functions which return pointers to memory > > they allocate or which accept NULL pointer arguments and return pointers > > to freshly allocated memory. > > question: what (if anything) is wrong with this function? > > function:

> > struct node *push(struct node *pTop, struct copair *pmfhcp){ > > struct node *pNewTop; > > if( (pNewTop = (struct node*)malloc(sizeof(struct node))) != NULL){ > > pNewTop->pmfhcp = pmfhcp; > > pNewTop->next = pTop; > > return(pNewTop); > Remember your scope rules. The pointer you create (pNewTop) is deallocated > at the return. What your pointing at is in heap space is nice and > malloc'd, but your pointer is freed and can be corrupted. Here's how. > Instead of using your pointer try to log it's location in memory, not > where it's pointing, inside the push call. After the return from push then > create a function that calls a function. This will cause stack frames to > be pushed for each func call. This may or may not corrupt your pointer, > but I think you have the gist.

Nonsense.

There is indeed a possibility that pNewTop is allocated on the stack - small, many compilers will put it in a register - but even if that happens, no harm is done. The value of the pointer is available as the return value of push(). If this is saved in another pointer - as the documentation should demand - nothing is lost.

Let me give you a counter example:

int add(int a, int b) { int sum = a + b; return sum;

Quote:

}

int main() { int x; x =add(1,2)+add(3,4); printf("%d",x);

Quote:

}

What else can be printed but 10? Still, the first call to add has a 'sum' which most likely is overwritten by the second call. No compiler will ever print 14.

[ Snipped some code based on this misunderstanding of return values. ]

Michiel Salters --

Wed, 19 Feb 2003 00:40:38 GMT

mik..#8 / 13

allocating memory with functions

Hans-Bernhard Broeker Peter Burka Michiel Salters robert maclemale

Thanks. I am extremely grateful for your thoughtful responses!

good luck to all, -mike

Quote:

>Expert Opinions wanted.

>snip

--

Wed, 19 Feb 2003 00:40:30 GMT

Brian Ingli#9 / 13

allocating memory with functions

On 28 Aug 2000 21:39:15 GMT, Hans-Bernhard Broeker

Quote:

>[...] >> lclint produced long lists of 33 and 39 errors.

>> Most errors are related to functions which return pointers to memory >> they allocate or which accept NULL pointer arguments and return pointers >> to freshly allocated memory.

>> question: what (if anything) is wrong with this function?

>Nothing in particular, except that 'lclint' is not restricting itself >to doing the work of a classic 'lint'. Actually, its imitation of >'lint' is more like a nice by-product than part of the original idea.

>The errors you list are generated by code not instrumented with

>the way a particular pointer is supposed to be used. The C language >alone (until the recent addition of the 'restrict' keyword in C99) had >no means to express such "usage contracts", but lclint wants them to >give it a way of checking pointer usage.

>E.g., lclint will complain whenever you assign NULL to a pointer

>comment, or a globally active lclint option that make that flag the >default status for any pointer. In its default state, it will also >complain if you ever have two pointer variables of the same scope >holding the same pointer, suspecting you might loose overview and >introduce dangling pointers later, when you might 'free()' one of >them, but forget the other.

>The details are all in the long and rather instructive manual for >lclint.

Use a compiler with better diagnostics instead of lint! I tested a bunch of code against lint and gcc a few years ago: gcc (-Wall) found all the real issues also found by lint, including printf, scanf and strftime format issues, and did not produce warnings about potential problems, requiring lint comments or options to silence it. So if gcc -Wall, or a similar compiler with all warnings enabled, complains about your code, there is a real /possibility/ of a problem that you should look at and fix. OTOH, lint will tell you about anything that may be a problem, and may point out cases where, for example, you are failing to test a return code from a function, or little portability issues, which are not of concern to a compiler. I would use a mouthy compiler with all warnings enabled for normal checking and keep lint for the post-debugging and unit testing once over, in case you have missed something non-obvious.

Thanks. Take care, Brian Inglis Calgary, Alberta, Canada --

use address above to reply --

Fri, 28 Feb 2003 22:09:50 GMT

Andy Isaacs#10 / 13

allocating memory with functions

Quote:

>I tested a bunch of code against lint and gcc a few years ago: >gcc (-Wall) found all the real issues also found by lint, >including printf, scanf and strftime format issues, and did not >produce warnings about potential problems, requiring lint >comments or options to silence it. >So if gcc -Wall, or a similar compiler with all warnings enabled, >complains about your code, there is a real /possibility/ of a >problem that you should look at and fix.

For best results, use "gcc -Wall -O2" or higher optimization level. Without optimization, gcc does not compute the necessary data-flow graph and so cannot warn you "`a' might be used uninitialized in this function".

-andy --

Sun, 02 Mar 2003 03:39:21 GMT

Hans-Bernhard Broeke#11 / 13

allocating memory with functions

Quote:

> On 28 Aug 2000 21:39:15 GMT, Hans-Bernhard Broeker

>>[...] >>> lclint produced long lists of 33 and 39 errors.

>>Nothing in particular, except that 'lclint' is not restricting itself >>to doing the work of a classic 'lint'. Actually, its imitation of >>'lint' is more like a nice by-product than part of the original idea.

[...]

Quote:

> Use a compiler with better diagnostics instead of lint!

Sorry, but that's missing the point. Original 'lint' may not stand competition against a modern compiler with warnings cranked up high like 'gcc -Wall -W -O -ansi -pedantic' ('-Wall' alone doesn't really cut it). But we were talking about 'lclint', here, which is a completely different thing. It can do checks neither traditional 'lint' nor gcc ever even dreamt of.

And even 'lint' can detect some types of errors you'll have a hard time noticing with 'gcc -Wall' alone. Like differences in function prototypes among separately compiled which aren't properly accounted for by #include's of correctly written headers.

Until 'gcc' learns to warn about any non-static prototype or global variable declaration found inside the compiled main source file, rather than in headers, it cannot replace 'lint', by a wide margin.