From raymond-xu at 126.com Tue Sep 5 23:03:48 2006 From: raymond-xu at 126.com (raymond) Date: Tue Sep 5 23:35:32 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <1157511828.5192.9.camel@localhost> I write a simple C program with a Macro like below: /*test.c*/ 1 #include 2 #include 3 #include 4 #define MSG_COMMON_HEADER() \ 5 u_int16_t len; \ 6 u_int16_t type; 7 8 struct any_msg { 9 MSG_COMMON_HEADER (); 10 }; 11 12 int main( int argc , char** argv) 13 { 14 struct any_msg msg = { 15 .type = 0, 16 .len = 4}; 17 printf( "msg.type = %d msg.len = %d\n", msg.type,msg.len); 18 return 0; 19 } Using the splint cmd: splint +posixlib macro_splint.c it outputs: Splint 3.1.1 --- 06 Jan 2006 macro_splint.c:9:13: Parse Error. (For help on parse errors, see splint -help parseerrors.) *** Cannot continue. It seems like splint can't parse the MSG_COMMON_HEADER() macro. Has anyone met this problem? Thanks a lot From benjl at cse.unsw.edu.au Tue Sep 5 23:41:25 2006 From: benjl at cse.unsw.edu.au (Benno) Date: Tue Sep 5 23:57:48 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <1157511828.5192.9.camel@localhost> References: <1157511828.5192.9.camel@localhost> Message-ID: <20060906034125.GP14443@cse.unsw.edu.au> On Wed Sep 06, 2006 at 11:03:48 +0800, raymond wrote: >I write a simple C program with a Macro like below: > >/*test.c*/ > 1 #include > 2 #include > 3 #include > 4 #define MSG_COMMON_HEADER() \ > 5 u_int16_t len; \ > 6 u_int16_t type; > 7 > 8 struct any_msg { > 9 MSG_COMMON_HEADER (); > 10 }; Won't this expand to: struct any_msg { u_int16_t len; u_int16_t type;; } Note the doulbe semi-colon. I'm not sure if that is valid C or not. It's definately not nice though. Don't know if that is the problem or not, but could be. Cheers, Benno > 12 int main( int argc , char** argv) > 13 { > 14 struct any_msg msg = { > 15 .type = 0, > 16 .len = 4}; > 17 printf( "msg.type = %d msg.len = %d\n", msg.type,msg.len); > 18 return 0; > 19 } > >Using the splint cmd: > splint +posixlib macro_splint.c >it outputs: > > Splint 3.1.1 --- 06 Jan 2006 > > macro_splint.c:9:13: Parse Error. (For help on parse errors, see > splint -help > parseerrors.) > *** Cannot continue. >It seems like splint can't parse the MSG_COMMON_HEADER() macro. > >Has anyone met this problem? > >Thanks a lot > > >_______________________________________________ >splint-discuss mailing list >splint-discuss@ares.cs.Virginia.EDU >http://www.cs.Virginia.EDU/mailman-2.1.5/listinfo/splint-discuss From raymond-xu at 126.com Wed Sep 6 00:46:19 2006 From: raymond-xu at 126.com (raymond) Date: Wed Sep 6 00:46:33 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <20060906034125.GP14443@cse.unsw.edu.au> References: <1157511828.5192.9.camel@localhost> <20060906034125.GP14443@cse.unsw.edu.au> Message-ID: <1157517980.5192.13.camel@localhost> On Wed, 2006-09-06 at 13:41 +1000, Benno wrote: > On Wed Sep 06, 2006 at 11:03:48 +0800, raymond wrote: > >I write a simple C program with a Macro like below: > > > >/*test.c*/ > > 1 #include > > 2 #include > > 3 #include > > 4 #define MSG_COMMON_HEADER() \ > > 5 u_int16_t len; \ > > 6 u_int16_t type; > > 7 > > 8 struct any_msg { > > 9 MSG_COMMON_HEADER (); > > 10 }; > > > Won't this expand to: > > struct any_msg { > u_int16_t len; > u_int16_t type;; > } > > Note the doulbe semi-colon. I'm not sure if that is valid C or not. > It's definately not nice though. > > Don't know if that is the problem or not, but could be. > > Cheers, > > Benno > It's not the reason, because I drop the semicolon on the line # 9, it still have the same parse error. > > 12 int main( int argc , char** argv) > > 13 { > > 14 struct any_msg msg = { > > 15 .type = 0, > > 16 .len = 4}; > > 17 printf( "msg.type = %d msg.len = %d\n", msg.type,msg.len); > > 18 return 0; > > 19 } > > > >Using the splint cmd: > > splint +posixlib macro_splint.c > >it outputs: > > > > Splint 3.1.1 --- 06 Jan 2006 > > > > macro_splint.c:9:13: Parse Error. (For help on parse errors, see > > splint -help > > parseerrors.) > > *** Cannot continue. > >It seems like splint can't parse the MSG_COMMON_HEADER() macro. > > > >Has anyone met this problem? > > > >Thanks a lot > > > > > >_______________________________________________ > >splint-discuss mailing list > >splint-discuss@ares.cs.Virginia.EDU > >http://www.cs.Virginia.EDU/mailman-2.1.5/listinfo/splint-discuss > _______________________________________________ > splint-discuss mailing list > splint-discuss@ares.cs.Virginia.EDU > http://www.cs.Virginia.EDU/mailman-2.1.5/listinfo/splint-discuss > From ok at cs.otago.ac.nz Wed Sep 6 00:51:43 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Wed Sep 6 01:22:53 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609060451.k864pht2354024@atlas.otago.ac.nz> raymond wrote: I write a simple C program with a Macro like below: /*test.c*/ 1 #include 2 #include 3 #include 4 #define MSG_COMMON_HEADER() \ 5 u_int16_t len; \ ====> 6 u_int16_t type; Note 1: having empty parentheses in a macro definition is technically undefined in C89. (I'm not sure, it might be illegal.) Note 2: your macro ends with a ';'. 7 8 struct any_msg { =====> 9 MSG_COMMON_HEADER (); Note 3: having empty parentheses in a macro call is technically undefined in C89. (I'm not sure, it might be illegal.) In any case, putting argument parentheses on something which HAS no arguments and ISN'T intended to be function-like is, um, the very opposite of good style. It confuses people. Note 4: your macro call has ANOTHER ';' after it. 10 }; 11 12 int main( int argc , char** argv) 13 { 14 struct any_msg msg = { 15 .type = 0, 16 .len = 4}; 17 printf( "msg.type = %d msg.len = %d\n", msg.type,msg.len); 18 return 0; 19 } Using the splint cmd: splint +posixlib macro_splint.c it outputs: Splint 3.1.1 --- 06 Jan 2006 macro_splint.c:9:13: Parse Error. (For help on parse errors, see splint -help parseerrors.) *** Cannot continue. It seems like splint can't parse the MSG_COMMON_HEADER() macro. It's not the macro, it's the result of macro expansion. Do it by hand! What you get is struct any_msg { u_int16_t len; u_int16_t type;; }; /* ^^ */ which isn't legal C and never has been. No conforming C processor can parse this; it is flat out illegal, and in telling you so, splint is doing no more than its job. There's one more thing. Splint is a C89 checker, not a C99 checker. I'm sure we all long for it to become a C99 checker, and had I world enough and time I'd be in there hacking it myself. (Sadly, I don't.) The construction struct any_msg msg = {.type = 0, .len = 4}; is new in C99; C89 did not support any form of named initialisation for structs, only positional. What's the right way to do it? #include #include #include #define MSG_COMMON_FIELDS \ u_int16_t len; \ u_int16_t type; struct any_msg { MSG_COMMON_FIELDS }; int main(int argc, char** argv) { struct any_msg msg = {/*len*/ 4, /*type*/ 0}; printf("msg.type = %d msg.len = %d\n", msg.type, msg.len); return 0; } From raymond-xu at 126.com Wed Sep 6 01:47:21 2006 From: raymond-xu at 126.com (raymond) Date: Wed Sep 6 01:47:35 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609060451.k864pht2354024@atlas.otago.ac.nz> References: <200609060451.k864pht2354024@atlas.otago.ac.nz> Message-ID: <1157521642.5192.16.camel@localhost> > > There's one more thing. Splint is a C89 checker, not a C99 checker. > I'm sure we all long for it to become a C99 checker, and had I world > enough and time I'd be in there hacking it myself. (Sadly, I don't.) > The construction > > struct any_msg msg = {.type = 0, .len = 4}; > > is new in C99; C89 did not support any form of named initialisation > for structs, only positional. > > What's the right way to do it? > > #include > #include > #include > #define MSG_COMMON_FIELDS \ > u_int16_t len; \ > u_int16_t type; > > struct any_msg { > MSG_COMMON_FIELDS > }; > > int main(int argc, char** argv) { > struct any_msg msg = {/*len*/ 4, /*type*/ 0}; > > printf("msg.type = %d msg.len = %d\n", msg.type, msg.len); > return 0; > } > Thanks your advices, but when I try your code, splint doesn't work, it still has the same parse error, From ok at cs.otago.ac.nz Wed Sep 6 01:52:06 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Wed Sep 6 01:52:21 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609060552.k865q6QP357211@atlas.otago.ac.nz> raymond insists that [the double semicolon is] not the reason, because I drop the semicolon on the line # 9, it still have the same parse error. Let's see what happens when we try some other programs. a% cat -n fu.c 1 #include 2 #include 3 #include 4 #define MSG_COMMON_HEADER() \ 5 u_int16_t len; \ 6 u_int16_t type; 7 8 struct any_msg { 9 MSG_COMMON_HEADER(); 10 }; 11 12 int main(int argc , char** argv) { 13 struct any_msg msg = { .type = 0, .len = 4 }; 14 15 printf("msg.type = %d msg.len = %d\n", msg.type, msg.len); 16 return 0; 17 } 18 First, the Alpha OSF/1 lint checker: a% lint fu.c "fu.c", line 9: error: syntax error "fu.c", line 9: error: structure members must be terminated by ';' "fu.c", line 10: error: zero sized structure OK, there really IS a parse error there, splint was right about that. "fu.c", line 13: error: illegal structure initialization "fu.c", line 13: error: syntax error That is, the C99-style struct initialisation really DOESN'T work in C89. "fu.c", line 15: warning: type undefined "fu.c", line 15: error: member of structure or union required "fu.c", line 15: warning: len undefined "fu.c", line 15: error: member of structure or union required "fu.c", line 15: error: operator (CALL) in a constant expression "fu.c", line 12: warning: argument argc unused in function main "fu.c", line 12: warning: argument argv unused in function main The rest are cascades. Now, let's try GCC, with a lot of warnings switched on: a% glint fu.c fu.c:9: parse error before `u_int16_t' fu.c:9: warning: no semicolon at end of struct or union fu.c:9: warning: type defaults to `int' in declaration of `type' fu.c:9: ANSI C forbids data definition with no type or storage class Hmm, that's odd, there seems to be something else going on. Let's come back to that. fu.c:9: warning: ANSI C does not allow extra `;' outside of a function fu.c:10: parse error before `}' fu.c:10: warning: ANSI C does not allow extra `;' outside of a function Right, the double semicolon *IS* a problem. It may not be THE problem, but it is A problem. fu.c: In function `main': fu.c:13: variable `msg' has initializer but incomplete type fu.c:13: unknown field `type' specified in initializer fu.c:13: warning: excess elements in struct initializer fu.c:13: warning: (near initialization for `msg') fu.c:13: unknown field `len' specified in initializer fu.c:13: warning: excess elements in struct initializer fu.c:13: warning: (near initialization for `msg') fu.c:13: storage size of `msg' isn't known fu.c:13: warning: unused variable `msg' fu.c:12: warning: unused parameter `argc' fu.c:12: warning: unused parameter `argv' Probably cascades from the earlier problems. So what else is going on? Let's get the compiler to tell us. a% glint -E foo.c <<3300 lines NOT containing any definition of u_int16_t snipped>> struct any_msg { u_int16_t len; u_int16_t type; ; }; int main(int argc , char** argv) { struct any_msg msg = { .type = 0, .len = 4 }; printf("msg.type = %d msg.len = %d\n", msg.type, msg.len); return 0; } And there is the problem. DOES NOT DEFINE u_int16_t (I have checked POSIX) DOES NOT DEFINE u_int16_t (I have checked C89) DOES NOT DEFINE u_int16_t (I have checked C89) In fact, NOTHING in this program defines u_int16_t. More than that, even C99 doesn't define any u_int16_t. There _is_ a standard header in C99 which defines, amongst other types, uint16_t (on a Linux box, try 'man stdint'). Some people prefer , which provides more information about those types, but doesn't add any extra types. There is NOTHING in C99 that provides u_int16_t. I have now checked on Fedora Linux, Alpha OSF/1, MacOS X, and Solaris 2.9. In none of them does this compile with any C compiler, including ones like gcc and Sun C that claim to be very nearly C99-compatible. So where is u_int16_t supposed to come from? It's not C89, it's not C99, it's not POSIX (the current POSIX, or at any rate the current Single Unix Specification, is aligned with C99, so would have no reason to define u_int16_t when uint_16_t is ready to hand), it's not Linux, it's not Solaris, it's not MacOS X, what _is_ it? splint is telling you about a very real problem; it's a pity that the parser doesn't say something like u_int_16_t may be intended as a type name but isn't one instead of falling over in a heap of rubble, but the immediate problem is definitely in your code, not splint. From ok at cs.otago.ac.nz Wed Sep 6 02:10:40 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Wed Sep 6 02:10:55 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609060610.k866Ae2B359257@atlas.otago.ac.nz> raymond wrote: Thanks your advices, but when I try your code, splint doesn't work, it still has the same parse error, OK, we now understand the problem completely. The original code had THREE problems (FOUR if you count () in a macro): (1) The double semicolon (not legal anywhere) (2) Struct initialisation by name instead of position (C99) AND (3) u_int16_t (uint16_t is in C99 and ) It turns out that Linux defines u_int16_t in , which includes. However, _using_ that is "unwarranted chumminess" with the headers; 'man unistd.h' says nothing about any such type. That header also typedefs: __uint16_t __U16_TYPE (actually a macro) __u_short (and u_short if you #define BSD first) __u_int16_t apparently amongst others, equally undocumented in 'man unistd.h'. The simplest thing would be to set up your own stdint.h header and #include "stdint.h" Set this up so that splint finds your copy of stdint.h and the C compiler finds the system's copy; add to your copy all the types and macros you happen to need. You *really* shouldn't be getting u_int16_t from because most UNIX-like systems *don't* define it there and those that do give you no reason to believe that it will still be there in the next release. (The obvious thing to do would be to replace these Linux-specific u_int{N}_tnames by the C99 uint{N}_t names.) From raymond-xu at 126.com Wed Sep 6 02:30:50 2006 From: raymond-xu at 126.com (raymond) Date: Wed Sep 6 02:31:02 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609060610.k866Ae2B359257@atlas.otago.ac.nz> References: <200609060610.k866Ae2B359257@atlas.otago.ac.nz> Message-ID: <1157524250.5192.17.camel@localhost> Thanks a lot! I think that I understand the problem completely, you are so warm-hearted. From jdennett at acm.org Wed Sep 6 01:34:47 2006 From: jdennett at acm.org (James Dennett) Date: Wed Sep 6 03:35:42 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609060451.k864pht2354024@atlas.otago.ac.nz> References: <200609060451.k864pht2354024@atlas.otago.ac.nz> Message-ID: <44FE5DF7.3000702@acm.org> Richard A. O'Keefe wrote: > raymond wrote: > I write a simple C program with a Macro like below: > > /*test.c*/ > 1 #include > 2 #include > 3 #include > 4 #define MSG_COMMON_HEADER() \ > 5 u_int16_t len; \ > ====> 6 u_int16_t type; > > Note 1: having empty parentheses in a macro definition is technically > undefined in C89. (I'm not sure, it might be illegal.) > Are you sure? It's well-defined in C++98, which is almost identical to C89/90 in terms of preprocessing. An empty parameter name is illegal, but the case of () defines a function-like macro with no arguments. AFAIK this is a moderately common, strictly conforming, technique. > Note 2: your macro ends with a ';'. > > Usually a bad idea, indeed. > 7 > 8 struct any_msg { > =====> 9 MSG_COMMON_HEADER (); > > Note 3: having empty parentheses in a macro call is technically > undefined in C89. (I'm not sure, it might be illegal.) > It's required to use a function-like macro with no arguments, I believe. > In any case, putting argument parentheses on something which HAS > no arguments and ISN'T intended to be function-like is, um, the > very opposite of good style. It confuses people. > > Note 4: your macro call has ANOTHER ';' after it. > Which is bad style, at least. -- James From Michael.Wojcik at microfocus.com Wed Sep 6 08:00:45 2006 From: Michael.Wojcik at microfocus.com (Michael Wojcik) Date: Wed Sep 6 08:23:52 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <11352F9641010A418AD5057945A3A6594CC099@MTV-EXCHANGE.microfocus.com> > From: splint-discuss-bounces@cs.virginia.edu > [mailto:splint-discuss-bounces@cs.virginia.edu] On Behalf Of > James Dennett > Sent: Wednesday, 06 September, 2006 01:35 > To: splint-discuss@cs.virginia.edu > > Richard A. O'Keefe wrote: > > raymond wrote: > > 4 #define MSG_COMMON_HEADER() \ > > 5 u_int16_t len; \ > > ====> 6 u_int16_t type; > > > > Note 1: having empty parentheses in a macro definition is technically > > undefined in C89. (I'm not sure, it might be illegal.) > > > Are you sure? It's well-defined in C++98, which is almost identical to > C89/90 in terms of preprocessing. An empty parameter name is illegal, > but the case of () defines a function-like macro with no arguments. I think Richard's wrong about this one. ISO 9899-1990 6.8.3 shows the identifier-list as optional (it has the "opt" subscript in the "of the form" sentence), and goes on to say "parameters are specified by the optional list of identifiers". The grammar in (non-normative) Annex B agrees (B.3). This hasn't changed in C99 (ISO 9899-1999 6.10.3 #10). That said, I agree with him that using a function-like macro in an object-like manner strikes me as poor style, and the rest of his comments were spot-on. -- Michael Wojcik Principal Software Systems Developer Micro Focus michael.wojcik@microfocus.com 9420 Key West Avenue Rockville, MD 20850 Direct: 517 676 0892 What would you like Micro Focus to do for you? Contribute your view by visiting http://www.microfocus.com/CustomerInsight.asp From ok at cs.otago.ac.nz Wed Sep 6 19:38:40 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Wed Sep 6 19:39:35 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609062338.k86Ncelh365044@atlas.otago.ac.nz> I wrote: > Note 1: having empty parentheses in a macro definition is technically > undefined in C89. (I'm not sure, it might be illegal.) James Dennett queried this: Are you sure? It's well-defined in C++98, which is almost identical to C89/90 in terms of preprocessing. An empty parameter name is illegal, but the case of () defines a function-like macro with no arguments. AFAIK this is a moderately common, strictly conforming, technique. Over the years I have owned three copies of the ANSI C standard (two of them copies of the Australian edition, one of them the infamous Herbert Schildt edition). All of them have walked out of my office. So it's hard to check. (Now that C89 is no longer an official standard, why isn't the standard available free over the net?) Fortunately, WG14 have kept an archive, which you can find on the net, and it turns out that my recollection was 100% correct. Allowing an empty argument list for a function-like macro was a CHANGE from C89 to C99. It was proposed by Fred J. Tydeman on 1995-01-09. Empty parentheses on a macro really truly were officially undefined behaviour, and he knew of a compiler which complained. He was talking about empty *actual parameters*, but the two are related. There is no point in writing #define FOO() ... unless you mean to invoke it as ... FOO() ... and the latter really was undefined behaviour caught by at least one compiler. I'm pretty sure the definition was undefined behaviour as well. > Note 3: having empty parentheses in a macro call is technically > undefined in C89. (I'm not sure, it might be illegal.) It's required to use a function-like macro with no arguments, I believe. So it may be, but you still weren't allowed to do it in C89. From terry-splint at tenberry.com Wed Sep 6 21:39:36 2006 From: terry-splint at tenberry.com (Terry Colligan) Date: Wed Sep 6 22:06:24 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609062338.k86Ncelh365044@atlas.otago.ac.nz> References: <200609062338.k86Ncelh365044@atlas.otago.ac.nz> Message-ID: <200609061839.37087.terry-splint@tenberry.com> On Wednesday 06 September 2006 04:38 pm, Richard A. O'Keefe wrote: > I wrote: > > Note 1: having empty parentheses in a macro definition is technically > > undefined in C89. (I'm not sure, it might be illegal.) > > James Dennett queried this: > Are you sure? It's well-defined in C++98, which is almost > identical to C89/90 in terms of preprocessing. An empty > parameter name is illegal, but the case of () defines a > function-like macro with no arguments. AFAIK this is a > moderately common, strictly conforming, technique. > > Over the years I have owned three copies of the ANSI C standard > (two of them copies of the Australian edition, one of them the > infamous Herbert Schildt edition). All of them have walked out > of my office. So it's hard to check. (Now that C89 is no longer > an official standard, why isn't the standard available free over > the net?) Fortunately, WG14 have kept an archive, which you can find on > the net, and it turns out that my recollection was 100% correct. Actually, no, it is not. First, let me say that I was a member of the orginal X3J11 committee. I have several copies of the X3.159-1989 standard (the predecessor to the WG14 committee), and I remember the discussions fairly clearly. I re-read the standard to confirm my understanding. A function-like macro defined with parens and with no arguments was in the draft standard from when I started on the committee, around 1983. It is not in the base document, the original 1978 K&R book. It was added pre-1983. It is (and was) clearly necessary to allow macros to replace functions, something which has been in C for a long time. It *is* clearly in the X3.159-1989 standard, in section 3.8.3. > Allowing an empty argument list for a function-like macro was a > CHANGE from C89 to C99. It was proposed by Fred J. Tydeman on 1995-01-09. > Empty parentheses on a macro really truly were officially undefined > behaviour, and he knew of a compiler which complained. > > He was talking about empty *actual parameters*, but the two are related. > There is no point in writing > #define FOO() ... > unless you mean to invoke it as > ... FOO() ... Yes! Exactly. > and the latter really was undefined behaviour caught by at least one > compiler. Then that compiler was not conforming to the 1989 standard. > I'm pretty sure the definition was undefined behaviour as well. No, it wasn't/isn't. The syntax (which is a defining part of the standard) clearly allows for parens with no arguments in the #define directive, and the descriptive text is written in a form that has a clear interpretation for no defined arguments. The description is relentlessly and excessively terse, but that was one of our goals -- to be as brief as possible so as to reduce the chance of the standard being self-conflicting. Personally, I think we went overboard and made the standard much harder to read as a result. What C99 upgraded from a common extension to part of the standard was the possiblility of empty actual arguments. > > Note 3: having empty parentheses in a macro call is technically > > undefined in C89. (I'm not sure, it might be illegal.) > > It's required to use a function-like macro with no arguments, I > believe. > > So it may be, but you still weren't allowed to do it in C89. Yes, you were -- at least in any conforming compiler. -- Terry Terry Colligan terry-splint@tenberry.com From ok at cs.otago.ac.nz Wed Sep 6 22:52:01 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Wed Sep 6 22:52:22 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609070252.k872q1Wg361916@atlas.otago.ac.nz> I made two claims, one of which was wrong and one of which was right: (1) defining a macro with () was not defined in C89 [wrong]. (2) invoking a macro with () was not defined in C89 [right]. Recall that > Allowing an empty argument list for a function-like macro was a > CHANGE from C89 to C99. It was proposed by Fred J. Tydeman on 1995-01-09. So we had the more than odd situation that apparently you were allowed to define an argumentless function-like macro but you weren't allowed to invoke it with no arguments. Terry Colligan , who should speak with authority, tries to have it both ways: It is (and was) clearly necessary to allow macros to replace functions, something which has been in C for a long time. True, but not really relevant. It was NOT necessary to allow an argumentless DEFINITION to get that effect. If empty arguments had been legal, then #define foobar(dummy) (1+1) ... dummy() would have been legal. It *is* clearly in the X3.159-1989 standard, in section 3.8.3. Is there any way you could talk ANSI into making the old superseded standard available on the web? As I noted, I've spent several hundred dollars over the years buying copies that have subsequently disappeared from my office, so I can't check this for myself. > He was talking about empty *actual parameters*, but the two are related. > There is no point in writing > #define FOO() ... > unless you mean to invoke it as > ... FOO() ... Yes! Exactly. > and the latter really was undefined behaviour caught by at least one > compiler. (A) Then that compiler was not conforming to the 1989 standard. ... (B) What C99 upgraded from a common extension to part of the standard was the possiblility of empty actual arguments. And that's where he tries to have it both ways. (A) is a statement that "the latter" (that is, an INVOCATION of a macro with an empty argument) conformed. (B) is a statement that it didn't (it used to be a "common extension", like three-argument main(), not "part of the standard"). The description is relentlessly and excessively terse, but that was one of our goals -- to be as brief as possible so as to reduce the chance of the standard being self-conflicting. Personally, I think we went overboard and made the standard much harder to read as a result. The C89 standard wasn't a bad read. In fact, compared with the C++ standard, it was an *excellent* read. (Mind you, compared with the C++ standard, what isn't?) > So it may be, but you still weren't allowed to do it in C89. Yes, you were -- at least in any conforming compiler. No, you have confirmed, in your statement (B) What C99 upgraded from a common extension to part of the standard was the possiblility of empty actual arguments. that invoking a macro with empty actual parameters was *not* required of conforming compilers. Thank you for confirming that. From jdennett at acm.org Thu Sep 7 00:19:33 2006 From: jdennett at acm.org (James Dennett) Date: Thu Sep 7 00:51:39 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609070252.k872q1Wg361916@atlas.otago.ac.nz> References: <200609070252.k872q1Wg361916@atlas.otago.ac.nz> Message-ID: <44FF9DD5.5000104@acm.org> Richard A. O'Keefe wrote: > I made two claims, one of which was wrong and one of which was right: > > (1) defining a macro with () was not defined in C89 [wrong]. > (2) invoking a macro with () was not defined in C89 [right]. > > Recall that > > Allowing an empty argument list for a function-like macro was a > > CHANGE from C89 to C99. It was proposed by Fred J. Tydeman on 1995-01-09. > > So we had the more than odd situation that apparently you were allowed > to define an argumentless function-like macro but you weren't allowed to > invoke it with no arguments. > This is the question at hand: was it a change, or was it not? > Terry Colligan , who should > speak with authority, tries to have it both ways: > > It is (and was) clearly necessary to allow macros to replace > functions, something which has been in C for a long time. > > True, but not really relevant. It was NOT necessary to allow an > argumentless DEFINITION to get that effect. If empty arguments > had been legal, then > > #define foobar(dummy) (1+1) > ... > dummy() > > would have been legal. > Was that the example you meant to use? Did you mean to attempt to use the macro foobar with no arguments (which is illegal, as the number of arguments is required to match the number of parameters)? If this is not a typo, I'm missing something, as I don't see any macro called dummy defined above. > It *is* clearly in the X3.159-1989 standard, in section 3.8.3. > > Is there any way you could talk ANSI into making the old superseded standard > available on the web? As I noted, I've spent several hundred dollars over > the years buying copies that have subsequently disappeared from my office, > so I can't check this for myself. > > > He was talking about empty *actual parameters*, but the two are related. > > There is no point in writing > > #define FOO() ... > > unless you mean to invoke it as > > ... FOO() ... > > Yes! Exactly. > > > and the latter really was undefined behaviour caught by at least one > > compiler. > > (A) Then that compiler was not conforming to the 1989 standard. > > ... > > (B) What C99 upgraded from a common extension to part of the standard was > the possiblility of empty actual arguments. > > And that's where he tries to have it both ways. > No. In C90, it was legal to have an empty list of arguments, but in C99 it is also legal to have a non-empty list of arguments, one or more of which is itself empty. (C90 does not permit an argument to be empty.) > (A) is a statement that "the latter" (that is, an INVOCATION of a macro > with an empty argument) conformed. > (B) is a statement that it didn't (it used to be a "common extension", > like three-argument main(), not "part of the standard"). > No; B refers to something else, which is the new feature in C99 of allowing #define binary(a,b) binary(2,) i.e., where there are two arguments but the second argument is empty. > The description is relentlessly and excessively terse, but that was one > of our goals -- to be as brief as possible so as to reduce the chance of > the standard being self-conflicting. Personally, I think we went overboard > and made the standard much harder to read as a result. > > The C89 standard wasn't a bad read. In fact, compared with the C++ > standard, it was an *excellent* read. (Mind you, compared with > the C++ standard, what isn't?) > There are probably other lists for language wars. I use both C and C++ as appropriate, and don't find either standard particularly more or less readable than the other. > > So it may be, but you still weren't allowed to do it in C89. > > Yes, you were -- at least in any conforming compiler. > > No, you have confirmed, in your statement > > (B) What C99 upgraded from a common extension to part of the standard was > the possiblility of empty actual arguments. > > that invoking a macro with empty actual parameters was *not* required of > conforming compilers. > > Possibly you have misread B to be a contradiction to A, instead of realizing that it must have been referring to empty arguments and not to an empty argument _list_. > Thank you for confirming that. > > I'm very confident that it was not confirmed, and reasonably confident that it is not true. -- James From jdennett at acm.org Thu Sep 7 00:05:46 2006 From: jdennett at acm.org (James Dennett) Date: Thu Sep 7 01:13:23 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <200609062338.k86Ncelh365044@atlas.otago.ac.nz> References: <200609062338.k86Ncelh365044@atlas.otago.ac.nz> Message-ID: <44FF9A9A.7040300@acm.org> Richard A. O'Keefe wrote: > I wrote: > > Note 1: having empty parentheses in a macro definition is technically > > undefined in C89. (I'm not sure, it might be illegal.) > > James Dennett queried this: > Are you sure? It's well-defined in C++98, which is almost > identical to C89/90 in terms of preprocessing. An empty > parameter name is illegal, but the case of () defines a > function-like macro with no arguments. AFAIK this is a > moderately common, strictly conforming, technique. > > Over the years I have owned three copies of the ANSI C standard > (two of them copies of the Australian edition, one of them the > infamous Herbert Schildt edition). All of them have walked out > of my office. So it's hard to check. (Now that C89 is no longer > an official standard, why isn't the standard available free over > the net?) I don't know if a PDF version has ever been created, or if the original source even exists anywhere. ISO presumably has no interest, considering it obsolete now that C99 exists. > Fortunately, WG14 have kept an archive, which you can find on > the net, and it turns out that my recollection was 100% correct. > > Allowing an empty argument list for a function-like macro was a > CHANGE from C89 to C99. It was proposed by Fred J. Tydeman on 1995-01-09. > Empty parentheses on a macro really truly were officially undefined > behaviour, and he knew of a compiler which complained. > > He was talking about empty *actual parameters*, but the two are related. > There is no point in writing > #define FOO() ... > unless you mean to invoke it as > ... FOO() ... > and the latter really was undefined behaviour caught by at least one > compiler. I'm pretty sure the definition was undefined behaviour as well. > > I'd dearly love to see C90; I've re-read C++98, which was intended to have the same preprocessing behaviour as C90 except in some simple ways, and that certainly makes it well-defined. (I implemented my preprocessor based on that specification.) > > Note 3: having empty parentheses in a macro call is technically > > undefined in C89. (I'm not sure, it might be illegal.) > > It's required to use a function-like macro with no arguments, I > believe. > > So it may be, but you still weren't allowed to do it in C89. > If so, this seems to be a case where the standard doesn't match existing practice, so it's a good thing that C99 addressed it. Maybe Michael Wojcik (who apparently has the C90 text to hand) could be kind enough to check the rules for macro replacement to confirm whether they fail to define the behaviour for an empty actual parameter list. (And for completeness: this is of course separate from the case of an empty argument (aka "actual parameter"), which was certainly not allowed in C90 or C++98, but is allowed in C99 and will almost certainly be allowed in C++0x.) -- James From ok at cs.otago.ac.nz Thu Sep 7 01:53:10 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Thu Sep 7 01:53:25 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <200609070553.k875rABs367950@atlas.otago.ac.nz> James Dennett wrote: This is the question at hand: was it a change, or was it not? The WG154 archive definitely SAYS it was. Terry Colligan also says it was. > #define foobar(dummy) (1+1) > ... > dummy() > > would have been legal. > Was that the example you meant to use? OK so there is a silly thinko: dummy() should have been foobar(). Did you mean to attempt to use the macro foobar with no arguments (which is illegal, as the number of arguments is required to match the number of parameters)? With the correct call, foobar(), you are mistaken. The number of actual parameters is *ONE*; that parameter happens to be empty. This is in no way different from #define foo(bar, ugh) bar ugh foo(,); /* two empty arguments */ foo(,zip()); /* one empty argument */ foo(zap(),); /* one empty argument */ No. In C90, it was legal to have an empty list of arguments, but in C99 it is also legal to have a non-empty list of arguments, one or more of which is itself empty. (C90 does not permit an argument to be empty.) Yes, that's what *I* said. It's PRECISELY what I said. > (A) is a statement that "the latter" (that is, an INVOCATION of a macro > with an empty argument) conformed. > (B) is a statement that it didn't (it used to be a "common extension", > like three-argument main(), not "part of the standard"). > No; B refers to something else, which is the new feature in C99 of allowing #define binary(a,b) binary(2,) i.e., where there are two arguments but the second argument is empty. Yes, that's what I *SAID* it was. Please read more carefully. There are probably other lists for language wars. I use both C and C++ as appropriate, and don't find either standard particularly more or less readable than the other. That wasn't a "language war" remark. It was a remark about the readability of the *standard*. Some parts of the C++ standard are good. But having sweated over the scope rules section for hour after hour, there is no way that you can persuade me that it is readable. Possibly you have misread B to be a contradiction to A, instead of realizing that it must have been referring to empty arguments and not to an empty argument _list_. You are making me very cross indeed. I understood PERFECTLY WELL what (B) was referring to. Please do not assume that someone who disagrees with you is an idiot. One more time: > > unless you mean to invoke it as > > ... FOO() ... > > Yes! Exactly. > > > and the latter really was undefined behaviour caught by at least one > > compiler. > > (A) Then that compiler was not conforming to the 1989 standard. Got that? At that point in the mesage, I was talking about *EMPTY ACTUAL ARGUMENTS* for macros. Look again and you will see that FOO() is not a macro definition! I said that passing empty actual arguments ("the latter") was undefined behaviour caught by a compiler, and (A) is a claim that a compiler that rejected *EMPTY ACTUAL ARGUMENTS* did not conform to the 1989 standard. > (B) What C99 upgraded from a common extension to part of the standard was > the possiblility of empty actual arguments. (B) is an explicit statement that EMPTY ACTUAL ARGUMENTS were something "upgraded" in C99, that they previously were only a "common extension", not "part of the standard". That is, (A) and (B) *are* contradictory because they are *BOTH* about EMPTY ACTUAL ARGUMENTS; *neither* of them is about macro definitions. No. In C90, it was legal to have an empty list of arguments, which is completely irrelevant to (A) and (B), neither of which is concerned with macro definitions or their formal parameters. I'm very confident that it was not confirmed, and reasonably confident that it is not true. "It" here was "C99 allows EMPTY ACTUAL ARGUMENTS in a macro call and C89 did not". That _is_ true, and Terry Colligan did confirm it. From cbfalconer at yahoo.com Thu Sep 7 00:25:06 2006 From: cbfalconer at yahoo.com (CBFalconer) Date: Thu Sep 7 08:36:14 2006 Subject: [splint-discuss] Parse Error on Macro, help References: <200609070252.k872q1Wg361916@atlas.otago.ac.nz> Message-ID: <44FF9F22.7219FE69@yahoo.com> "Richard A. O'Keefe" wrote: > ... snip ... > > Is there any way you could talk ANSI into making the old superseded standard > available on the web? As I noted, I've spent several hundred dollars over > the years buying copies that have subsequently disappeared from my office, > so I can't check this for myself. To all practical purposes they are available. The C06 draft is at: and the C99 standard (last draft) is at: The C99 standard is also available in text form as N869.txt, which is much more useful. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. From derek at knosof.co.uk Thu Sep 7 09:13:55 2006 From: derek at knosof.co.uk (derek@knosof.co.uk) Date: Thu Sep 7 09:14:03 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <44FF9F22.7219FE69@yahoo.com> Message-ID: cbfalconer@yahoo.com wrote: > > Is there any way you could talk ANSI into making the old superseded standard > > available on the web? As I noted, I've spent several hundred dollars over > > the years buying copies that have subsequently disappeared from my office, > > so I can't check this for myself. You can buy a pdf from the ANSI site for $19. > To all practical purposes they are available. The C06 draft is at: > > See http://c0x.coding-guidelines.com for a Google searchable version of the latest draft. > > and the C99 standard (last draft) is at: > > There are a lot of minor differences between this and the published document. > The C99 standard is also available in text form as N869.txt, which > is much more useful. This is not the C99 Standard. From Michael.Wojcik at MicroFocus.com Thu Sep 7 10:26:02 2006 From: Michael.Wojcik at MicroFocus.com (Michael Wojcik) Date: Thu Sep 7 10:27:58 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <11352F9641010A418AD5057945A3A6594CC0BF@MTV-EXCHANGE.microfocus.com> > From: splint-discuss-bounces@cs.virginia.edu > [mailto:splint-discuss-bounces@cs.virginia.edu] On Behalf Of > derek@knosof.co.uk > Sent: Thursday, 07 September, 2006 09:14 > > cbfalconer@yahoo.com wrote: > > [Richard A. O'Keefe wrote:] > > > Is there any way you could talk ANSI into making the old > superseded standard > > > available on the web? As I noted, I've spent several > hundred dollars over > > > the years buying copies that have subsequently > disappeared from my office, > > > so I can't check this for myself. > > You can buy a pdf from the ANSI site for $19. Not of "the old superseded standard", which is what Richard asked for. > > To all practical purposes they are available. The C06 draft ... is not "the old superseded standard". > > and the C99 standard (last draft) ... is not "the old superseded standard". The topic of obtaining the C90 standard comes up periodically on comp.lang.c. AFAIR, the last time I read such a discussion, there were still some national standards bodies that were selling it (or, at any rate, their nationally-branded versions of C90 plus some or all of COR1, AMD1, and COR2) - Australia's was one, I think. Some company was supposedly selling it on CD-ROM. And used versions of the Schildt book are sometimes available - though it's bloated by Schildt's infamous commentary, and it's missing one page of the standard due to a printing error (and it's a particularly useful bit, part of the fprintf spec). > > is at: > > > > > > There are a lot of minor differences between this and the published > document. On the other hand, n1124.pdf is quite close to the published document, and also incorporates TC1 and TC2. I have the C99 published standard, but I generally refer to n1124. -- Michael Wojcik Principal Software Systems Developer Micro Focus michael.wojcik@microfocus.com 9420 Key West Avenue Rockville, MD 20850 Direct: 517 676 0892 What would you like Micro Focus to do for you? Contribute your view by visiting http://www.microfocus.com/CustomerInsight.asp From Michael.Wojcik at MicroFocus.com Thu Sep 7 10:26:04 2006 From: Michael.Wojcik at MicroFocus.com (Michael Wojcik) Date: Thu Sep 7 10:28:00 2006 Subject: [splint-discuss] Parse Error on Macro, help Message-ID: <11352F9641010A418AD5057945A3A6594CC0C0@MTV-EXCHANGE.microfocus.com> > From: splint-discuss-bounces@cs.virginia.edu > [mailto:splint-discuss-bounces@cs.virginia.edu] On Behalf Of > James Dennett > Sent: Thursday, 07 September, 2006 00:06 > > Richard A. O'Keefe wrote: > > I wrote: > > > Note 1: having empty parentheses in a macro definition is technically > > > undefined in C89. (I'm not sure, it might be illegal.) And *this* is wrong, per 9899-1990 6.8.3, as discussed earlier; and Richard noted in a subsequent email that it was wrong. Empty parentheses [in the parameter list, ie an empty identifier-list] in a macro *definition* is allowed in C89/C90. > > He was talking about empty *actual parameters*, but the two are related. > > There is no point in writing > > #define FOO() ... > > unless you mean to invoke it as > > ... FOO() ... > > and the latter really was undefined behaviour caught by at least one > > compiler. But *this* is arguably correct. 9899-1990 6.8.3 goes on to say, "If (before argument substitution) any argument consists of no preprocessing tokens, the behavior is undefined". Clearly allowing an empty parameter list in the definition, but disallowing an empty parameter list when invoking such a function-like macro, doesn't make much sense. However, if an implementor interpreted "any argument" above as including the case of a function-like macro with an empty parameter list, then it's UB and the implementation could refuse to translate the TU. I'd be reluctant, personally, to defend such an interpretation, but the C90 standard does seem to be ambiguous here and I can see why Tydeman's DR was useful. > Maybe Michael Wojcik (who apparently has the C90 text to hand) could be > kind enough to check the rules for macro replacement to confirm whether > they fail to define the behaviour for an empty actual parameter list. The passage I quoted above seems to be the relevant bit, and IMO the whole thing hangs on the interpretation of the phrase "any argument" in it. Rather than argue over that, though, I suggest we accept the fact that the issue was sufficiently in doubt for Tydeman to propose a DR and the committee to accept it; and so sufficiently in doubt that otherwise-conforming implementations might mistake the intent of the standard if it did indeed intend to allow an empty argument list for a function-like macro with an empty parameter list. (The only other mention of UB in function-like macro replacement is if the sequence of pp-tokens in the argument list includes sequences that would otherwise act as preprocessing directives, which clearly doesn't apply in this case.) -- Michael Wojcik Principal Software Systems Developer Micro Focus michael.wojcik@microfocus.com 9420 Key West Avenue Rockville, MD 20850 Direct: 517 676 0892 What would you like Micro Focus to do for you? Contribute your view by visiting http://www.microfocus.com/CustomerInsight.asp From jdennett at acm.org Thu Sep 7 10:15:47 2006 From: jdennett at acm.org (James Dennett) Date: Thu Sep 7 11:40:14 2006 Subject: Empty arguments/empty argument lists [Was: Re: [splint-discuss] Parse Error on Macro, help] In-Reply-To: <200609070553.k875rABs367950@atlas.otago.ac.nz> References: <200609070553.k875rABs367950@atlas.otago.ac.nz> Message-ID: <45002993.30605@acm.org> Richard A. O'Keefe wrote: > James Dennett wrote: > This is the question at hand: was it a change, or was it not? > > The WG154 archive definitely SAYS it was. > Terry Colligan > also says it was. > > > #define foobar(dummy) (1+1) > > ... > > dummy() > > > > would have been legal. > > > Was that the example you meant to use? > > OK so there is a silly thinko: dummy() should have been foobar(). > Fair enough. As I said, that would fall foul of a different rule, the rule that the number of macro arguments must match the number of macro parameters. So I don't think it illustrates your point -- except that you appear to claim that this use of the macro foobar has a single (empty) argument. That seems to be the key of this issue. Those who believe (based on a reading and understanding of the standard(s)) that there are no arguments, and those who believe (based on their reading and understanding of the standard(s)) that there is a single, empty argument. > Did you mean to attempt to use the macro foobar with no > arguments (which is illegal, as the number of arguments is > required to match the number of parameters)? > > With the correct call, foobar(), you are mistaken. > The number of actual parameters is *ONE*; that parameter happens > to be empty. As I say -- that is key to this. I can't find text in C++98 that says this, but some compilers I have here appear to agree with you. (I have one C++ compiler here from Sun that considers this an issue "Warning: Too few arguments in macro foo".) To be clear: I'm testing the compilers/preprocessors with #define foobar(a) int main() { foobar(); return 0; } > This is in no way different from > > #define foo(bar, ugh) bar ugh > > foo(,); /* two empty arguments */ > foo(,zip()); /* one empty argument */ > foo(zap(),); /* one empty argument */ > > It is different in one crucial way: the complete absence of an argument list. Unfortunately I do not find in any of the documents I have here a formal specification for handling of this case. In the analagous case of a function call, fn() has no arguments. Of course it's true that argument by analogy is weak. > No. In C90, it was legal to have an empty list of arguments, > but in C99 it is also legal to have a non-empty list of > arguments, one or more of which is itself empty. (C90 does not > permit an argument to be empty.) > > Yes, that's what *I* said. > It's PRECISELY what I said. > Except for one crucial point, which is that you were not clear that you considered that foobar() does not have an empty list of arguments, but rather a list of one argument which is itself empty. > > (A) is a statement that "the latter" (that is, an INVOCATION of a macro > > with an empty argument) conformed. > > (B) is a statement that it didn't (it used to be a "common extension", > > like three-argument main(), not "part of the standard"). > > > No; B refers to something else, which is the new feature in C99 of allowing > #define binary(a,b) > binary(2,) > i.e., where there are two arguments but the second argument is empty. > > Yes, that's what I *SAID* it was. > Please read more carefully. > I can't find that in your previous words; your new wording is clearer, thank you. > There are probably other lists for language wars. I use both C > and C++ as appropriate, and don't find either standard > particularly more or less readable than the other. > > That wasn't a "language war" remark. It was a remark about the > readability of the *standard*. Some parts of the C++ standard are good. > But having sweated over the scope rules section for hour after hour, > there is no way that you can persuade me that it is readable. > The name lookup rules themselves are amazingly complicated, sad to say. > Possibly you have misread B to be a contradiction to A, instead of > realizing that it must have been referring to empty arguments and not to > an empty argument _list_. > > You are making me very cross indeed. > Unfortunate; I'm attempting to engage in a civil discussion. Please note that I only said that it was _possible_. (Also note the point I've made -- probably too often -- elsewhere in this post, that distinguishing the two cases #args=0 and arg[n]="" is vital.) > I understood PERFECTLY WELL what (B) was referring to. > I hope that with my clarifications you will feel that "shouting" is no longer required. > Please do not assume that someone who disagrees with you is an idiot. > > Trust me, I don't. In turn, please don't assume ill will where none is meant; discussions will go better that way. > One more time: > > > unless you mean to invoke it as > > > ... FOO() ... > > > > Yes! Exactly. > > > > > and the latter really was undefined behaviour caught by at least one > > > compiler. > > > > (A) Then that compiler was not conforming to the 1989 standard. > > Got that? > If I re-add the context, he was saying that a compiler that refused to translate a use FOO() of a function-like macro with no parameters was non-conforming with the C89 standard. Do you agree with this description? > At that point in the mesage, I was talking about *EMPTY ACTUAL ARGUMENTS* > for macros. Look again and you will see that FOO() is not a macro definition! > I did read it that way all along, and was also discussing that case. > I said that passing empty actual arguments ("the latter") was undefined > behaviour caught by a compiler, and (A) is a claim that a compiler that > rejected *EMPTY ACTUAL ARGUMENTS* did not conform to the 1989 standard. > > A is a claim that a compiler that rejected a use (with no arguments) of a function-like macro (with no parameters) did not conform. > > (B) What C99 upgraded from a common extension to part of the standard was > > the possiblility of empty actual arguments. > > (B) is an explicit statement that EMPTY ACTUAL ARGUMENTS were something > "upgraded" in C99, that they previously were only a "common extension", > not "part of the standard". > > That is, (A) and (B) *are* contradictory because they are *BOTH* > about EMPTY ACTUAL ARGUMENTS; *neither* of them is about macro definitions. > > I believe (A) was intended to be about an empty argument list, while (B) is about a non-empty argument list including one or more empty arguments. Maybe the OP would like to step in, as his interpretation of the statement must surely have some authority. > No. In C90, it was legal to have an empty list of arguments, > > which is completely irrelevant to (A) and (B), neither of which is > concerned with macro definitions or their formal parameters. > It's entirely relevant: "arguments" applies in the context of a use of a macro, and it is in this context I was using it. To expand: it was a claim that, in C90, it was legal to invoke a function-like macro (that has been defined with no parameters) with no (actual) arguments. (An unqualified use of the term "arguments" is most commonly -- in my experience -- taken to mean "actual arguments", whereas the terse way to say "formal arguments" is "parameters".) > I'm very confident that it was not confirmed, and reasonably confident > that it is not true. > > "It" here was "C99 allows EMPTY ACTUAL ARGUMENTS in a macro call and C89 > did not". That _is_ true, and Terry Colligan did confirm it. > Your use of the term "empty actual arguments" is unfortunate in failing to distinguish between the two key cases here. However: I'm leaning towards thinking that your interpretation is more probably correct than not for C99 and C++0x. (That said, I've not yet found wording there which makes it clear that foo() has one (actual) argument. If C90 doesn't specify, then the use foo() would still be undefined simply because of the lack of such a definition.) Given that we both assume someone disagreeing with us can still be intelligent, it's fair to assume that Terry probably did *not* intend to say anything self-contradictory, so it would be great if he would step in and clarify his meaning. This subject matter is non-trivial, and the terminology less than optimal; there's room for intelligent people to disagree, and even to make mistakes. Given that this discussion is interesting (in particular: I've seen behaviour from compilers that doesn't match my expectations, which is none too common), I hope we can iron out the remaining details (though at this point I might take it to comp.std.c and/or comp.std.c++ in any case). -- James From jdennett at acm.org Thu Sep 7 10:35:25 2006 From: jdennett at acm.org (James Dennett) Date: Thu Sep 7 11:40:15 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: <44FF9F22.7219FE69@yahoo.com> References: <200609070252.k872q1Wg361916@atlas.otago.ac.nz> <44FF9F22.7219FE69@yahoo.com> Message-ID: <45002E2D.4010007@acm.org> CBFalconer wrote: > "Richard A. O'Keefe" wrote: > > ... snip ... > >> Is there any way you could talk ANSI into making the old superseded standard >> available on the web? As I noted, I've spent several hundred dollars over >> the years buying copies that have subsequently disappeared from my office, >> so I can't check this for myself. >> > > To all practical purposes they are available. Not really. > The C06 draft is at: > > > > and the C99 standard (last draft) is at: > > > > The C99 standard is also available in text form as N869.txt, which > is much more useful. > All of these are much too different from C89/C90 for those who want to know what C89/C90 said -- such as those with an interest in the history of C, those who find that most of their implementations still don't make much of an attempt to conform to C99, or those who rely on C++98, which incorporates much of C90 by reference. Splint is a tool for checking C90, so users of this list might care about the definition of the language splint checks. Reading about C99 won't tell them that -- witness the number of questions about splint not accepting the C99 code int main(void) { (void)0; int a; return 0; } because the declaration of a is not valid in C90. -- James From jdennett at acm.org Thu Sep 7 10:22:23 2006 From: jdennett at acm.org (James Dennett) Date: Thu Sep 7 11:51:41 2006 Subject: [splint-discuss] Parse Error on Macro, help In-Reply-To: References: Message-ID: <45002B1F.8030603@acm.org> derek@knosof.co.uk wrote: > cbfalconer@yahoo.com wrote: > >>> Is there any way you could talk ANSI into making the old superseded standard >>> available on the web? As I noted, I've spent several hundred dollars over >>> the years buying copies that have subsequently disappeared from my office, >>> so I can't check this for myself. >>> > > You can buy a pdf from the ANSI site for $19. > A copy of C90? Do you have a link, or a description of how to do so? C99 now costs $30 from ANSI, but my search of the ANSI web store doesn't find C90. -- James From elfring at users.sourceforge.net Sun Sep 10 16:09:44 2006 From: elfring at users.sourceforge.net (SF Markus Elfring) Date: Sun Sep 10 16:30:17 2006 Subject: [splint-discuss] Parse Error on "pthread.h" from Cygwin Message-ID: <45047108.2030407@users.sourceforge.net> Hello, I would like to try static code analysis on the software "http://www.apsis.ch/pound/" with your tool. $ /cygdrive/e/Programme/splint-3.1.1/bin/splint -warnposix +trytorecover -I/usr/include /cygdrive/e/Projekte/Pound/2.1/pound.c Splint 3.1.1 --- 08 Sep 2006 /usr/include/pthread.h:79:56: Parse Error. Too many errors, giving up. *** Cannot continue. I am surprised that the error message points to a comma that is a delimiter for a function parameter in this line from the header file. Are any special configuration settings (https://sourceforge.net/tracker/index.php?func=detail&aid=1281594&group_id=34302&atid=459914) useful to resolve this issue? I would like to see a better readable hint about the detail that the parser does not like or does not understand. Regards, Markus From ok at cs.otago.ac.nz Sun Sep 10 22:33:37 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Sun Sep 10 23:09:41 2006 Subject: [splint-discuss] Parse Error on "pthread.h" from Cygwin Message-ID: <200609110233.k8B2XbnO390413@atlas.otago.ac.nz> SF Markus Elfring wrote: I would like to try static code analysis on the software "http://www.apsis.ch/pound/" with your tool. $ /cygdrive/e/Programme/splint-3.1.1/bin/splint -warnposix +trytorecover -I/usr/include /cygdrive/e/Projekte/Pound/2.1/pound.c Splint 3.1.1 --- 08 Sep 2006 /usr/include/pthread.h:79:56: Parse Error. Too many errors, giving up. *** Cannot continue. I am surprised that the error message points to a comma that is a delimiter for a function parameter in this line from the header file. Why the surprise? Presumably the parse error is in the argument just preceding that token. On the Linux box I sometimes use, /usr/include/pthread.h line 79 is PTHREAD_PRIO_INHERIT, which doesn't have a column 56. Perhaps you could show us the entire declaration where the problem is. A good strategy is to check whether identifiers are declared. Are any special configuration settings (https://sourceforge.net/tracker/index.php?func=detail&aid=1281594&group_id=34302&atid=459914) useful to resolve this issue? Yes. Remember that Splint checks for conformance to standards; it knows what *should* be in standard headers (C89 by default; add POSIX headers with +posixlib) so doesn't need to actually read the system headers. I would like to see a better readable hint about the detail that the parser does not like or does not understand. The parser does not like and does not understand NON-STANDARD constructions (where the standard is ANSI C89/ISO C90). Everything else it understands. GNUisms are a problem, but the usual cause of this kind of problem seems to be identifiers that you think are declared but splint thinks aren't because they are system-specific stuff in standard headers. From gregory.descamps at awtce.be Mon Sep 11 12:17:12 2006 From: gregory.descamps at awtce.be (gregory.descamps@awtce.be) Date: Mon Sep 11 12:32:53 2006 Subject: [splint-discuss] Gregory Descamps is out of the office Message-ID: I will be out of the office starting 2006/09/08 and will not return until 2006/09/18. I will respond to your message when I return. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.cs.Virginia.EDU/pipermail/splint-discuss/attachments/20060911/4741641b/attachment.htm From felipe.contreras at gmail.com Thu Sep 14 23:49:07 2006 From: felipe.contreras at gmail.com (Felipe Contreras) Date: Fri Sep 15 00:18:12 2006 Subject: [splint-discuss] Annoying False Positives Message-ID: <94a0d4530609142049p35029897s6bdc102f3a0fbc17@mail.gmail.com> I have stumbled upon a lot of false positive errors with splint. Here is the one that bothers me the most (attached). Am I doing something wrong? If not, can you fix this error? Cheers. -- Felipe Contreras -------------- next part -------------- A non-text attachment was scrubbed... Name: test.c Type: text/x-csrc Size: 636 bytes Desc: not available Url : http://www.cs.Virginia.EDU/pipermail/splint-discuss/attachments/20060914/8754696c/test.bin From ptp at lysator.liu.se Fri Sep 15 07:54:09 2006 From: ptp at lysator.liu.se (Tommy Pettersson) Date: Fri Sep 15 08:13:36 2006 Subject: [splint-discuss] Annoying False Positives In-Reply-To: <94a0d4530609142049p35029897s6bdc102f3a0fbc17@mail.gmail.com> References: <94a0d4530609142049p35029897s6bdc102f3a0fbc17@mail.gmail.com> Message-ID: <20060915115409.GA11592@static-81.216.50.98.addr.tdcsong.se> On Thu, Sep 14, 2006 at 10:49:07PM -0500, Felipe Contreras wrote: > I have stumbled upon a lot of false positive errors with splint. > > Here is the one that bothers me the most (attached). > > Am I doing something wrong? You did not say with what options you are running splint, but here's the output I get from splint with no extra options: Splint 3.1.1 --- 20 Jul 2006 f.c: (in function my_test_new) f.c:23: Only storage test->data (type void *) not released before assignment: test->data = malloc(100) A memory leak has been detected. Only-qualified storage is not released before the last reference to it is lost. (Use -mustfreeonly to inhibit warning) f.c:25: Returned storage *test contains 1 undefined field: data Storage derivable from a parameter, return value or global is not defined. Use /*@out@*/ to denote passed or returned storage which need not be defined. (Use -compdef to inhibit warning) Finished checking --- 2 code warnings The first warning is annoying, I agree, but as most of the time, splint is buggingly correct. The call to memset gives test->data a value of all zero bits. What that value means is architecture dependent and not guaranteed to be a NULL pointer. This means among other things that tests like "if (!test->data)" are equally undefined until the pointer gets a proper value. Your code give test->data a proper value right away, and it's obvious from looking at the code that it always works as expected. But splint does not "understand" code and can of course not see that. I don't know if maybe splint should be extended to keep track of values with undefined behavior. It is clearly wrong to free a pointer after setting its value with memset, but the code memset (test, 0, sizeof (test)); free (test->data); does NOT produce a warning from splint! (even in strict mode.) After a memset (foo, 0, ...) you can put lines like: /*@-mustfreeonly@*/ foo->ptr1 = 0; foo->ptr2 = init2; .. /*@=mustfreeonly@*/ The second warning you get is also correct. me_test_new does (possibly) return reachable undefined storage. The returned pointer points to a struct with a pointer to newly malloced but not initialized memory, and it would be wrong to read that memory. Splint does much of its checking per function, and in this case you need to put a partial annotation on the functions return value, so splint can generate correct warnings for functions that call me_test_new. /*@null@*/ /*@partial@*/ static MyTest * my_test_new (void) { ... There are also more advanced special annotations to specify in detail what fields of a struct get allocated, freed, initialized and so on by a function. -- Tommy Pettersson From felipe.contreras at gmail.com Fri Sep 15 12:10:11 2006 From: felipe.contreras at gmail.com (Felipe Contreras) Date: Fri Sep 15 12:53:59 2006 Subject: [splint-discuss] Annoying False Positives In-Reply-To: <20060915115409.GA11592@static-81.216.50.98.addr.tdcsong.se> References: <94a0d4530609142049p35029897s6bdc102f3a0fbc17@mail.gmail.com> <20060915115409.GA11592@static-81.216.50.98.addr.tdcsong.se> Message-ID: <94a0d4530609150910u7f11296cvc2b9ccc09323d7d2@mail.gmail.com> On 9/15/06, Tommy Pettersson wrote: > On Thu, Sep 14, 2006 at 10:49:07PM -0500, Felipe Contreras wrote: > > I have stumbled upon a lot of false positive errors with splint. > > > > Here is the one that bothers me the most (attached). > > > > Am I doing something wrong? > > You did not say with what options you are running splint, but > here's the output I get from splint with no extra options: Well, I'm using splint to get the most warnings I can, so I'm not specifying any extra options. My objective is to get zero warnings so I can feel my code is better. > Splint 3.1.1 --- 20 Jul 2006 > > f.c: (in function my_test_new) > f.c:23: Only storage test->data (type void *) not released before assignment: > test->data = malloc(100) > A memory leak has been detected. Only-qualified storage is not released > before the last reference to it is lost. (Use -mustfreeonly to inhibit > warning) > f.c:25: Returned storage *test contains 1 undefined field: data > Storage derivable from a parameter, return value or global is not defined. > Use /*@out@*/ to denote passed or returned storage which need not be defined. > (Use -compdef to inhibit warning) > > Finished checking --- 2 code warnings > > > The first warning is annoying, I agree, but as most of the time, > splint is buggingly correct. The call to memset gives test->data > a value of all zero bits. What that value means is architecture > dependent and not guaranteed to be a NULL pointer. This means > among other things that tests like "if (!test->data)" are > equally undefined until the pointer gets a proper value. Your > code give test->data a proper value right away, and it's obvious > from looking at the code that it always works as expected. But > splint does not "understand" code and can of course not see > that. If I try with calloc, or manually set test->data = NULL; I get the same warning. > I don't know if maybe splint should be extended to keep track of > values with undefined behavior. It is clearly wrong to free a > pointer after setting its value with memset, but the code > > memset (test, 0, sizeof (test)); > free (test->data); > > does NOT produce a warning from splint! (even in strict mode.) I agree. > After a memset (foo, 0, ...) you can put lines like: > > /*@-mustfreeonly@*/ > foo->ptr1 = 0; > foo->ptr2 = init2; > .. > /*@=mustfreeonly@*/ Yeah, I could, but my code is already ugly with all the splint comments. > The second warning you get is also correct. me_test_new does > (possibly) return reachable undefined storage. The returned > pointer points to a struct with a pointer to newly malloced but > not initialized memory, and it would be wrong to read that > memory. Splint does much of its checking per function, and in > this case you need to put a partial annotation on the functions > return value, so splint can generate correct warnings for > functions that call me_test_new. > > /*@null@*/ /*@partial@*/ static MyTest * my_test_new (void) { ... > > There are also more advanced special annotations to specify in > detail what fields of a struct get allocated, freed, initialized > and so on by a function. I see, but what if I consider malloc'ed memory initialized? Somebody else is going to use that buffer memory and write stuff to it. I guess the best thing to do is to declare @partial@ data, in fact that fixed all the warnings. :) Thanks a lot. -- Felipe Contreras From elfring at users.sourceforge.net Fri Sep 15 16:03:47 2006 From: elfring at users.sourceforge.net (SF Markus Elfring) Date: Fri Sep 15 16:02:50 2006 Subject: [splint-discuss] Splint for C++ References: FE009ERM88i19jX3TZH000487c6@Mx1.Myoutlookonline.com Message-ID: <450B0723.40003@users.sourceforge.net> > I wanted to know whether there is a variant of Splint for C++. The approach "http://splintpp.sourceforge.net/" does not seem to make progress. Would you like to look at the article "http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis" for alternatives? Are introspection tools like "http://synopsis.fresco.org/" enough for your needs? Regards, Markus From ptp at lysator.liu.se Fri Sep 15 17:46:21 2006 From: ptp at lysator.liu.se (Tommy Pettersson) Date: Fri Sep 15 17:46:35 2006 Subject: [splint-discuss] Annoying False Positives In-Reply-To: <94a0d4530609150910u7f11296cvc2b9ccc09323d7d2@mail.gmail.com> References: <94a0d4530609142049p35029897s6bdc102f3a0fbc17@mail.gmail.com> <20060915115409.GA11592@static-81.216.50.98.addr.tdcsong.se> <94a0d4530609150910u7f11296cvc2b9ccc09323d7d2@mail.gmail.com> Message-ID: <20060915214621.GA6024@static-81.216.50.98.addr.tdcsong.se> On Fri, Sep 15, 2006 at 11:10:11AM -0500, Felipe Contreras wrote: > Well, I'm using splint to get the most warnings I can, so I'm not > specifying any extra options. My objective is to get zero warnings so > I can feel my code is better. Most of the checks are off by default. "splint -strict" turns on almost all warnings; there are some warnings about index bounds that have to be explicitly turned on. But it would not be possible to write a "real" program that has zero splint warnings. The objective should be to write clear and simple code that is easy to understand. If splint doesn't understand it, splint should be shut up or ignored, the code should not be mutilated! > If I try with calloc, or manually set test->data = NULL; I get the same > warning. calloc does, just like memset(ptr, 0, ...), fill the memory with a zero bit pattern. So they both assign the pointer with a value that is not known to be NULL, whereas "ptr = 0;" assigns the pointer a value that is known to be NULL (but might have the bit pattern 0x0004 or whatever, although it is usually 0x0). The following code: test = malloc (sizeof (test)) test->data = 0; test->data = malloc (... does therefore not give the mustfreeonly warning (at least not on my computer). > >After a memset (foo, 0, ...) you can put lines like: > > > > /*@-mustfreeonly@*/ > > foo->ptr1 = 0; > > foo->ptr2 = init2; > > .. > > /*@=mustfreeonly@*/ > > Yeah, I could, but my code is already ugly with all the splint comments. Most of the time annotations like /*@-mustfreeonly@*/ serve as informative comments for the reader of the code. It says it's ok to not free the pointer before giving it a new value in this special case. Good to know if you want to make changes to the code. > > /*@null@*/ /*@partial@*/ static MyTest * my_test_new (void) { ... > > > >There are also more advanced special annotations to specify in > >detail what fields of a struct get allocated, freed, initialized > >and so on by a function. > > I see, but what if I consider malloc'ed memory initialized? Somebody > else is going to use that buffer memory and write stuff to it. So, the my_test_new function _allocates_ the memory, and the function that write stuff to it _initializes_ it. In between the memory is uninitialized. It is wrong for the writing function (that receive uninitialized memory) to read from that memory before writing to it (unless it wants poor random data). How does splint know to check for this? It doesn't, unless it knows the memory in uninitialized. By annotating this fact you get more checks that the returned value from my_test_new is used correctly. Before you added that annotation splint could not detect such errors, but it _did_ detect my_test_new returned uninitialized memory without saying so. -- Tommy Pettersson From elfring at users.sourceforge.net Sun Sep 17 11:34:22 2006 From: elfring at users.sourceforge.net (SF Markus Elfring) Date: Sun Sep 17 12:03:00 2006 Subject: [splint-discuss] Parse Error on "pthread.h" from Cygwin In-Reply-To: <200609110233.k8B2XbnO390413@atlas.otago.ac.nz> References: <200609110233.k8B2XbnO390413@atlas.otago.ac.nz> Message-ID: <450D6AFE.50309@users.sourceforge.net> No difference ... $ /cygdrive/e/Programme/splint-3.1.1/bin/splint -warnposix +posixlib +trytorecover -I/usr/include -I. /cygdrive/e/Projekte/Pound/2.1/pound.c Splint 3.1.1 --- 08 Sep 2006 /usr/include/pthread.h:79:56: Parse Error. Too many errors, giving up. *** Cannot continue. > Why the surprise? Presumably the parse error is in the argument > just preceding that token. > > On the Linux box I sometimes use, /usr/include/pthread.h line 79 is > PTHREAD_PRIO_INHERIT, > which doesn't have a column 56. Perhaps you could show us the entire > declaration where the problem is. > The header files are different between those operating systems and environments. > The parser does not like and does not understand NON-STANDARD constructions > (where the standard is ANSI C89/ISO C90). Everything else it understands. > Is this interface too new for the check? /*line 79:*/ int pthread_attr_getschedpolicy (const pthread_attr_t *, int *); http://opengroup.org/onlinepubs/000095399/functions/pthread_attr_getschedpolicy.html Does any developer/maintainer care that the analysis tool will achieve conformance to current standards? How are the chances that limitations will be lifted? Regards, Markus From ok at cs.otago.ac.nz Sun Sep 17 18:42:28 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Sun Sep 17 18:53:34 2006 Subject: [splint-discuss] Annoying False Positives Message-ID: <200609172242.k8HMgSdi440209@atlas.otago.ac.nz> "Felipe Contreras" asked: I have stumbled upon a lot of false positive errors with splint. Here is the one that bothers me the most (attached). When I run that through splint it reports two errors. Neither of them is a false positive. home/users/okeefe_r/quasar/sp-test.c:22:2: Only storage test->data (type void *) not released before assignment: test->data = malloc(100) A memory leak has been detected. Only-qualified storage is not released before the last reference to it is lost. (Use -mustfreeonly to inhibit warning) That doesn't refer to, but is caused by the call to memset(). /*@null@*/ static MyTest * my_test_new(void) { MyTest *test; test = (MyTest *) malloc (sizeof (MyTest)); if (!test) { return NULL; } >>> memset (test, 0, sizeof (MyTest)) test->data = malloc (100); return test; } splint is a checker for the ANSI C89/ISO C90 language. That language gives us ***NO*** reason to believe that a word with all bytes 0 is a null pointer, and in fact there have been C implementations where the null pointer WASN'T all bytes 0. Using memset to initialise a struct is in general such a daft idea that splint really ought to complain about this on general principles. The cleanest and simplest way I know to initialise a struct to something sane is just static MyTest const zero_test; and then test = zero_test; Yes, I know that null pointer constants in C are *spelled* 0 in the *source* code, but that has no implications whatever for what the bytes will be in memory. Anyway, here splint sees a struct variable that is initialised to who knows what. *It* certainly doesn't know what the variable is initialised to (and if it did figure out that all bytes were being set to zero, it has as pointed out above NO reason to believe that all bytes zero is NOT a valid pointer to some object). Simply remove that line and that message goes away. The second message is this: home/users/okeefe_r/quasar/sp-test.c:24:9: Returned storage *test contains 1 undefined field: data Storage derivable from a parameter, return value or global is not defined. Use /*@out@*/ to denote passed or returned storage which need not be defined. (Use -compdef to inhibit warning) I believe this is referring to the fact that while test is defined, and, if test is not null, test->data is defined, if test->data is not null, then the contents of test->data are NOT defined. By the way, it is bad style to test pointers using "!". Rewrite the function like this: /*@null@*/ static MyTest * my_test_new(void) { MyTest *test = malloc(sizeof *test); size_t const n = 100; if (test == NULL) return test; test->data = malloc(n); if (test->data == NULL) return test; memset(test->data, 0, n); return test; } Hmm. While rewriting like that is a good idea, it still doesn't make the report go away. Think think. Ah! Why do you ever want to return a non-NULL pointer to a record containing a NULL data pointer? I mean, the data pointer gets to be NULL only if you just ran out of memory; what are the odds that you will be able to do much of _anything_ else afterwards? If you change the specification of the function to my_test() either returns a pointer to a MyTest record containing a pointer to a zeroed block of 100 bytes, or returns NULL, indicating that memory ran out. /*@null@*/ static MyTest * my_test_new(void) { MyTest *test = malloc(sizeof *test); size_t const n = 100; if (test == NULL) return NULL; test->data = malloc(n); if (test->data == NULL) { free(test); return NULL; } memset(test->data, 0, n); return test; } With that definition, there are no more complaints from splint. From ok at cs.otago.ac.nz Sun Sep 17 19:22:01 2006 From: ok at cs.otago.ac.nz (Richard A. O'Keefe) Date: Sun Sep 17 19:22:13 2006 Subject: [splint-discuss] Parse Error on "pthread.h" from Cygwin Message-ID: <200609172322.k8HNM1mC441669@atlas.otago.ac.nz> I wrote: > On the Linux box I sometimes use, /usr/include/pthread.h line 79 is > PTHREAD_PRIO_INHERIT, > which doesn't have a column 56. Perhaps you could show us the entire > declaration where the problem is. SF Markus Elfring replied The header files are different between those operating systems and environments. which was EXACTLY my point; problem reports concerning system header files are completely useless without extracting the relevant parts. I also wrote: > The parser does not like and does not understand NON-STANDARD constructions > (where the standard is ANSI C89/ISO C90). Everything else it understands. because GCC-isms are a common cause of problems with system headers. Is this interface too new for the check? /*line 79:*/ v int pthread_attr_getschedpolicy (const pthread_attr_t *, int *); ^ If that's where the problem is, that suggests to me that pthread_attr_t has not been declared. Does any developer/maintainer care that the analysis tool will achieve conformance to current standards? I'm not one of the developers nor yet a maintainer of splint. I would very much like C99 support, but (a) none of the compilers available to me on any of my machines claims full conformance to C99, so I can wait another year. (b) many of the changes are library additions, and I can handle most of that myself by patching splint's view of the libraries on an ad hoc basis. It would be better not to have to, of course. From elfring at users.sourceforge.net Mon Sep 18 08:04:46 2006 From: elfring at users.sourceforge.net (SF Markus Elfring) Date: Mon Sep 18 08:28:56 2006 Subject: [splint-discuss] Parse Error on "pthread.h" from Cygwin In-Reply-To: <200609172322.k8HNM1mC441669@atlas.otago.ac.nz> References: <200609172322.k8HNM1mC441669@atlas.otago.ac.nz> Message-ID: <450E8B5E.3070506@users.sourceforge.net> > v > int pthread_attr_getschedpolicy (const pthread_attr_t *, int *); > ^ > If that's where the problem is, that suggests to me that > pthread_attr_t has not been declared. > I would appreciate if the parser would explicitly say so in the error message. The required data structure should be specified by the header file "sys/types.h". The addition of the parameter "-D_POSIX_THREADS" or "-D__CYGWIN__" results into an "obstacle" two lines later. /usr/include/pthread.h:81:56: int pthread_attr_getschedpolicy (const pthread_attr_t *, int *); It seems to be hard to collect all preprocessor symbols and other configuration options to get this tool to work as expected. > (b) many of the changes are library additions, and I can handle most > of that myself by patching splint's view of the libraries on an > ad hoc basis. It would be better not to have to, of course. > Do you know a clean overview of all required "tweaks" besides "http://splint.org/manual/"? Were answers from the mailing list be used to publish an other presentation? Regards, Markus From wenzel at bbr-vt.de Tue Sep 19 06:13:52 2006 From: wenzel at bbr-vt.de (Wenzel, Bodo) Date: Tue Sep 19 06:43:22 2006 Subject: [splint-discuss] How to use bounds checks? Message-ID: <450FDEFF.16634.F7ECA0@wenzel.bbr-vt.de> Hi. Starting a new project we thought that using Splint would be a good idea. But we ran into problems, especially with bounds checks. The source code (with a silly example) below contains comments that describe our difficulties, any help is welcome! Oh, and sorry for the long posting. Splint (Win32 version 3.1.1) is called with: ============================================ +checks +partial +bounds -export-header Source code: ============ int no_sub_no_error(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 9@*/ ; int no_sub_no_error(const int *pointer) { int array[12]; int pointer_index, array_index; int sum; pointer_index = 0; for (array_index = 0; array_index < 10; array_index++) { array[array_index + 0] = pointer[pointer_index++]; array[array_index + 1] = 0; array[array_index + 2] = 0; } #if defined(S_SPLINT_S) /* Apparently Splint doesn't remember which cells were written * just above. */ array_index = 10 - 1; /* set loop maximum */ array[11] = 0; /* set maxRead(array) */ #endif sum = 0; for (array_index = 0; array_index < 10; array_index++) { sum += array[array_index + 0] * array[array_index + 1] * array[array_index + 2]; } return sum; } /*----------------------------------------------------------------*/ int no_sub_error_caught(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 10@*/ ; int no_sub_error_caught(const int *pointer) { int array[12]; int pointer_index, array_index; int sum; pointer_index = 0; for (array_index = 0; array_index < 11; array_index++) { array[array_index + 0] = pointer[pointer_index++]; array[array_index + 1] = 0; array[array_index + 2] = 0; /* must report an error */ } #if defined(S_SPLINT_S) /* Apparently Splint doesn't remember which cells were written * just above. */ array_index = 11 - 1; /* set loop maximum */ array[11] = 0; /* set maxRead(array) */ #endif sum = 0; for (array_index = 0; array_index < 11; array_index++) { sum += array[array_index + 0] * array[array_index + 1] * array[array_index + 2]; /* must report an error */ } return sum; } /*----------------------------------------------------------------*/ int no_sub_false_error(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 9@*/ ; int no_sub_false_error(const int *pointer) { int array[12]; int pointer_index, array_index, index; int sum; pointer_index = 0; array_index = 0; for (index = 0; index < 10; index++) { array[array_index + 0] = pointer[pointer_index++]; array[array_index + 1] = 0; array[array_index + 2] = 0; array_index++; } sum = 0; array_index = 0; for (index = 0; index < 10; index++) { /* Apparently Splint doesn't remember which cells were written * just above. So false errors are reported... */ sum += array[array_index + 0] * array[array_index + 1] * array[array_index + 2]; array_index++; } return sum; } /*----------------------------------------------------------------*/ int with_sub_no_error(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 9@*/ ; static void prepare_array_no_error(/*@out@*/ int *array, const int *pointer) /*@modifies array[]@*/ /*@requires maxSet(array) >= 11 /\ maxRead(pointer) >= 9@*/ /*@ensures maxRead(array) == 11@*/ ; static int calculate_sum_no_error(const int *array) /*@modifies nothing@*/ /*@requires maxRead(array) >= 11@*/ ; int with_sub_no_error(const int *pointer) { int array[12]; prepare_array_no_error(array, pointer); return calculate_sum_no_error(array); } static void prepare_array_no_error(int *array, const int *pointer) { int pointer_index, array_index, index; /* Everything is fine in this part :-) * But the extra variable 'index' doesn't look nice. */ pointer_index = 0; array_index = 0; for (index = 0; index < 10; index++) { array[array_index + 0] = pointer[pointer_index++]; array[array_index + 1] = 0; array[array_index + 2] = 0; array_index++; } } static int calculate_sum_no_error(const int *array) { int sum; int array_index, index; /* Everything is fine in this part :-) * But the extra variable 'index' doesn't look nice. */ sum = 0; array_index = 0; for (index = 0; index < 10; index++) { sum += array[array_index + 0] * array[array_index + 1] * array[array_index + 2]; array_index++; } return sum; } /*----------------------------------------------------------------*/ int with_sub_error_caught(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 10@*/ ; static void prepare_array_error_caught(/*@out@*/ int *array, const int *pointer) /*@modifies array[]@*/ /*@requires maxSet(array) >= 11 /\ maxRead(pointer) >= 10@*/ /*@ensures maxRead(array) == 11@*/ ; static int calculate_sum_error_caught(const int *array) /*@modifies nothing@*/ /*@requires maxRead(array) >= 11@*/ ; int with_sub_error_caught(const int *pointer) { int array[12]; prepare_array_error_caught(array, pointer); return calculate_sum_error_caught(array); } static void prepare_array_error_caught(int *array, const int *pointer) { int pointer_index, array_index, index; /* Everything is fine in this part :-) * But the extra variable 'index' doesn't look nice. */ pointer_index = 0; array_index = 0; for (index = 0; index < 11; index++) { array[array_index + 0] = pointer[pointer_index++]; array[array_index + 1] = 0; array[array_index + 2] = 0; array_index++; } } static int calculate_sum_error_caught(const int *array) { int sum; int array_index, index; /* Everything is fine in this part :-) * But the extra variable 'index' doesn't look nice. */ sum = 0; array_index = 0; for (index = 0; index < 11; index++) { sum += array[array_index + 0] * array[array_index + 1] * array[array_index + 2]; array_index++; } return sum; } /*----------------------------------------------------------------*/ int with_sub_false_error(const int *pointer) /*@modifies nothing@*/ /*@requires maxRead(pointer) >= 9@*/ ; static void prepare_array_false_error(/*@out@*/ int *array, const int *pointer) /*@modifies array[]@*/ /*@requires maxSet(array) >= 11 /\ maxRead(pointer) >= 9@*/ /*@ensures maxRead(array) == 11@*/ ; static int calculate_sum_false_error(const int *array) /*@modifies nothing@*/ /*@requires maxRead(array) >= 11@*/ ; int with_sub_false_error(const int *pointer) { int array[12]; prepare_array_false_error(array, pointer); return calculate_sum_false_error(array); } static void prepare_array_false_error(int *array, const int *pointer) { int index; for (index = 0; index < 10; index++) { /* Splint doesn't know exactly which cells are written to, * when the extra variable 'index' is "optimized away". */ array[index + 0] = pointer[index]; array[index + 1] = 0; array[index + 2] = 0; } } static int calculate_sum_false_error(const int *array) { int sum; int index; sum = 0; for (index = 0; index < 10; index++) { /* Splint doesn't know exactly which cells are read, * when the extra variable 'index' is "optimized away". */ sum += array[index + 0] * array[index + 1] * array[index + 2]; } return sum; } Splint output: ============== Splint 3.1.1 --- 12 April 2003 bounds060919.c: (in function no_sub_error_caught) bounds060919.c(51,5): Possible out-of-bounds store: array[array_index + 2] Unable to resolve constraint: requires array_index @ bounds060919.c(51,11) <= 9 needed to satisfy precondition: requires maxSet(array @ bounds060919.c(51,5)) >= array_index @ bounds060919.c(51,11) + 2 A memory write may write to an address beyond the allocated buffer. (Use -boundswrite to inhibit warning) bounds060919.c(65,14): Possible out-of-bounds read: array[array_index + 2] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(65,14)) >= 12 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(65,14)) >= array_index @ bounds060919.c(65,20) + 2 A memory read references memory beyond the allocated storage. (Use -boundsread to inhibit warning) bounds060919.c: (in function no_sub_false_error) bounds060919.c(98,12): Possible out-of-bounds read: array[array_index + 0] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(98,12)) >= 9 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(98,12)) >= array_index @ bounds060919.c(98,18) + 0 bounds060919.c(98,12): Possible out-of-bounds read: array[array_index + 0] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(98,12)) >= 0 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(98,12)) >= array_index @ bounds060919.c(98,18) + 0 bounds060919.c(99,14): Possible out-of-bounds read: array[array_index + 1] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(99,14)) >= 10 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(99,14)) >= array_index @ bounds060919.c(99,20) + 1 bounds060919.c(99,14): Possible out-of-bounds read: array[array_index + 1] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(99,14)) >= 1 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(99,14)) >= array_index @ bounds060919.c(99,20) + 1 bounds060919.c(100,14): Possible out-of-bounds read: array[array_index + 2] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(100,14)) >= 11 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(100,14)) >= array_index @ bounds060919.c(100,20) + 2 bounds060919.c(100,14): Possible out-of-bounds read: array[array_index + 2] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(100,14)) >= 2 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(100,14)) >= array_index @ bounds060919.c(100,20) + 2 bounds060919.c: (in function prepare_array_error_caught) bounds060919.c(208,5): Possible out-of-bounds store: array[array_index + 2] Unable to resolve constraint: requires maxSet(array @ bounds060919.c(208,5)) >= 12 needed to satisfy precondition: requires maxSet(array @ bounds060919.c(208,5)) >= array_index @ bounds060919.c(208,11) + 2 bounds060919.c: (in function calculate_sum_error_caught) bounds060919.c(226,14): Possible out-of-bounds read: array[array_index + 2] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(226,14)) >= 12 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(226,14)) >= array_index @ bounds060919.c(226,20) + 2 bounds060919.c: (in function prepare_array_false_error) bounds060919.c(268,5): Possible out-of-bounds store: array[index + 2] Unable to resolve constraint: requires maxSet(array @ bounds060919.c(268,5)) >= index @ bounds060919.c(268,11) + 2 needed to satisfy precondition: requires maxSet(array @ bounds060919.c(268,5)) >= index @ bounds060919.c(268,11) + 2 bounds060919.c: (in function calculate_sum_false_error) bounds060919.c(282,14): Possible out-of-bounds read: array[index + 1] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(282,14)) >= index @ bounds060919.c(282,20) + 1 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(282,14)) >= index @ bounds060919.c(282,20) + 1 bounds060919.c(283,14): Possible out-of-bounds read: array[index + 2] Unable to resolve constraint: requires maxRead(array @ bounds060919.c(283,14)) >= index @ bounds060919.c(283,20) + 2 needed to satisfy precondition: requires maxRead(array @ bounds060919.c(283,14)) >= index @ bounds060919.c(283,20) + 2 Finished checking --- 13 code warnings With regards, Bodo Wenzel - Software Development - -- BBR - Baudis Bergmann R?sch Verkehrstechnik GmbH Pillaustra?e 1e D - 38126 Braunschweig T: +49.531.27300-766 F: +49.531.27300-999 @: wenzel@bbr-vt.de W: http://www.bbr-vt.de