Return-Path: Delivered-To: apmail-incubator-stdcxx-dev-archive@www.apache.org Received: (qmail 87857 invoked from network); 12 Jul 2006 16:18:26 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 12 Jul 2006 16:18:26 -0000 Received: (qmail 1870 invoked by uid 500); 12 Jul 2006 16:18:26 -0000 Delivered-To: apmail-incubator-stdcxx-dev-archive@incubator.apache.org Received: (qmail 1858 invoked by uid 500); 12 Jul 2006 16:18:26 -0000 Mailing-List: contact stdcxx-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-dev@incubator.apache.org Received: (qmail 1844 invoked by uid 99); 12 Jul 2006 16:18:26 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Jul 2006 09:18:26 -0700 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [212.82.213.172] (HELO exkiv.kyiv.vdiweb.com) (212.82.213.172) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Jul 2006 09:18:24 -0700 Received: from [10.11.37.44] ([10.11.37.44]) by exkiv.kyiv.vdiweb.com with Microsoft SMTPSVC(6.0.3790.1830); Wed, 12 Jul 2006 19:18:14 +0300 Message-ID: <44B520C5.9030603@kyiv.vdiweb.com> Date: Wed, 12 Jul 2006 19:18:13 +0300 From: Farid Zaripov User-Agent: Thunderbird 1.5.0.4 (Windows/20060516) MIME-Version: 1.0 To: stdcxx-dev@incubator.apache.org Subject: RE: design of testuite exceptions (was: Re: svn commit: r418319 - /incubator/stdcxx/trunk/tests/strings/21.string.io.cpp) Content-Type: multipart/mixed; boundary="------------000807050906050906040905" X-OriginalArrivalTime: 12 Jul 2006 16:18:14.0458 (UTC) FILETIME=[C6D8C9A0:01C6A5CE] X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N --------------000807050906050906040905 Content-Type: text/plain; charset=KOI8-R; format=flowed Content-Transfer-Encoding: 7bit Martin, I implemented your latest notes about testsuite exception (rw_exception.h, exception.cpp). The updated version is attached. > -----Original Message----- > From: Martin Sebor [mailto:sebor@roguewave.com] > Sent: Wednesday, July 12, 2006 4:27 AM > To: stdcxx-dev@incubator.apache.org > Subject: Re: design of testuite exceptions (was: Re: svn > commit: r418319 - > /incubator/stdcxx/trunk/tests/strings/21.string.io.cpp) > > Okay. I think I would still like to remove the logtostderr > argument and do the logging in new.cpp. Done > Also, it would be more efficient to avoid catching and > rethrowing the exception only to call va_end() on the > argument list. Done > Finally, [...] > we want to catch the same type and > maybe just throw different (but not visible) types derived > from it. Done > Moving on to allocator.cpp [...] > the fifth argument to rw_throw: "SharedAlloc::funcall" > should be the name of the function or 0 (in which case > rw_throw would need to avoid trying to format it): Done > I would be happier with catching the exception here (by > reference), logging the what() string when logging/tracing is > enabled, and then rethrowing it, than be stuck with the extra > argument to rw_throw(). Done Farid. --------------000807050906050906040905 Content-Type: text/plain; name="allocator.cpp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="allocator.cpp.diff" Index: allocator.cpp =================================================================== --- allocator.cpp (revision 421257) +++ allocator.cpp (working copy) @@ -34,6 +34,7 @@ #include // for bad_alloc, placement new #include // for va_arg(), va_list #include // for memset() +#include // for _rw_throw_exception /**************************************************************************/ @@ -55,37 +56,7 @@ static int _rw_id_gen; // generates unique ids -/**************************************************************************/ -_TEST_EXPORT int -rw_vasnprintf (char**, size_t*, const char*, va_list); - - -static void -_rw_throw_exception (const char *file, int line, const char *fmt, ...) -{ - struct BadSharedAlloc: _RWSTD_BAD_ALLOC { - char what_ [4096]; - - /* virtual */ const char* what () const _THROWS (()) { - return what_; - } - }; - - BadSharedAlloc ex; - - va_list va; - va_start (va, fmt); - - char *buf = ex.what_; - size_t bufsize = sizeof ex.what_; - rw_vasnprintf (&buf, &bufsize, fmt, va); - - va_end (va); - - throw ex; -} - /**************************************************************************/ SharedAlloc:: @@ -136,14 +107,14 @@ const size_t nbytes = nelems * size; if (max_blocks_ < n_blocks_ + nelems) - _rw_throw_exception (__FILE__, __LINE__, - "allocate (%zu): reached block limit of %zu", - nbytes, max_blocks_); + rw_throw (ex_bad_alloc, __FILE__, __LINE__, 0, + "allocate (%zu): reached block limit of %zu", + nbytes, max_blocks_); if (max_bytes_ < n_bytes_ + nbytes) - _rw_throw_exception (__FILE__, __LINE__, - "allocate (%zu): reached size limit of %zu", - nbytes, max_bytes_); + rw_throw (ex_bad_alloc, __FILE__, __LINE__, 0, + "allocate (%zu): reached size limit of %zu", + nbytes, max_bytes_); return operator_new (nbytes, false); } @@ -229,9 +200,9 @@ // increment the exception counter for this function ++n_throws_ [mf]; - _rw_throw_exception (__FILE__, __LINE__, - "UserAlloc::%s: reached call limit of %zu", - _rw_func_names [mf], throw_at_calls_); + rw_throw (ex_bad_alloc, __FILE__, __LINE__, 0, + "UserAlloc::%s: reached call limit of %zu", + _rw_func_names [mf], throw_at_calls_); RW_ASSERT (!"logic error: should not reach"); } --------------000807050906050906040905 Content-Type: text/plain; name="new.cpp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="new.cpp.diff" Index: new.cpp =================================================================== --- new.cpp (revision 421257) +++ new.cpp (working copy) @@ -28,8 +28,6 @@ // expand _TEST_EXPORT macros #define _RWSTD_TEST_SRC -#include // for bad_alloc - #include // for abort(), free(), getenv(), malloc() #include // for memset() @@ -37,6 +35,8 @@ #include #include +#include + /************************************************************************/ #ifndef _RWSTD_BAD_ALLOC @@ -272,16 +272,6 @@ } -struct BadAlloc: _RWSTD_BAD_ALLOC -{ - char what_ [4096]; - - /* virtual */ const char* what () const _THROWS (()) { - return what_; - } -}; - - static size_t seq_gen; // sequence number generator @@ -365,48 +355,47 @@ || reached_block_limit || reached_size_limit) { - BadAlloc ex; - #ifndef _RWSTD_NO_EXCEPTIONS - rw_snprintfa (ex.what_, 4096U, "%s:%d: %s (%zu) ", - __FILE__, __LINE__, name [array], nbytes); + try { + const char * threw = "threw bad_alloc:"; - strcat (ex.what_, "threw bad_alloc: "); + if (reached_call_limit) + rw_throw (ex_bad_alloc, + __FILE__, __LINE__, name [array], + "(%zu) %s reached call limit of %zu", + nbytes, threw, pst->new_calls_ [array]); - if (reached_call_limit) + else if (reached_block_limit) + rw_throw (ex_bad_alloc, + __FILE__, __LINE__, name [array], + "(%zu) %s reached block limit of %zu: %zu", + nbytes, threw, *pst->throw_at_blocks_ [array], + pst->blocks_ [array]); - rw_snprintfa ( - ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_), - "reached call limit of %zu", pst->new_calls_ [array]); + else if (reached_size_limit) + rw_throw (ex_bad_alloc, + __FILE__, __LINE__, name [array], + "(%zu) %s reached size limit of %zu: %zu", + nbytes, threw, *pst->throw_at_bytes_ [array], + pst->bytes_ [array]); + } + catch (const std::exception & ex) { + if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1]) + rw_fprintf (rw_stderr, "%s\n", ex.what ()); - else if (reached_block_limit) + throw; + } - rw_snprintfa ( - ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_), - "reached block limit of %zu: %zu", - *pst->throw_at_blocks_ [array], pst->blocks_ [array]); - - else if (reached_size_limit) - - rw_snprintfa ( - ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_), - "reached size limit of %zu: %zu", - *pst->throw_at_bytes_ [array], pst->bytes_ [array]); - - if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1]) - rw_fprintf (rw_stderr, "%s\n", ex.what ()); - - throw ex; - #else // if defined (_RWSTD_NO_EXCEPTIONS) if (reached_breakpoint) { - rw_snprintfa ( - ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_), + char buf[4096]; + + rw_snprintfa (buf, sizeof(buf), "reached a breakpoint at of %zu calls", *pst->break_at_seqno_); - _RW::__rw_assert_fail (ex.what_, __FILE__, __LINE__, name [array]); + _RW::__rw_assert_fail (buf, __FILE__, __LINE__, name [array]); } if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1]) @@ -426,16 +415,21 @@ ptr = malloc (block_size); if (!ptr) { - BadAlloc ex; - rw_snprintfa (ex.what_, 4096U, - "%s:%d: %s (%zu) threw bad_alloc: malloc() returned 0", - __FILE__, __LINE__, name [array], nbytes); - - if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1]) - rw_fprintf (rw_stderr, "%s\n", ex.what ()); #ifndef _RWSTD_NO_EXCEPTIONS - throw ex; + + try { + rw_throw (ex_bad_alloc, + __FILE__, __LINE__, name [array], + "(%zu): malloc() returned 0", nbytes); + } + catch (const std::exception & ex) { + if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1]) + rw_fprintf (rw_stderr, "%s\n", ex.what ()); + + throw; + } + #else // if defined (_RWSTD_NO_EXCEPTIONS) return ptr; #endif // _RWSTD_NO_EXCEPTIONS @@ -514,7 +508,6 @@ Header* const hdr = _rw_find_block (ptr, true, name [array]); if (!hdr) { - // hdr should never be 0 except under special circumstances // such as when the compiler's runtime library itself passes // the wrong argument to operator delete (such as libcxx --------------000807050906050906040905 Content-Type: text/plain; name="rw_streambuf.h.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="rw_streambuf.h.diff" Index: rw_streambuf.h =================================================================== --- rw_streambuf.h (revision 421257) +++ rw_streambuf.h (working copy) @@ -29,11 +29,12 @@ #define RW_STREAMBUF_H_INCLUDED -#include // for memset() -#include // for basic_streambuf +#include // for memset() +#include // for basic_streambuf #include -#include // for make_char +#include // for make_char +#include // for _rw_throw_exception enum MemFun { @@ -56,6 +57,10 @@ Unknown = 0x4000 }; +static const char* const streambuf_func_names[] = { + "setbuf", "seekoff", "seekpos", "showmanyc", "xsgetn", "underflow", + "uflow", "overflow", "pbackfail", "xsputn", "sync" +}; template struct MyStreambuf: std::basic_streambuf @@ -163,17 +168,21 @@ public: int ncalls (MemFun) const; + int memfun_inx (MemFun) const; char_type *buf_; std::streamsize bufsize_; - int throw_set_; // functions that should throw - int fail_set_; // functions that should fail - MemFun threw_; // which function threw - MemFun failed_; // which function failed + int throw_set_; // functions that should throw + int fail_set_; // functions that should fail + MemFun threw_; // which function threw + MemFun failed_; // which function failed - int fail_when_; // call number on which to fail + int fail_when_; // call number on which to fail + int throw_when_ [11]; // call number on which to throw for each func + int allthrows_; // total number of thrown exceptions + // max size of the pending input sequence static std::streamsize in_pending_; @@ -183,7 +192,10 @@ private: bool test (MemFun) const; + int ncalls_ [11]; // number of calls made to each function + + int allcalls_; // total number of calls }; @@ -202,11 +214,14 @@ MyStreambuf (std::streamsize bufsize, int fail_set, int when) : Base (), buf_ (0), bufsize_ (bufsize), throw_set_ (0), fail_set_ (0), threw_ (None), failed_ (None), - fail_when_ (when) + fail_when_ (when), allthrows_ (0), allcalls_ (0) { // reset the member function call counters std::memset (ncalls_, 0, sizeof ncalls_); + // reset the member function throw counters + std::memset (throw_when_, 0, sizeof throw_when_); + // allocate a (possibly wide) character buffer for output buf_ = new charT [bufsize_]; @@ -232,11 +247,14 @@ MyStreambuf (const char *buf, std::streamsize bufsize, int fail_set, int when) : Base (), buf_ (0), bufsize_ (bufsize), throw_set_ (0), fail_set_ (0), threw_ (None), failed_ (None), - fail_when_ (when) + fail_when_ (when), allthrows_ (0), allcalls_ (0) { // reset the member function call counters std::memset (ncalls_, 0, sizeof ncalls_); + // reset the member function throw counters + std::memset (throw_when_, 0, sizeof throw_when_); + // as a convenience, if `bufsize == -1' compute the size // from the length of `buf' if (std::streamsize (-1) == bufsize_) @@ -396,11 +414,10 @@ return traits_type::eof (); } - template int MyStreambuf:: -ncalls (MemFun which) const +memfun_inx (MemFun which) const { int inx = -1; @@ -413,10 +430,22 @@ } } - return ncalls_ [inx]; + return inx; } +template +int +MyStreambuf:: +ncalls (MemFun which) const +{ + int inx = memfun_inx (which); + if (0 <= inx) + return ncalls_ [inx]; + + return -1; +} + template bool MyStreambuf:: @@ -424,35 +453,34 @@ { MyStreambuf* const self = _RWSTD_CONST_CAST (MyStreambuf*, this); - int inx = -1; + int inx = memfun_inx (which); + if (-1 == inx) + return true; - for (unsigned i = 0; i < sizeof (which) * _RWSTD_CHAR_BIT; ++i) { - if (which & (1U << i)) { - if (inx < 0) - inx = i; - else - return true; - } - } - // increment the counter tracking the number of calls made // to each member function; do so regardless of whether // an exception will be thrown below - const int callno = self->ncalls_ [inx]++; + self->ncalls_ [inx] ++; + self->allcalls_ ++; + const int callno = self->ncalls_ [inx]; #ifndef _RWSTD_NO_EXCEPTIONS // if the call counter is equal to the `fail_when_' watermark // and `shich' is set in the `throw_set_' bitmask, throw an // exception with the value of the member id - if (callno == fail_when_ && throw_set_ & which) { + if (callno == throw_when_ [inx] && throw_set_ & which) { self->threw_ = which; - throw which; + self->allthrows_++; + + rw_throw (ex_stream, __FILE__, __LINE__, + streambuf_func_names [inx], + "%s", "test exception"); } #else // if defined (_RWSTD_NO_EXCEPTIONS) - if (callno == fail_when_ && throw_set_ & which) { + if (callno == throw_when_ [inx] && throw_set_ & which) { self->threw_ = which; return false; } --------------000807050906050906040905 Content-Type: text/plain; name="rw_exception.h" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="rw_exception.h" /************************************************************************ * * rw_exception.h - defines a test driver exception * * $Id: $ * *************************************************************************** * * Copyright 2006 The Apache Software Foundation or its licensors, * as applicable. * * Copyright 2004-2006 Rogue Wave Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **************************************************************************/ #ifndef RW_EXCEPTION_H_INCLUDED #define RW_EXCEPTION_H_INCLUDED #include enum ExceptionId { ex_unknown = 0, // custom exceptions, i.e. not derived for std::exception ex_stream = 1, ex_custom = 7, // exceptions derived from std::exception ex_bad_alloc = 8, ex_std = (7 << 3) }; struct _TEST_EXPORT Exception { const ExceptionId id_; Exception (ExceptionId id) : id_ (id) {} virtual ~Exception (); virtual const char* what () const = 0; }; _TEST_EXPORT void rw_throw (ExceptionId exid, const char *file, int line, const char *function, const char *fmt, ...); #endif // RW_EXCEPTION_H_INCLUDED --------------000807050906050906040905 Content-Type: text/plain; name="exception.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="exception.cpp" /************************************************************************ * * exception.cpp - exceptions testsuite helpers * * $Id: $ * ************************************************************************ * * Copyright 2006 The Apache Software Foundation or its licensors, * as applicable. * * Copyright 2006 Rogue Wave Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **************************************************************************/ // expand _TEST_EXPORT macros #define _RWSTD_TEST_SRC #include #include #include #include // for strncpy() #include // for free() #include // for size_t #include // for va_arg(), va_list #include // for std::bad_alloc /**************************************************************************/ Exception::~Exception () { } /**************************************************************************/ struct ExceptionBase { char buf_ [256]; char* what_; ExceptionBase (); ExceptionBase (const ExceptionBase&); ~ExceptionBase (); ExceptionBase& operator= (const ExceptionBase&); private: void free_ (); }; ExceptionBase::ExceptionBase () : what_ (buf_) { buf_ [0] = '\0'; } ExceptionBase::ExceptionBase (const ExceptionBase& ex) : what_ (buf_) { *this = ex; } ExceptionBase::~ExceptionBase () { free_ (); } ExceptionBase& ExceptionBase::operator= (const ExceptionBase& ex) { if (&ex != this) { free_ (); if (ex.buf_ != ex.what_) what_ = strdup (ex.what_); else strncpy (buf_, ex.buf_, sizeof (buf_)); } return *this; } void ExceptionBase::free_ () { if (buf_ != what_) { free (what_); what_ = buf_; } } /**************************************************************************/ struct BadAlloc : std::bad_alloc, ExceptionBase { ~BadAlloc () _THROWS (()) {} const char* what () const _THROWS (()) { return what_; } }; /**************************************************************************/ struct StreamException : Exception, ExceptionBase { StreamException () : Exception (ex_stream) { } const char* what () const { return what_; } }; /**************************************************************************/ _TEST_EXPORT int rw_vasnprintf (char**, size_t*, const char*, va_list); /**************************************************************************/ static int _rw_format (char** pbuf, size_t* pbufsize, const char* file, int line, const char* function, const char* fmt, va_list va) { const int nchars1 = function ? rw_asnprintf (pbuf, pbufsize, "\"%s\", %d, \"%s\" ", file, line, function) : rw_asnprintf (pbuf, pbufsize, "\"%s\", %d, ", file, line); if (0 > nchars1) return nchars1; char *tmpbuf = 0; size_t tmpsize = 0; const int nchars2 = rw_vasnprintf (&tmpbuf, &tmpsize, fmt, va); if (0 > nchars2) { free (tmpbuf); return nchars1; } const int nchars3 = rw_asnprintf (pbuf, pbufsize, "%{+}%s", tmpbuf); free (tmpbuf); return 0 > nchars3 ? nchars1 : nchars1 + nchars3; } // str should be allocated by malloc() call // str shouldn't be free after call _rw_init_exception() static void _rw_init_exception (ExceptionBase& ex, char* str, size_t nchars) { if (nchars < sizeof (ex.buf_)) { memcpy (ex.buf_, str, nchars); ex.buf_ [nchars] = '\0'; free (str); } else ex.what_ = str; } _TEST_EXPORT void rw_throw (ExceptionId exid, const char *file, int line, const char *function, const char *fmt, ...) { // format string char* buf = 0; size_t bufsize = 0; va_list va; va_start (va, fmt); const int nchars = _rw_format (&buf, &bufsize, file, line, function, fmt, va); va_end (va); switch (exid) { case ex_stream: { StreamException ex; _rw_init_exception (ex, buf, nchars); throw ex; } case ex_bad_alloc: { BadAlloc ex; _rw_init_exception (ex, buf, nchars); throw ex; } default: free (buf); throw ex_unknown; } } --------------000807050906050906040905--