[splint-discuss] string concatenation patch

Ed Beroset beroset at mindspring.com
Mon Dec 31 06:52:20 PST 2007


Over the weekend I was trying to fix up splint so that it wouldn't die 
with a parser error for code like the following:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
     printf("The answer is %" PRIu32 ".\n", 42);
     return 0;
}

For those who don't recall, the ISO C 99 standard added printf and scanf 
format specifiers to inttypes.h.  There are two issues here.  The first 
is that the inttypes.h that is in splint's standard.h doesn't include 
these definitions.  I tried a few things, but failed in that attempt so 
far.  (Maybe somebody can show me how to do this.)

The second issue is that a C compiler, according to section 5.1.1.2 of 
the standard, should concatenate adjacent string literals.  That means 
that even when the statement is written as

printf("The answer is %" "d" ".\n", 42);

splint doesn't understand it.  I believe I have solved that issue and 
the patch is pasted to the bottom of this email message, but here's the 
logic behind it.  I looked and the grammar file already accepts multiple 
strings like that, but the format specifier checking wasn't able to 
handle the multiple strings.  What I did was to change the 
exprNode_stringLiteral() function in exprNode.c so that it now merges 
the strings before creating the node.  Since the same function is also 
invoked for wide strings, it should work either way if I've done things 
correctly.  Some confirmation of that would be useful.

Also, I tried running splint on its own source code, but was unable to 
get it to parse the original file.  I think I have the annotations 
correct, but some hint as to how to check at least this file with splint 
would also be helpful to me.  Thanks for the great tool.  I hope the 
patch (which was created from the 3.1.2 source tarball) is useful.

Ed

--- src/exprNode.c.orig	2007-12-31 09:02:46.000000000 -0500
+++ src/exprNode.c	2007-12-31 09:14:48.000000000 -0500
@@ -865,10 +865,52 @@
    size_t len = size_fromInt (size_toInt (cstring_length (t)) - 2);
    char *ts = cstring_toCharsSafe (t);
    char *s = cstring_toCharsSafe (cstring_create (len + 1));
+  char *ss = s;
+  bool escape = FALSE;
+  bool betweenStrings = FALSE;
+  int i;

    llassert (*ts == '\"' && *(ts + len + 1) == '\"');
-  strncpy (s, ts+1, len);
-  *(s + len) = '\0';
+  /* from ISO/IEC 9899 5.1.1.2 Translation phases, phase 6,
+     "Adjacent string literal tokens are concatenated."
+
+     This code does the concatenation as part of the copying
+  */
+  ts++;
+  for (i=0; i < len; i++)
+    {
+      switch (*ts)
+	{
+	case '\\':
+	  *ss++ = *ts++;
+	  escape = TRUE;
+	  /*@switchbreak@*/ break;
+	case '\"':
+	  betweenStrings = !escape;
+	  if (!betweenStrings)
+	    {
+	      *ss++ = *ts;
+	    }
+	  ts++;
+	  escape = FALSE;
+	  /*@switchbreak@*/ break;
+	case ' ':
+	case '\n':
+	case '\t':
+	  if (!betweenStrings)
+	    {
+	      *ss++ = *ts;
+	    }
+	  ts++;
+	  escape = FALSE;
+	  /*@switchbreak@*/ break;
+	default:
+	  *ss++ = *ts++;
+	  escape = FALSE;
+	  /*@switchbreak@*/ break;
+	}
+    }
+  *ss = '\0';
    cstring_free (t);
    return exprNode_rawStringLiteral (cstring_fromCharsO (s), loc);
  }



More information about the splint-discuss mailing list