[comp.sources.misc] v08i023: memlintok: macros to avoid lint complaints about malloc/free

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/29/89)

Posting-number: Volume 8, Issue 23
Submitted-by: bobl@tessi.UUCP
Archive-name: memlintok

Here is a package which painlessly gets around lint complaints about
the memory allocation functions.  See enclosed the "README" file and
man page for more information.

	- Bob Lewis
	  bobl@tessi.uucp

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile good memlintok.3 memlintok.h t_memlintok.c
# Wrapped by bobl@ghidrah on Mon Aug 28 10:49:33 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(1747 characters\)
sed "s/^X//" >README <<'END_OF_README'
X"memlintok.h" is a header file that can be used to politely shut lint(1) up
Xabout casting results of memory allocation functions malloc(3), realloc(3),
Xand calloc(3).  It also stops complaints about the argument of free(3).
X
XCONTENTS
X--------
XFiles in this distribution are:
X
XREADME			you're reading it
XMakefile		has several useful targets, including "install" and "test"
Xgood			good results for "make test"
Xmemlintok.3		man page
Xmemlintok.h		the header file itself
Xt_memlintok.c	a test/demo program
X
XDISCUSSION
X----------
XOne common way of ignoring lint errors is to do something like:
X
X	#ifdef lint
X	#define malloc(arg) NULL
X	#endif
X
XThe trouble with doing things this way is that lint will not then be able to
Xcheck malloc's argument, so you could get away with something like:
X
X	char *p;
X	char *q;
X	...
X	p = malloc(q);
X
XThe macros here are a bit more sophisticated, so that the memory functions
Xget invoked in a syntactically correct and properly-typed (although
Xsemantically incorrect) fashion and the arguments get checked
Xindependently.  The man page describes their use.
X
XThe file also includes a macro MR_ALLOC_LINTOK that is simply a compact form
Xof the commonly-occurring code to allocate memory if a (typically static)
Xpointer is NULL and to reallocate it if the pointer isn't NULL.
X
XThere are also macros to do some primitive exception handling of the memory
Xallocation function.  See the man page for more on these.
X
XAs I developed it with my own resources, I'm releasing this code to the
Xpublic domain.  I hereby deny any responsibility for its use or any damages
Xresulting from same.
X
XNevertheless, if anyone has any problems with it, questions about it, or
Ximprovements to it, please let me know.
X
X	- Bob Lewis
X	  bobl@tessi.uucp
END_OF_README
if test 1747 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(954 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# $Header: Makefile,v 1.4 89/05/02 15:06:48 bobl Locked $
X
Xdefault: new
X
X#
X#	This is where you want the header to go.  It might be advisable to
X#	put it in some local directory rather than this default one...
X#
XHDR_DEST = /usr/include
X
X#
X#	The man page goes here.  Again, you may have some local place to put it.
X#
XMAN_DEST = /usr/man/man3
X
XFILES = \
X	README \
X	Makefile \
X	good \
X	memlintok.3 \
X	memlintok.h \
X	t_memlintok.c
X
Xclean:
X	rm -f t_memlintok new core a.out *.o memlintok.shar
X
Xnew:	t_memlintok
X	t_memlintok >new
X
Xt_memlintok:	t_memlintok.c memlintok.h
X	cc t_memlintok.c -o t_memlintok
X
Xtest:	new t_memlintok
X	@echo "# comparing new results with known good ones:"
X	diff new good
X	@echo "# should be no lint errors:"
X	lint -bachx t_memlintok.c
X
Xupdate:	new
X	mv -f new good
X
Xshar: memlintok.shar
X
Xmemlintok.shar: $(FILES)
X	shar $(FILES) >memlintok.shar
X
Xinstall: memlintok.h memlintok.3
X	cp memlintok.h $(HDR_DEST)
X	cp memlintok.3 $(MAN_DEST)
X
X	
END_OF_Makefile
if test 954 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f good -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"good\"
else
echo shar: Extracting \"good\" \(244 characters\)
sed "s/^X//" >good <<'END_OF_good'
X100 ints malloc'd
X200 ints realloc'd
X25 ints mr_alloc'd (realloc'd)
X500 ints calloc'd
X1000 ints mr_alloc'd (malloc'd)
X50 ints calloc'd (or else)
X100 ints malloc'd (or else)
X200 ints realloc'd (or else)
X400 ints mr_alloc'd (realloc'd) (or else)
END_OF_good
if test 244 -ne `wc -c <good`; then
    echo shar: \"good\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f memlintok.3 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"memlintok.3\"
