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) | [3] http://en.wikipedia.org/wiki/PC-Lint | [4] http://www.splint.org/ | [5] /boston/2012/01/13.1 | [6] /boston/2012/01/15.1
=> Gemini Mention this post | Contact the author This content has been proxied by September (ba2dc).Proxy Information
text/gemini