From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailout.scc.kit.edu (mailout.scc.kit.edu [129.13.185.202]) by krisdoz.my.domain (8.14.5/8.14.5) with ESMTP id s7HFwZec020333 for ; Sun, 17 Aug 2014 11:58:39 -0400 (EDT) Received: from hekate.usta.de (asta-nat.asta.uni-karlsruhe.de [172.22.63.82]) by scc-mailout-02.scc.kit.edu with esmtp (Exim 4.72 #1) id 1XJ2qp-00025j-5z; Sun, 17 Aug 2014 17:58:35 +0200 Received: from donnerwolke.usta.de ([172.24.96.3]) by hekate.usta.de with esmtp (Exim 4.77) (envelope-from ) id 1XJ2qn-0001VC-5B; Sun, 17 Aug 2014 17:58:33 +0200 Received: from iris.usta.de ([172.24.96.5] helo=usta.de) by donnerwolke.usta.de with esmtp (Exim 4.72) (envelope-from ) id 1XJ2qn-0005X2-3M; Sun, 17 Aug 2014 17:58:33 +0200 Received: from schwarze by usta.de with local (Exim 4.77) (envelope-from ) id 1XJ2q2-0000fK-DL; Sun, 17 Aug 2014 17:57:46 +0200 Date: Sun, 17 Aug 2014 17:57:46 +0200 From: Ingo Schwarze To: tech@mdocml.bsd.lv Cc: Thomas Klausner Subject: enum type safety Message-ID: <20140817155745.GA3959@iris.usta.de> References: <20140814214036.GJ29858@iris.usta.de> <20140816215701.GE12335@iris.usta.de> <20140817122227.GH21604@danbala.tuwien.ac.at> X-Mailinglist: mdocml-tech Reply-To: tech@mdocml.bsd.lv MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20140817122227.GH21604@danbala.tuwien.ac.at> User-Agent: Mutt/1.5.21 (2010-09-15) Hi, Thomas Klausner just pointed out that some compilers still worry that the local variable r might be used uninitialized in term_ascii.c, function ascii_hspan(). Digging into this, i found that it cannot actually happen: 1. The function ascii_hspan() is only called through the struct termp hspan function pointer. 2. Such a call happens at exactly one place: term.c, term_hspan(). 3. The function term_hspan() has the following callers: - term.c, term_setwidth() - man_term.c, a2width() - mdoc_term.c, a2width() - mdoc_term.c, a2offs() All these callers initialize the struct roffsu passed to term_hspan() using a2roffsu() and checking the return value or SCALE_HS_INIT(). Now obviously, when compiling the term_ascii.c translation unit, the compiler cannot know what the calling translation units may pass into this non-static function. But what can they? All the enum roffscale enumeration constants defined in out.h are handled in ascii_hspan(). Isn't that safe? What could possibly go wrong? Digging into this, i learnt something about C i didn't yet know. Here is what the C standard says (C99 = ISO/IEC 9899:TC3, C11 = ISO/IEC 9899:201x Comittee Draft): * Each enumerated type shall be compatible with a char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, ... (C99/C11 6.7.2.2 paragraph 4) * Conversion of an operand value to a compatible type causes no change to the value or the representation. (C99/C11 6.3 paragraph 2) So the C standard *requires* enum types to *not* be type-safe, the following would be legal C: enum roffscale scale; char c; /* ... */ scale = 42; /* ... */ c = scale; And now the C standard *requires* that c ends up being 42. This is amazing. You use enum for type safety (that's generally regarded as good practice, isn't it?) and then the very standard forbids the compiler to actually implement enum in a type-safe way. So whereever you have an interface with external linkage accepting an enum value, for defensive programming you have to assume that *any* value representable in *any* signed or unsigned integer type can come in, so you basically *always* need a default: clause. Is this analysis right, or do you consider the patch appended below as silly? Yours, Ingo Index: term_ascii.c =================================================================== RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term_ascii.c,v retrieving revision 1.31 diff -u -p -r1.31 term_ascii.c --- term_ascii.c 16 Aug 2014 19:00:01 -0000 1.31 +++ term_ascii.c 17 Aug 2014 15:54:48 -0000 @@ -253,7 +253,7 @@ ascii_hspan(const struct termp *p, const case SCALE_EM: r = su->scale; break; - case SCALE_MAX: + default: abort(); /* NOTREACHED */ } -- To unsubscribe send an email to tech+unsubscribe@mdocml.bsd.lv