From owner-freebsd-arch@FreeBSD.ORG Tue Dec 13 09:17:03 2005 Return-Path: X-Original-To: freebsd-arch@freebsd.org Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4820D16A41F for ; Tue, 13 Dec 2005 09:17:03 +0000 (GMT) (envelope-from PeterJeremy@optushome.com.au) Received: from mail20.syd.optusnet.com.au (mail20.syd.optusnet.com.au [211.29.132.201]) by mx1.FreeBSD.org (Postfix) with ESMTP id 70B8443D5A for ; Tue, 13 Dec 2005 09:17:02 +0000 (GMT) (envelope-from PeterJeremy@optushome.com.au) Received: from cirb503493.alcatel.com.au (c220-239-19-236.belrs4.nsw.optusnet.com.au [220.239.19.236]) by mail20.syd.optusnet.com.au (8.12.11/8.12.11) with ESMTP id jBD9GwZU005165 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO); Tue, 13 Dec 2005 20:16:58 +1100 Received: from cirb503493.alcatel.com.au (localhost.alcatel.com.au [127.0.0.1]) by cirb503493.alcatel.com.au (8.12.10/8.12.10) with ESMTP id jBD9GvHh077969; Tue, 13 Dec 2005 20:16:57 +1100 (EST) (envelope-from pjeremy@cirb503493.alcatel.com.au) Received: (from pjeremy@localhost) by cirb503493.alcatel.com.au (8.12.10/8.12.9/Submit) id jBD9GvKW077968; Tue, 13 Dec 2005 20:16:57 +1100 (EST) (envelope-from pjeremy) Date: Tue, 13 Dec 2005 20:16:56 +1100 From: Peter Jeremy To: Bruce Evans Message-ID: <20051213091656.GD77268@cirb503493.alcatel.com.au> References: <1023.1134389663@critter.freebsd.dk> <200512121643.39236.max@love2party.net> <20051213175413.H80942@delplex.bde.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20051213175413.H80942@delplex.bde.org> User-Agent: Mutt/1.4.2.1i X-PGP-Key: http://members.optusnet.com.au/peterjeremy/pubkey.asc Cc: freebsd-arch@freebsd.org Subject: Re: printf behaviour with illegal or malformed format string X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Dec 2005 09:17:03 -0000 On Tue, 2005-Dec-13 18:53:15 +1100, Bruce Evans wrote: >>>Our first line of defence against this kind of error is compile-time >>>checking by GCC, but we cannot rely on the string being sane in libc, >>>we still need to do error checking. > >There is also fmtcheck(3). I'm probably not the only person who hadn't heard of this function before reading your mail. I'm not sure it is of much use other than validating user-supplied format strings (and maybe internationalisation translations via catgets(3)). >I think most checking belongs in the compiler and in fmtcheck(3). fmtcheck(3) can't check that the arguments passed to printf are valid. All it can do is verify that two arbitrary format strings expect the same arguments and the documentation states it doesn't even manage that: The fmtcheck() function does not understand all of the conversions that printf(3) does. Note that fmtcheck(3) has no way of reporting that neither format string makes sense - the documentation states that it will always return one of its arguments. If a programmer (mistakenly) believes that "%hf" is sensible then fmtcheck(3) isn't going to help. >printf() itself cannot detect most types errors without compiler >support that would basically involve passing it the types of all >args so that it could call fmtcheck(3). This is an interesting idea but fmtcheck(3) isn't adequate. In particular, consider: int i, j; const char *fmt, *string; ... fmt = "%*.*s %p"; ... printf(fmt, i, j, string, string); Based on the printf() arguments, the compiler can't really do better than: printf(fmtcheck(fmt, "%d %d %s %s"), i, j, string, string); but fmtcheck(3) doesn't consider that "%*.*s %p" and "%d %d %s %s" are equivalent. What could be useful is a function that takes a format string and a set of argument types and verifies that the argument types match the format string. The compiler could then expand the printf() to: if (fmtvalidate(fmt, "int;int;char*;char*")) printf(fmt, i, j, string, string); else abort(); (though it's not clear how the compiler should handle struct/union pointers which might make sense to a user extension). >>>If the variable is set, a bogus format string will result in abort(2). > >This sometimes breaks defined behaviour. I thought printf(3) documented the behaviour for invalid conversion specifiers and mofidiers but I can't find it in the man page right now. -- Peter Jeremy