else
echo shar: Extracting \"memlintok.3\" \(4706 characters\)
sed "s/^X//" >memlintok.3 <<'END_OF_memlintok.3'
X.TH LINTOK 3 "2 May 1989"
X.SH NAME
Xmemlintok \- package to stop lint complaints about memory allocation
X.SH SYNOPSIS
X.LP
X#include "memlintok.h"
X.SH DESCRIPTION
X.LP
XThis package contains cpp macro definitions that
Xstop lint from complaining about the memory management functions
X.IR malloc (3),
X.IR calloc (3),
X.IR realloc (3),
Xand
X.IR free (3)
X(hereafter, we'll call these the "\fI*alloc\fP(3)" functions),
Xwhile at the same time performing checks of their arguments.
XThere are two sets of macros defined here: one without exception handling
X(like the
X.IR *alloc (3)
Xfunctions themselves) and one with.
X.LP
XThe macros without exception handling are:
X.IP ""
XCALLOC_LINTOK(ptr, nelem, type)
X.br
XMALLOC_LINTOK(ptr, nelem, type)
X.br
XREALLOC_LINTOK(ptr, nelem, type)
X.br
XFREE_LINTOK(ptr)
X.br
X.LP
Xwhere "ptr" is a variable of type "type *".  After invoking any
Xof the "*ALLOC_LINTOK" macros, "ptr" will either be NULL (if and
Xonly if the
Xunderlying function returned it) or it will point to an array of
X"nelem" objects of type "type".
X.LP
XNote that the usage of MALLOC_LINTOK, CALLOC_LINTOK, and
XREALLOC_LINTOK requires more than a name change.  An original
Xcall of the form:
X.IP
Xptr = (type *) malloc(nelem * sizeof(type))
X.LP
Xmust be replaced by
X.IP
XMALLOC_LINTOK(ptr, nelem, type)
X.LP
Xand similarly for CALLOC_LINTOK and REALLOC_LINTOK.  All three
Xmacros "return" values and may therefore be used as part of
Xexpressions.
X.LP
XIf a macro's result is compared with NULL, lint will usually complain
Xif NULL is cast to anything.  For example, this will produce a lint error:
X.IP
Xint *ia;
X.br
X ...
X.br
Xif (MALLOC_LINTOK(ia, 42, int) == (int *) NULL)
X.br
X ...
X.LP
XBut since uncast 0 (i.e., NULL) is always a valid pointer, it
Xis unnecessary to cast it to anything.
XRemoving the cast stops the lint complaint:
X.IP
X ...
X.br
Xif (MALLOC_LINTOK(ia, 42, int) == NULL)
X.br
X ...
X.LP
XIf the macro invocation doesn't appear within an expression,
Xyou will need to cast the *ALLOC_LINTOK()
Xinvocations to
X.B void
Xif you want to get rid of the
X"*alloc returns value which is sometimes ignored"
Xand
X"*alloc returns value which is always ignored"
Xmessages.
X.LP
XYou can mix invocations of these macros with calls to the original
Xfunctions.  The only difference is in the lint behavior.
X.LP
XA common way of invoking the memory management functions is to call
X.IR malloc ()
Xif a
Xpointer is NULL (usually the first time it's set) and
X.IR realloc ()
Xif it isn't NULL (usually on subsequent times).  The simple macro
X.IP
XMR_ALLOC_LINTOK(ptr, nelem, type)
X.LP
Xdoes this with MALLOC_LINTOK() and REALLOC_LINTOK().
X.LP
XSince memory allocation failure is often an exceptional condition,
X"memlintok.h" also has definitions of four other useful macros that include
Xexception handling:
X.IP
XCALLOC_OR_ELSE_LINTOK(ptr, nelem, type)
X.br
XMALLOC_OR_ELSE_LINTOK(ptr, nelem, type)
X.br
XREALLOC_OR_ELSE_LINTOK(ptr, nelem, type)
X.br
XMR_ALLOC_OR_ELSE_LINTOK(ptr, nelem, type)
X.br
X.LP
XEach of these macros invokes the corresponding *ALLOC_LINTOK() macro and,
Xif that macro fails, invokes another macro:
X.IP
XERROR_EXIT_LINTOK(nelem, size)
X.LP
XWhere "nelem" is the number of elements of "size" bytes attempting to be
Xallocated.
X.LP
XA default ERROR_EXIT_LINTOK(nelem, size), which prints an informative
Xmessage and dies, is also defined, but you are free to redefine it
X(after including "memlintok.h" and before invoking any of the macros herein
X-- remember to "#undef ERROR_EXIT_LINTOK" first)
Xif you want to do your own error handling.
X.SH "SEE ALSO"
X.BR malloc (3),
X.BR stdio (3S)
X.SH NOTE
X.LP
X"memlintok.h" assumes NULL is defined in <stdio.h> (which is usually the case).
X.LP
XIt also assumes the cpp symbol "lint" is defined when and only when the
Xcode is being passed through lint and not generating real executable code.
X.LP
XThese macros have been tested under SunOS, HP-UX, and Apollo DOMAIN/IX.
X.SH BUGS
X.LP
XThese macros are intended for use with the dynamic
Xallocation of single elements of fixed size (i.e. structs or typedefs)
Xor variably-sized arrays of same.
XIn the author's experience, this covers most uses of the
X.IR \fI*alloc\fP (3)
Xfunctions.
XThe macros do not work well, however, when creating variably-sized single
Xstructures that are not arrays.
X.LP
XAt least one version of
X.IR lint (1)
X(SunOS 4.0) complains when these macros
Xare used with "void *" pointers.
XIt needn't.
X.LP
XApollo DOMAIN/IX
X.IR lint (1)
Xgenerates several bogus (I believe) complaints about the default exception
Xhandling macro.
X.SH AUTHOR
X.LP
XBob Lewis (bobl@tessi.uucp) produced these macros using his own
Xresources and hereby releases them to the public domain.
XThe author will not be held responsible for their use, misuse,
Xabuse, or any damages arising from same.
END_OF_memlintok.3
if test 4706 -ne `wc -c <memlintok.3`; then
    echo shar: \"memlintok.3\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f memlintok.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"memlintok.h\"
else
echo shar: Extracting \"memlintok.h\" \(2986 characters\)
sed "s/^X//" >memlintok.h <<'END_OF_memlintok.h'
X#ifndef INCLUDED_LINTOK
X
X/* $Header: memlintok.h,v 1.3 89/05/02 15:01:43 bobl Locked $ */
X
X/*
X *	These definitions stop lint from complaining about malloc, calloc,
X *	realloc, and free while at the same time performing checks of
X *	their arguments.  See the memlintok(3) man page for more details.
X *
X *	Bob Lewis (bobl@tessi.uucp) produced these macros using his own
X *	resources and hereby releases them to the public domain.
X *	The author will not be held responsible for their use, misuse,
X *	abuse, or any damages arising from same.
X */
X
X#ifndef NULL
X#include <stdio.h>
X#endif
X
Xextern char *calloc();
X#ifdef lint
X#define CALLOC_LINTOK(ptr, nelem, type) \
X	calloc((ptr = (type *) NULL, (unsigned) (nelem)), (unsigned) sizeof(type))
X#else
X#define CALLOC_LINTOK(ptr, nelem, type) \
X	(ptr = (type *) calloc((unsigned) (nelem), (unsigned) sizeof(type)))
X#endif
X
Xextern char *malloc();
X#ifdef lint
X#define MALLOC_LINTOK(ptr, nelem, type) \
X	malloc((ptr = (type *) NULL, (unsigned) ((nelem) * sizeof(type))))
X#else
X#define MALLOC_LINTOK(ptr, nelem, type) \
X	(ptr = (type *) malloc((unsigned) ((nelem) * sizeof(type))))
X#endif
X
Xextern char *realloc();
X#ifdef lint
X#define REALLOC_LINTOK(ptr, nelem, type) \
X	realloc( \
X		(ptr = (type *) NULL, (char *) NULL), \
X		(unsigned) ((nelem) * sizeof(type)))
X#else
X#define REALLOC_LINTOK(ptr, nelem, type) \
X	(ptr = (type *) realloc( \
X		(char *) ptr, \
X		(unsigned) ((nelem) * sizeof(type))))
X#endif
X
X/* common use of malloc/realloc -- use it or don't use it */
X#define MR_ALLOC_LINTOK(ptr, nelem, type) \
X	( (ptr) == NULL \
X		? MALLOC_LINTOK(ptr, (nelem), type) \
X		: REALLOC_LINTOK(ptr, (nelem), type) )
X
X/*
X *	These next macros invoke CALLOC_LINTOK, MALLOC_LINTOK, REALLOC_LINTOK,
X *	and MR_ALLOC_LINTOK with an error exit if they fail.
X *
X *	If you want to handle your own memory allocation errors, just
X *	"#undef ERROR_EXIT_LINTOK" and define your own.
X */
X#define ERROR_EXIT_LINTOK(nelem, size) \
X	{ \
X		(void) fprintf(stderr, \
X			"Memory allocation of %d * %d bytes on line %d of \"%s\" failed.\n", \
X			(nelem), (size), __LINE__, __FILE__); \
X		exit(1); \
X	}
X
X#define CALLOC_OR_ELSE_LINTOK(ptr, nelem, type) \
X	{ \
X		if (CALLOC_LINTOK(ptr, (nelem), type) == NULL) \
X			ERROR_EXIT_LINTOK((nelem), sizeof(type)); \
X	}
X
X#define MALLOC_OR_ELSE_LINTOK(ptr, nelem, type) \
X	{ \
X		if (MALLOC_LINTOK(ptr, (nelem), type) == NULL) \
X			ERROR_EXIT_LINTOK((nelem), sizeof(type)); \
X	}
X
X#define REALLOC_OR_ELSE_LINTOK(ptr, nelem, type) \
X	{ \
X		if (REALLOC_LINTOK(ptr, (nelem), type) == NULL) \
X			ERROR_EXIT_LINTOK((nelem), sizeof(type)); \
X	}
X
X#define MR_ALLOC_OR_ELSE_LINTOK(ptr, nelem, type) \
X	{ \
X		if (MR_ALLOC_LINTOK(ptr, (nelem), type) == NULL) \
X			ERROR_EXIT_LINTOK((nelem), sizeof(type)); \
X	}
X
Xextern free();
X#ifdef lint
X#define FREE_LINTOK(ptr) \
X	free((ptr = NULL, (char *) NULL))
X#else
X#define FREE_LINTOK(ptr) \
X	free((char *) ptr)
X#endif
X
X/* We could have a "CFREE_LINTOK", but what's the point? */
X
X#define INCLUDED_LINTOK
X#endif
X
END_OF_memlintok.h
if test 2986 -ne `wc -c <memlintok.h`; then
    echo shar: \"memlintok.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f t_memlintok.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"t_memlintok.c\"
else
echo shar: Extracting \"t_memlintok.c\" \(1438 characters\)
sed "s/^X//" >t_memlintok.c <<'END_OF_t_memlintok.c'
X/* $Header: t_memlintok.c,v 1.3 89/05/02 15:07:08 bobl Exp $ */
X
X#include <stdio.h>
X
X#include "memlintok.h"
X
Xmain()
X{
X	int *p, *q;
X
X	if (MALLOC_LINTOK(p, 100, int) == NULL)
X		fail("can't malloc 100 ints\n");
X	else
X		succeed("100 ints malloc'd\n");
X
X	(void) REALLOC_LINTOK(p, 200, int);
X	if (p == NULL)
X		fail("can't realloc 200 ints\n");
X	else
X		succeed("200 ints realloc'd\n");
X
X	if (MR_ALLOC_LINTOK(p, 25, int) == NULL)
X		fail("can't mr_alloc (realloc) 25 ints\n");
X	else
X		succeed("25 ints mr_alloc'd (realloc'd)\n");
X
X	if (CALLOC_LINTOK(q, 500, int) == NULL)
X		fail("can't calloc 500 ints\n");
X	else
X		succeed("500 ints calloc'd\n");
X	q[0] = 0;
X	FREE_LINTOK(q);
X
X	FREE_LINTOK(p);
X	p = NULL;
X	if (MR_ALLOC_LINTOK(p, 1000, int) == NULL)
X		fail("can't mr_alloc (malloc) 1000 ints\n");
X	else
X		succeed("1000 ints mr_alloc'd (malloc'd)\n");
X
X	CALLOC_OR_ELSE_LINTOK(p, 50, int);
X	succeed("50 ints calloc'd (or else)\n");
X	MALLOC_OR_ELSE_LINTOK(p, 100, int);
X	succeed("100 ints malloc'd (or else)\n");
X	REALLOC_OR_ELSE_LINTOK(p, 200, int);
X	succeed("200 ints realloc'd (or else)\n");
X
X#undef ERROR_EXIT_LINTOK
X#define ERROR_EXIT_LINTOK(nelem, size) \
X	fail("memory allocation failed\n");
X
X	MR_ALLOC_OR_ELSE_LINTOK(p, 400, int);
X	succeed("400 ints mr_alloc'd (realloc'd) (or else)\n");
X
X	exit(0);
X	return 0;	/* shuts up HP-UX lint */
X}
X
Xfail(s)
X	char *s;
X{
X	fputs(s, stdout);
X	exit(1);
X}
X
Xsucceed(s)
X	char *s;
X{
X	fputs(s, stdout);
X	return;
X}
END_OF_t_memlintok.c
if test 1438 -ne `wc -c <t_memlintok.c`; then
    echo shar: \"t_memlintok.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0