Author: sebor
Date: Mon Jul 17 16:26:00 2006
New Revision: 422914
URL: http://svn.apache.org/viewvc?rev=422914&view=rev
Log:
2006-07-17 Martin Sebor <[EMAIL PROTECTED]>
* src/printf.cpp (_rw_bufcat): Avoided appending NUL to the end
of buffer and failed consistently when the maximum size of of the
buffer has been reached.
(rw_vasnprintf): Allowed buffer length not including the terminating
NUL to reach its maximum capacity. Reset errno to original value if
set by a failed call to fprintf (e.g., when the file has been closed).
(_rw_vasnprintf_ex): Made sure buffer is NUL-terminated before
invoking user-defined callbacks.
(rw_snprintfa): Returned (char*)0 on error.
* test/printf.cpp (stress_bufsize): Stress test to exercised the
ability to format into a fixed size buffer and correctly report
buffer overlow errors via ENOMEM.
(main): Closed stderr before calling stress_bufsize to avoid
excessive noise.
Modified:
incubator/stdcxx/trunk/tests/self/0.printf.cpp
incubator/stdcxx/trunk/tests/src/printf.cpp
Modified: incubator/stdcxx/trunk/tests/self/0.printf.cpp
URL:
http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/self/0.printf.cpp?rev=422914&r1=422913&r2=422914&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/self/0.printf.cpp (original)
+++ incubator/stdcxx/trunk/tests/self/0.printf.cpp Mon Jul 17 16:26:00 2006
@@ -32,6 +32,7 @@
#include <ios> // for ios::openmode, ios::seekdir
#include <string> // for string
+#include <assert.h> // for assert()
#include <ctype.h> // for isdigit()
#include <errno.h> // for EXXX, errno
#include <limits.h> // for INT_MAX, ...
@@ -2703,6 +2704,51 @@
/***********************************************************************/
+static void
+stress_bufsize ()
+{
+ // exercise the ability to format into a fixed size buffer
+ // and correctly report buffer overlow errors via ENOMEM
+
+ //////////////////////////////////////////////////////////////////
+ static const char str[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ char buf [sizeof str] = "";
+
+ for (unsigned size = 0; size != sizeof str - 1; ++size) {
+ for (unsigned len = 0; len != sizeof str - 1; ++len) {
+
+ errno = 0;
+
+ const char* const s = str + sizeof str - 1 - len;
+
+ // format a substring of s len characters long
+ // into a buffer size characters wide
+ const char* const res =
+ rw_snprintfa (buf, size, "%{*}%s", size, s);
+
+ const int error = errno;
+
+ if (size <= len) {
+ // verify that the function returns 0 and sets errno
+ // to ENOMEM when the provided buffer is not big enough
+ assert (0 == res);
+ assert (ENOMEM == error);
+ }
+ else {
+ // verify that the function returns the address
+ // of the provided buffer on success and that
+ // the contents of the buffer match the argument
+ assert (res == buf);
+ assert (0 == error);
+ assert (0 == strcmp (s, buf));
+ }
+ }
+ }
+}
+
+/***********************************************************************/
+
int main ()
{
test_percent ();
@@ -2751,6 +2797,13 @@
nfailures, ntests);
return 1;
}
+
+ //////////////////////////////////////////////////////////////////
+ // close stderr to prevent the tested function from spitting out
+ // thousands of error messages in the stress test below
+ fclose (stderr);
+
+ stress_bufsize ();
printf ("\nPassed all %d assertions.\n", ntests);
Modified: incubator/stdcxx/trunk/tests/src/printf.cpp
URL:
http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/src/printf.cpp?rev=422914&r1=422913&r2=422914&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/src/printf.cpp (original)
+++ incubator/stdcxx/trunk/tests/src/printf.cpp Mon Jul 17 16:26:00 2006
@@ -419,7 +419,7 @@
size_t buflen = buf.endoff;
const size_t bufree = *buf.pbuf ? *buf.pbufsize - buflen : 0;
- if (bufree <= len || !*buf.pbuf) {
+ if (bufree < len || !*buf.pbuf) {
// for guard block
static const char guard[] = "\xde\xad\xbe\xef";
@@ -465,14 +465,11 @@
*buf.pbuf = newbuf;
*buf.pbufsize = newbufsize - guardsize;
-
- (*buf.pbuf)[buflen] = '\0';
}
if (0 != str) {
memcpy (*buf.pbuf + buflen, str, len);
buflen += len;
- (*buf.pbuf)[buflen] = '\0';
}
buf.endoff = buflen;
@@ -750,7 +747,7 @@
goto fail;
RW_ASSERT (0 != *buf.pbuf);
- RW_ASSERT (0 != *buf.pbufsize);
+ RW_ASSERT (0 != buf.pbufsize);
if (0 == pcnt)
break;
@@ -843,8 +840,8 @@
if (len < 0)
goto fail;
- RW_ASSERT (size_t (len) < *buf.pbufsize);
- RW_ASSERT (buf.endoff < *buf.pbufsize);
+ RW_ASSERT (size_t (len) <= *buf.pbufsize);
+ RW_ASSERT (buf.endoff <= *buf.pbufsize);
const size_t offinx = size_t (nextoff - 1);
@@ -916,7 +913,7 @@
++paramno;
}
- RW_ASSERT (len + buflen < *buf.pbufsize);
+ RW_ASSERT (len + buflen <= *buf.pbufsize);
// adjust the next pointer to point to the terminating
// NUL in the (possibly reallocated) buffer
@@ -975,10 +972,12 @@
fail: // function failed
+ const int error = errno;
+
fprintf (stderr, "%s:%d: rw_vasnprintf(%p, %p, \"%s\", va_list) "
"error: errno = %d: %s\n",
__FILE__, __LINE__, (void*)buf.pbuf, (void*)buf.pbufsize, fmt,
- errno, strerror (errno));
+ error, strerror (error));
for (size_t i = 0; i != paramno; ++i)
free (pspec [i].strarg);
@@ -992,6 +991,9 @@
*buf.pbuf = 0;
}
+ if (errno != error)
+ errno = error;
+
return -1;
#undef varg
@@ -2445,6 +2447,11 @@
// top to bottom
if (_rw_usr_fun [i]) {
+ if (0 == _rw_bufcat (buf, 0, 1))
+ return -1;
+
+ (*buf.pbuf)[buf.endoff] = '\0';
+
// user-defined extension?
if (0 < spec.paramno) {
// pass the address of the paramno argument
@@ -3094,7 +3101,7 @@
_RWSTD_UNUSED (nchars);
- return buf;
+ return nchars < 0 ? 0 : buf;
}
/********************************************************************/