Return-Path: <tiff-bounces@lists.maptools.org>
X-Original-To: info@awaresystems.be
Delivered-To: info@awaresystems.be
Received: from mx-m.b-one.net (mx-m.one.com [91.198.169.60])
	by mail9.b-one.net (Postfix) with ESMTP id 68BAD400125
	for <info@awaresystems.be>; Fri,  6 Feb 2009 22:08:53 +0100 (CET)
X-Virus-Scanned: by one.com
X-Spam-Score: 0
X-Spam-Level: 
X-Spam-Status: No, score=0 tagged_above=0 required=6 tests=[none]
X-Greylist: domain auto-whitelisted by SQLgrey-1.7.4
Received: from lists.maptools.org (lists.maptools.org [65.39.174.144])
	by mx-m.b-one.net (Postfix) with ESMTP id 9EFDB189FE20
	for <info@awaresystems.be>; Fri,  6 Feb 2009 22:08:50 +0100 (CET)
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
	by lists.maptools.org (Postfix) with ESMTP id 763961D18B13D;
	Fri,  6 Feb 2009 16:07:32 -0500 (EST)
Received: from cerious.com (mail.cerious.com [66.193.70.90])
	by lists.maptools.org (Postfix) with ESMTP id ECD381D18B117
	for <tiff@lists.maptools.org>; Fri,  6 Feb 2009 15:34:29 -0500 (EST)
Received: from [192.168.1.113] (account pcrews HELO [127.0.0.1])
	by cerious.com (CommuniGate Pro SMTP 4.1.8)
	with ESMTP id 11276640 for tiff@lists.maptools.org;
	Fri, 06 Feb 2009 15:34:28 -0500
Message-ID: <498C9ED5.8030000@cerious.com>
Date: Fri, 06 Feb 2009 15:34:29 -0500
From: Phillip Crews <pcrews@cerious.com>
Organization: Cerious Software Inc.
User-Agent: Thunderbird 2.0.0.19 (Windows/20081209)
MIME-Version: 1.0
To: tiff@lists.maptools.org
References: <498B321F.3000300@pobox.com>
	<Pine.SOC.4.64.0902051303550.12379@freddy.simplesystems.org>
	<498B3D49.2030202@pobox.com>
	<Pine.SOC.4.64.0902051352210.12379@freddy.simplesystems.org>
	<498BBEED.7050805@cerious.com>
	<Pine.SOC.4.64.0902061027520.12379@freddy.simplesystems.org>
In-Reply-To: <Pine.SOC.4.64.0902061027520.12379@freddy.simplesystems.org>
X-Antivirus: avast! (VPS 090206-0, 02/06/2009), Outbound message
X-Antivirus-Status: Clean
Subject: Re: [Tiff] assertions, and building with DEBUG/NDEBUG
X-BeenThere: tiff@lists.maptools.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: TIFF and libtiff discussion <tiff.lists.maptools.org>
List-Unsubscribe: <http://lists.maptools.org/mailman/listinfo/tiff>,
	<mailto:tiff-request@lists.maptools.org?subject=unsubscribe>
List-Archive: <http://lists.maptools.org/mailman/private/tiff>
List-Post: <mailto:tiff@lists.maptools.org>
List-Help: <mailto:tiff-request@lists.maptools.org?subject=help>
List-Subscribe: <http://lists.maptools.org/mailman/listinfo/tiff>,
	<mailto:tiff-request@lists.maptools.org?subject=subscribe>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Sender: tiff-bounces@lists.maptools.org
Errors-To: tiff-bounces@lists.maptools.org

Bob Friesenhahn wrote:
> On Thu, 5 Feb 2009, Phillip Crews wrote:
>>
>> In a library like libtiff, it is inappropriate to abort the calling
>> program when an assertion is triggered, which a failed assert() does on
>> many platforms.
>>
>> In my code, I use my own macro, which is defined as assert() in debug
>> builds, but in release builds calls an internal logging routine and
>> continues. If a severe problem or crash occurs later because of the bad
>> value, I have information to go on in the log.
>
> It is quite often (most often) not appropriate to proceed with 
> processing once an assert has been encountered.  Doing to risks heap 
> corruption, and potential exploits from intentionally malligned files. 
> If any heap or stack corruption has occured, then the process is then 
> in an instable state.

Unfortunately, this is neither how assert() was designed, nor how it is 
implemented on the platforms I'm familiar with. Of course, assert() 
should never be used for external data validation. In practice, it's not 
always easy to analyze how someone else used it.

> The key thing is to discriminate between issues which are best 
> reported as errors, warnings, or assertions.  Assertions should always 
> stop processing since they should be used to detect logic (i.e. 
> design/implementation) errors.  Warnings result in a message to the 
> user, but processing continues.  Errors result in a message to the 
> user, and a return to the invoking code with no further processing of 
> the current file.

The default behavior for assert() in production builds (NDEBUG) on most 
platforms is to not even do the check, much less to log, which is why I 
defined my own assertion macro and supporting routines. Because of 
unpredictability in the large number of libraries I use, I do not 
attempt to build with neither DEBUG nor NDEBUG defined. Some libraries I 
use specifically state that NDEBUG should be defined for production 
builds, though I don't have enough in-depth knowledge or free time to 
analyze  them all.

I am careful with my assertions -- I use them for sanity, parameter, 
handle, scalar size, thread, or constant validations -- verifying 
assumptions made by the code or even reminders for the future. Examples:

  CS_ASSERT(sizeof(HFILE) == sizeof(long));  /* Following code assumes 
handles are 32-bit */
  CS_ASSERT(CS_ISGUITHREAD()); /* Must only be called from user 
interface thread */
  CS_ASSERT(open_count < 200); /* Something isn't closing files properly! */
  CS_ASSERT(origin == SEEK_SET || origin == SEEK_END || origin == SEEK_CUR);

I handle buffer checks, range checks, and other things that could result 
in invalid memory accesses as errors: by returning FALSE, NULL or an 
error code, by setting a default value, or by raising an exception (in 
C++ code). Many of these include a CS_ASSERT(0) so I'll see the problem 
immediately when testing internally.

Anyway, back to what libtiff should do: I don't see my style of logging 
as a viable option unless it's done with platform and 
application-specific callbacks, at which point you're pretty much 
restricted to using TIFFWarning()/TIFFError() unless you're willing to 
adopt significant ABI changes.

One way would be to define a TASSERTW (warn and continue) for cases 
where processing can continue, a TASSERTF (fatal) which actually calls 
TIFFError() and bails using abort() -- this should be used minimally if 
at all, considering that libtiff is used in large-scale GUI applications 
and daemons, which need to completely fail as rarely as possible. An 
additional define -DOLDASSERT could be used to provide the current 
assert behavior.

#if defined(OLDASSERT)
#define TASSERTW(x) assert(x)
#define TASSERTF(x) assert(x)
#else
#define TASSERTW(x) (void)( (!!(x)) || (TiffAssertW(x, __FILE__, 
__LINE__, __func__), 0) )
#define TASSERTF(x) (void)( (!!(x)) || (TiffAssertF(x, __FILE__, 
__LINE__, __func__), 0) )
#endif

"Wrong" assertions of course need to be converted to actual error 
returns; unfortunately, this is not a trivial task, since each requires 
analysis, a lot of them are deep, and all callers will need to be 
examined to be sure they propagate the error correctly. There shouldn't 
be a lot of them, however.

_______________________________________________
Tiff mailing list: Tiff@lists.maptools.org
http://lists.maptools.org/mailman/listinfo/tiff
http://www.remotesensing.org/libtiff/
