[comp.unix.programmer] hiding lint's ravings

jdm5548@diamond.tamu.edu (James Darrell McCauley) (09/09/90)

How do you professionals deal with insignificant(?) ravings from
lint (or other high quality C program verifiers) such as the 
following:

>test.c(x): warning: possible pointer alignment problem
which was caused by the malloc in:

>double **dmatrix(nr,nc)
>int nr,nc;
>{
>  double **m = NULL;
>
>  m = (double **) malloc( (unsigned) nr * sizeof(double *) );
>  if (!m) ...

From what netlanders tell me, this warning is explanined as:
(by Conor P. Cahill) 
|>                         The problem is that malloc is defined
|> as returning a pointer to char which has looser alignment requirements than
|> pointer to pointer.  Since malloc guarrantees that the result is suitably 
|> alligned for all data types, you can ignore this message.

Well, I can just ignore warnings like this, but those who review
my code (professors, employers, clients) are not likely to. It makes
an bad impression and frankly, I find it a little embarrassing.
(I'm embarrassed for those who publish code in which lint detects
things like unused arguments, etc). I could just:
#ifndef lint
   m = (double *) malloc(...
#endif
but before long, the code looks disgusting.  Do you just ignore
warnings like this and remain confident in your code, or do you
do your best to work around them?

By the way, I got this error while using a Sparc under Sun OS 4.0.3c,
but not under 4.0.3 (which perplexes me).
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
James Darrell McCauley                 jdm5548@diamond.tamu.edu
Dept of Ag. Engineering                          (409) 845-6484
Texas A&M University, College Station, Texas 77843-2117, USA
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

mcdonald@aries.scs.uiuc.edu (Doug McDonald) (09/09/90)

In article <8086@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes:
>How do you professionals deal with insignificant(?) ravings from
>lint (or other high quality C program verifiers) such as the 
>following:
>
>>test.c(x): warning: possible pointer alignment problem
>which was caused by the malloc in:
>
>>double **dmatrix(nr,nc)
>>int nr,nc;
>>{
>>  double **m = NULL;
>>
>>  m = (double **) malloc( (unsigned) nr * sizeof(double *) );
>>  if (!m) ...
>
>From what netlanders tell me, this warning is explanined as:
>(by Conor P. Cahill) 
>|>                         The problem is that malloc is defined
>|> as returning a pointer to char which has looser alignment requirements than
>|> pointer to pointer.  Since malloc guarrantees that the result is suitably 
>|> alligned for all data types, you can ignore this message.
>
>Well, I can just ignore warnings like this, but those who review
>my code (professors, employers, clients) are not likely to. It makes
>an bad impression and frankly, I find it a little embarrassing.


It is NOT embarrassing to you. It just plain a BUG in lint. Pure and
simple. Complain to the person that sold you the broken "lint".
A checker program really OUGHT to understand the rules of what it is
checking. One of those rules concersn alignments of the return
value of malloc.

Doug McDonald

chris@mimsy.umd.edu (Chris Torek) (09/09/90)

In article <8086@helios.TAMU.EDU> jdm5548@diamond.tamu.edu
(James Darrell McCauley) writes:
>How do you professionals deal with insignificant(?) ravings from
>lint (or other high quality C program verifiers) such as
[the bogus `possible pointer alignment problem' messages from malloc]?
>... I can just ignore warnings like this, but those who review
>my code (professors, employers, clients) are not likely to.

Since the warning is due to a bug in lint, those who do not ignore it
are simply compounding the problem.  The real cure is to fix lint.

>By the way, I got this error while using a Sparc under Sun OS 4.0.3c,
>but not under 4.0.3 (which perplexes me).

Looks like someone fixed it, but had to back out the fix (or else 4.0.3
and 4.0.3c were separate development efforts, which is entirely possible).

This happens to be easy to fix as a special case inside lint (add an
`/*ALIGNOK*/' lint-pragma that can be used in <stdXXX.h> files to tag
the special functions malloc and calloc).  A harder one is varargs routines:

	/* used as error(quit, errno, fmt, ...) */

	/* VARARGS3 */
	error(va_alist)	/* note Classic C <varargs.h>, not New C <stdarg.h> */
		va_dcl
	{
		int quit, e;
		char *fmt;
		va_list ap;

		va_start(ap);
		quit = va_arg(ap, int);
		e = va_arg(ap, int);
		fmt = va_arg(ap, int);
		...

One would like lint to verify that the first three arguments are indeed
<int> <int> and <char *> respectively.  (Indeed, since this particular
function behaves like printf, one would also like lint to verify subsequent
arguments the way the 4.3BSD-reno lint [thanks to Arthur Olson] verifies
arguments to printf, fprintf, and sprintf.)

The only solution I have to this is:

	#ifdef lint
	/* VARARGS3 */
	error(quit, e, fmt) int quit, e; char *fmt; { }
	#define error lint_error
	#endif

	... definition of error() as before ...
	#undef error

You must then ignore all `function lint_.* defined but not used' errors.
If you were to use

	#ifdef lint
	/* VARARGS3 */
	error(quit, e, fmt) int quit, e; char *fmt; { }
	#else
	... definition of error() ...
	#endif

then lint would not be able to check the code inside error() itself.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

duane@anasaz.UUCP (Duane Morse) (09/09/90)

Here are two suggestions to remove lint's pointer alignment complaint.

1) Put #ifdef lint/#endif around the code and do something innocuous
when running lint.  If the profs read the code carefully, this may raise
their eyebrows.

2) Write your own "malloc" subroutine which returns 0 for success and
a nonzero value for failure; pass a pointer to where you want to store
the address and have the routine interpret it as a char **; use a
variable of the type you really need (struct whatever *) and cast it
to (char **) in the subroutine call -- lint won't complain about any
of this.

By the way, if the prof's really complain about this lint 'error' in your
program, it doesn't say much about their knowledge of lint.
-- 

Duane Morse	e-mail: duane@anasaz (or ... asuvax!anasaz!duane)
(602) 861-7609

guy@auspex.auspex.com (Guy Harris) (09/10/90)

>How do you professionals deal with insignificant(?) ravings from
>lint (or other high quality C program verifiers) such as the 
>following:

With "egrep".

>By the way, I got this error while using a Sparc under Sun OS 4.0.3c,
>but not under 4.0.3 (which perplexes me).

I suspect you meant "but not on a Sun-[23] under 4.0.3", not "but not
under 4.0.3".  The key is the SPARC, not the "c"; the SunOS
(BSD-environment) "lint" is little pickier about alignment complaints
when run on a SPARC machine - it does them even if you don't give "lint"
the "-h" option.  (Of course, I always use "-h" anyway, so I don't
notice the difference....)

karl@haddock.ima.isc.com (Karl Heuer) (09/10/90)

In article <8086@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes:
>How do you professionals deal with insignificant(?) ravings from lint [like]
>test.c(x): warning: possible pointer alignment problem

This is caused by a long-standing bug in lint.  It could have been fixed long
ago, but this hasn't been a high-priority item with AT&T.  (It's "fixed" in
SVR4 by going full swing in the other direction; ANSI-lint now fails to report
some genuine alignment problems, as I understand the situation.)

And it's almost invariably a bad idea to muck up your code with a workaround:

>#ifndef lint
>   m = (double *) malloc(...
>#endif

Not only does this look ugly (and in my opinion, creates a *worse* impression
than the presence of a well-known spurious lint warning), but it can easily
lead to further problems.  For example, lint will now believe that "m" is
uninitialized.

But if you must have a workaround, one fairly clean one is to use a separate
interface for each type:
	#if !defined(lint)
	#define mkdouble()  ((double *)malloc(sizeof(double)))
	#define rmdouble(p) free((void *)p)
	#else
	extern double *mkdouble(void);
	extern void    rmdouble(double *);
	#endif
which might be a good idea anyway since it leaves room for more complex
constructors/destructors in a future revision.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

volpe@underdog.crd.ge.com (Christopher R Volpe) (09/10/90)

In article <8086@helios.TAMU.EDU>, jdm5548@diamond.tamu.edu (James
Darrell McCauley) writes:
|>How do you professionals deal with insignificant(?) ravings from
|>lint (or other high quality C program verifiers) such as the 
|>following:
|>
|>>test.c(x): warning: possible pointer alignment problem

I don't know if this will work, since my lint doesn't complain
about this possible alignment problem, but how about trying
the following?

#include <malloc.h>
#ifdef LINT
double *(*_malloc)() = (double *(*)()) malloc; /* note underscore */
#define malloc (*_malloc)
#endif

This declares "_malloc" to be a pointer to a function returning pointer
to double, and initializes it with the address of the malloc routine,
suitably cast. Then, all calls to "malloc" actually use "(*_malloc)",
which returns objects with proper alignment as far as lint is concerned.
                                         
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (09/11/90)

Here's a nifty little gizmo that implements /*NOSTRICT*/ by
postprocessing lint's output for you.

#!/usr/bin/perl
'di';
'ig00';
#
# $Header: nostrict,v 1.1 90/08/11 13:26:31 lwall Locked $
#
# $Log:	nostrict,v $
# Revision 1.1  90/08/11  13:26:31  lwall
# Initial revision
# 

for $arg (@ARGV) {
    next unless $arg =~ /\.[ch]$/;
    open(IN,$arg);
    while (<IN>) {
	vec($ok{$arg}, $., 1) = 1 if m#/\*\s*NOSTRICT\s*\*/# .. m#;\s*($|/\*)#;
    }
    close IN;
}

open(LINT, "-|") || exec @ARGV;

while (<LINT>) {
    next unless ($file,$line) = /(\S+)\((\d+\))/;
    next unless defined $ok{$file};
    $_ = '' if vec($ok{$file}, $line, 1);
    next unless ($file,$line) = /::\s*(\S+)\((\d+\))/;
    next unless defined $ok{$file};
    $_ = '' if vec($ok{$file}, $line, 1);
}
continue {
    print;
}
##############################################################################

	# These next few lines are legal in both Perl and nroff.

.00;			# finish .ig
 
'di			\" finish diversion--previous line must be blank
.nr nl 0-1		\" fake up transition to first page again
.nr % 0			\" start at page 1
'; __END__ ############# From here on it's a standard manual page ############
.TH NOSTRICT 1 "August 11, 1990"
.AT 3
.SH NAME
nostrict \- postprocesses lint output to implement NOSTRICT directives
.SH SYNOPSIS
.B nostrict lint [lint_args]
.SH DESCRIPTION
.I Nostrict
runs the command supplied in the rest of the arguments on the command
line, and then weeds out any lint complaints referring to statements
preceded by the /*NOSTRICT*/ directive that the lint documentation
documents but that lint doesn't implement.
.SH ENVIRONMENT
No environment variables are used.
.SH FILES
None.
.SH AUTHOR
Larry Wall
.SH "SEE ALSO"
lint(1)
.SH DIAGNOSTICS
None.  Relies on lint to tell you about missing files.
.SH BUGS
Should probably differentiate the errors you want NOSTRICT for from
the errors you don't.

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

rsalz@bbn.com (Rich Salz) (09/12/90)

In <8086@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes:
[ Summary:
    extern char *malloc();
    double **dpp = (double **)malloc((unsigned int)n * sizeof (double*));
 causes lint to complain "possible pointer alignment problem". ]

Some people said ignore it, but James replied:
>Well, I can just ignore warnings like this, but those who review
>my code (professors, employers, clients) are not likely to.
Then, simply put, they are not competent to review your code.

If you need a better solution, you can often fool lint by writing your own
malloc function that returns something with worst-case alignment.  For example:
	#define NEW(type, count)	xmalloc(count * sizeof (type))
	typedef double *ALIGN;

	ALIGN
	xmalloc(i) int i; {
	    ALIGN p = (ALIGN)malloc((unsigned int)i);
	    if (p == NULL) FatalError("no memory");
	    return p;
	}

	double **dpp = NEW(double*, n);
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.

dave@imax.com (Dave Martindale) (09/14/90)

In article <2985@anasaz.UUCP> duane@anasaz.UUCP (Duane Morse) writes:
>Here are two suggestions to remove lint's pointer alignment complaint.
>
>2) Write your own "malloc" subroutine which returns 0 for success and
>a nonzero value for failure; pass a pointer to where you want to store
>the address and have the routine interpret it as a char **; use a
>variable of the type you really need (struct whatever *) and cast it
>to (char **) in the subroutine call -- lint won't complain about any
>of this.

This is a BAD idea.  If you are on a machine where a byte and (short,
int, long, float, double) pointers do not have the same representation,
this won't work.  When you declare the "extra" allocator argument
as a char **, and then store the memory address via it, the memory
allocator will always store the address in char * format - it doesn't
know what actual type of pointer you want to use.

In contrast, even though lint complains, when you use malloc in the
normal way, the C compiler knows that malloc is returning a char *
and you want a different type of pointer, and will generate code to
do the conversion if any is needed on this machine.

So, your suggestion gets rid of the lint complaint, but gives code
that is no longer portable.  If I were marking such an assignment,
I'd mark that as an error.