Back in the K&R days [1], C code tended to play rather loose with the rules. As a result, some pretty subtle bugs would go undetected, such as passing the wrong number of parameters to a function, the wrong type of parameters to a function, and ignoring the results of a function. Because of these types of errors, a program called lint [2] was developed that could detect them, as well as other commonly made mistakes. In fact, lint was very fussy about the code it was given.
But it was a popular tool (I remember the ads for PC Lint [3] that would show a snippit of C code that had a subtle bug that PC Lint could detect. I got good enough to spot the errors shown in the ads) and one could always tell code that's been through lint because of code like:
>
```
(void)printf("hello world\n");
```
The standard these days seems to be a program called splint [4] and man, is it picky; just getting code to pass through splint is hard enough, but then there's the -strict option:
-strict
Absurdly strict checking. All checking done by checks, plus modifications and global variables used in unspecified functions, strict standard library, and strict typing of C operators. A special reward will be presented to the first person to produce a real program that produces no errors with strict checking.
Which brings us to today's code:
>
```
/*************************************************************************
*
* Copyright 2012 by Sean Conner. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Comments, questions and criticisms can be sent to: sean@conman.org
*
*************************************************************************/
/* Style: C89, "splint -strict" compliant */
#ifndef S_SPLINT_S
# include <stdio.h>
# include <ctype.h>
# include <string.h>
# include <stdlib.h>
#endif
#define LINESIZE ((size_t)16)
/*@-protoparamname@*/
static void do_dump(FILE *fpin,FILE *fpout)
/*@globals fileSystem @*/
/*@modifies *fpin, *fpout, fileSystem @*/
;
/*@+protoparamname@*/
/****************************************************************/
int main(int argc,char *argv[])
/*@globals fileSystem, stdin, stdout@*/
/*@modifies fileSystem, stdin, stdout@*/
{
if (argc == 1)
{
do_dump(stdin,stdout);
}
else
{
int i;
for (i = 1 ; i < argc ; i++)
{
FILE *fp;
/*@-boundsread@*/
fp = fopen(argv[i],"rb");
/*@+boundsread@*/
if (fp == NULL)
{
perror(argv[i]);
continue;
}
printf("-----%s-----\n",argv[i]);
do_dump(fp,stdout);
if (fclose(fp) == EOF)
{
perror(argv[i]);
}
}
}
return EXIT_SUCCESS;
}
/******************************************************************/
static void do_dump(FILE *fpin,FILE *fpout)
/*@globals fileSystem @*/
/*@modifies *fpin, *fpout, fileSystem@*/
{
unsigned char buffer[BUFSIZ];
unsigned char *pbyte;
size_t offset;
size_t bread;
size_t j;
char ascii[LINESIZE + 1];
offset = 0;
while((bread = fread(buffer,(size_t)1,BUFSIZ,fpin)) > 0)
{
pbyte = buffer;
while (bread > 0)
{
fprintf(fpout,"%08lX: ",(unsigned long)offset);
j = 0;
do
{
fprintf(fpout,"%02X ",(unsigned int)*pbyte);
if (isprint(*pbyte))
{
ascii [j] = (char)*pbyte;
}
else
{
ascii [j] = '.';
}
pbyte ++;
offset ++;
j ++;
bread --;
} while ((j < LINESIZE) && (bread > 0));
ascii [j] = '\0';
if (j < LINESIZE)
{
size_t i;
for (i = j ; i < LINESIZE ; i++)
{
fprintf(fpout," ");
}
}
fprintf(fpout,"%s\n",ascii);
}
if (fflush(fpout) == EOF)
{
perror("output");
exit(EXIT_FAILURE);
}
}
}
/***************************************************************/
```
I'm actually surprised at just how few splint directives I needed (they're those funny looking comments like /*@-frobnitz@*/) to get this code through splint -strict. The only hard part was the function prototype—it didn't matter if I included the parameter names:
>
```
Splint 3.1.2 --- 07 Dec 2009
06.c:34:27: Declaration parameter has name: fpin
A parameter in a function prototype has a name. This is dangerous, since a
macro definition could be visible here. (Use either -protoparamname or
-namechecks to inhibit warning)
06.c:34:38: Declaration parameter has name: fpout
A parameter in a function prototype has a name. This is dangerous, since a
macro definition could be visible here. (Use either -protoparamname or
-namechecks to inhibit warning)
Finished checking --- 2 code warnings
```
or not:
>
```
Splint 3.1.2 --- 07 Dec 2009
06.c:36:15: Unrecognized identifier in modifies comment: fpin
Identifier used in code has not been declared. (Use -unrecog to inhibit
warning)
06.c:36:22: Unrecognized identifier in modifies comment: fpout
sRef.c:1369: at source point
06.c:47:26: *** Internal Bug at sRef.c:1369: llassert failed:
sRef_isReasonable (s) [errno: 25]
*** Please report bug to splint-bug@splint.org ***
(attempting to continue, results may be incorrect)
*** Segmentation Violation
*** Location (not trusted): 06.c:47:26
*** Last code point: exprNode.c:3046
*** Previous code point: exprNode.c:10317
*** Please report bug to splint-bug@splint.org
*** A useful bug report should include everything we need to reproduce the bug.
```
(and it crashes! Woot!)
splint bitched about the prototype. I could have rearranged the code so the prototype was unnecessary, but I decided to shut that particular error up with the /*@-protoparamname@*/ ... /*@+protoparamname@*/ directives. But really, other than that and one other minor bitch, the code passed splint -strict rather easily.
I wonder if I can claim that prize, or is the program too simple?
[1] http://en.wikipedia.org/wiki/K&R_C
[2] http://en.wikipedia.org/wiki/Lint_(software)