> -----Original Message-----
> From: Martin Sebor [mailto:[EMAIL PROTECTED]
> Sent: Monday, July 10, 2006 1:59 AM
> To: [email protected]
> Subject: Re: rw_match can address to memory after end of string buffer
>
[...]
>
> >> Hmm, that does look like a subtle bug in rw_match(). Let
> me look into
> >> how best to fix it.
>
> The commit below should fix it. I'm not 100% happy with the
> code and suspect there might still be some bugs lurking in
> there but if they are there the current test doesn't reveal
> them (even under Sun dbx with memory checking on) and none of
> the string tests is showing any signs of problems either.
> http://svn.apache.org/viewvc?rev=420363&view=rev
The bug with addressing after the end of string still present.
I updated the test 0.char.cpp to check this bug.
The diff file is attached.
ChangeLog:
* 0.char.cpp: (test_rw_match): the test strings allocated at
the protected memory to detect addressing after end of the string.
Farid.
Index: 0.char.cpp
===================================================================
--- 0.char.cpp (revision 429612)
+++ 0.char.cpp (working copy)
@@ -27,10 +27,35 @@
#include <rw_char.h>
#include <rw_printf.h>
#include <driver.h>
+#include <rw_alloc.h> // for rw_alloc(), rw_free()
#include <stdlib.h> // for free()
#include <string.h> // for memset(), size_t, strlen()
+#include <signal.h> // for signal()
+#include <setjmp.h> // for setjmp(), longjmp()
+#ifdef sigsetjmp
+#define SETJMP(env) sigsetjmp(env, 1)
+#else
+#define SETJMP(env) setjmp(env)
+#endif
+
+#define BEGIN_TEST_OVERRUN() \
+ (signal (SIGSEGV, sig_handler), \
+ (0 == SETJMP (mark)))
+
+static jmp_buf mark;
+
+extern "C" {
+
+static void
+sig_handler (int)
+{
+ longjmp (mark, -1);
+}
+
+}
+
/***********************************************************************/
static void
@@ -750,7 +775,15 @@
return 0;
}
+// using mymemcpy to hide g++ warning:
+// null argument where non-null required (argument 2)
+static inline void*
+mymemcpy (void* dst, const void* src, size_t count)
+{
+ return memcpy (dst, src, count);
+}
+
static void
test_rw_match ()
{
@@ -759,14 +792,43 @@
size_t result;
+#define IF_PREPARE_TEST(str1, size1, str2, size2, type) \
+ if (true) { \
+ const size_t sz1 = str1 ? size1 : 0; \
+ void* s1 = sz1 ? rw_alloc (sz1, RW_PROT_RDWR) : 0; \
+ RW_ASSERT (s1 && sz1 || !(s1 || sz1)); \
+ mymemcpy (s1, str1, sz1); \
+ size_t sz2 = str2 ? size2 : 0; \
+ void* s2 = sz2 ? rw_alloc (sz2, RW_PROT_RDWR) : 0; \
+ RW_ASSERT (s2 && sz2 || !(s2 || sz2)); \
+ mymemcpy (s2, str2, sz2); \
+ sz2 /= sizeof (type); \
+ if (BEGIN_TEST_OVERRUN ())
+
+#define CLEANUP_TEST() \
+ rw_free (s1); \
+ rw_free (s2); \
+ } \
+ else
+
#undef TEST
-#define TEST(s1, s2, len, expect) \
- result = rw_match ((const char*)s1, (const char*)s2, size_t (len)); \
- rw_assert (expect == result, \
- 0, __LINE__, \
- "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
- int (sizeof s1 - 1), s1, int (sizeof s2 - 1), s2, len, \
- expect, result)
+#define TEST(str1, str2, len, expect) \
+ IF_PREPARE_TEST(str1, sizeof (str1), str2, sizeof (str2), char) { \
+ result = rw_match ((const char*)s1, (const char*)s2, size_t (len)); \
+ rw_assert (expect == result, \
+ 0, __LINE__, \
+ "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
+ int (sz1 ? sz1 - 1 : 0), s1, \
+ int (sz2 ? sz2 - 1 : 0), s2, len, \
+ expect, result); \
+ } \
+ else \
+ rw_assert (0, 0, __LINE__, \
+ "rw_match(%{#*s}, %{#*s}, %zu) addressed after " \
+ "end of string", \
+ int (sz1 ? sz1 - 1 : 0), s1, \
+ int (sz2 ? sz2 - 1 : 0), s2, len); \
+ CLEANUP_TEST()
TEST (0, 0, -1, 0);
TEST ("", 0, -1, 0);
@@ -906,24 +968,53 @@
TEST ("A<UC1>@3A", "AAAAA", -1, 6);
TEST ("<UC1>@0<UC2>@1<UC3>@2<UC4>@3", "BCCDDD", -1, 7);
+
#else // unknown
rw_warn (0, 0, "unknown character set (neither ASCII nor EBCDIC)");
#endif
+#undef TEST
+#define TEST(ch1, ch2, expect) \
+ IF_PREPARE_TEST(&ch1, 1, &ch2, 1, char) { \
+ result = rw_match ((const char*)s1, (const char*)s2, 1); \
+ rw_assert (expect == result, \
+ 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%c\', 1) == %zu, got %zu", \
+ ch1, ch2, expect, result); \
+ } \
+ else \
+ rw_assert (0, 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%c\', 1) addressed after " \
+ "end of string", \
+ ch1, ch2); \
+ CLEANUP_TEST()
+
+ char ch = 'a';
+ TEST (ch, ch, 1);
+
//////////////////////////////////////////////////////////////////
rw_info (0, 0, 0, "rw_match(char*, const wchar_t*, size_t)");
#ifndef _RWSTD_NO_WCHAR_T
#undef TEST
-#define TEST(s1, s2, len, expect) \
- result = rw_match ((const char*)s1, (const wchar_t*)s2, size_t (len)); \
- rw_assert (expect == result, \
- 0, __LINE__, \
- "rw_match(%{#*s}, L%{#*ls}, %zu) == %zu, got %zu", \
- int (sizeof s1 - 1), s1, \
- int (sizeof (s2) / sizeof *(s2) - 1), s2, len, \
- expect, result)
+#define TEST(str1, str2, len, expect)
\
+ IF_PREPARE_TEST(str1, sizeof (str1), str2, sizeof (str2), wchar_t) {
\
+ result = rw_match ((const char*)s1, (const wchar_t*)s2, size_t (len));
\
+ rw_assert (expect == result,
\
+ 0, __LINE__,
\
+ "rw_match(%{#*s}, L%{#*ls}, %zu) == %zu, got %zu",
\
+ int (sz1 ? sz1 - 1 : 0), s1,
\
+ int (sz2 ? sz2 - 1 : 0), s2, len,
\
+ expect, result);
\
+ }
\
+ else
\
+ rw_assert (0, 0, __LINE__,
\
+ "rw_match(%{#*s}, L%{#*ls}, %zu) addressed after "
\
+ "end of string",
\
+ int (sz1 ? sz1 - 1 : 0), s1,
\
+ int (sz2 ? sz2 - 1 : 0), s2, len);
\
+ CLEANUP_TEST()
TEST (0, (wchar_t*)0, -1, 0);
TEST ("", (wchar_t*)0, -1, 0);
@@ -1009,6 +1100,25 @@
TEST ("[EMAIL PROTECTED]", L"[EMAIL PROTECTED]", -1, 4);
TEST ("[EMAIL PROTECTED]@c", L"[EMAIL PROTECTED]@c", -1, 6);
+#undef TEST
+#define TEST(ch1, ch2, expect) \
+ IF_PREPARE_TEST(&ch1, 1, &ch2, sizeof (wchar_t), wchar_t) { \
+ result = rw_match ((const char*)s1, (const wchar_t*)s2, 1); \
+ rw_assert (expect == result, \
+ 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%lc\', 1) == %zu, got %zu", \
+ ch1, ch2, expect, result); \
+ } \
+ else \
+ rw_assert (0, 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%lc\', 1) addressed after " \
+ "end of string", \
+ ch1, ch2); \
+ CLEANUP_TEST()
+
+ wchar_t wch = L'a';
+ TEST (ch, wch, 1);
+
#else // if defined (_RWSTD_NO_WCHAR_T)
rw_note (0, 0, 0, "_RWSTD_NO_WCHAR_T #defined, wchar_t test disabled");
@@ -1018,15 +1128,30 @@
//////////////////////////////////////////////////////////////////
rw_info (0, 0, 0, "rw_match(char*, const UserChar*, size_t)");
+ const UserChar* ustr;
+
#undef TEST
-#define TEST(s1, s2, len, expect) \
- result = rw_match ((const char*)s1, \
- make_user_string (s2, sizeof (s2)), size_t (len)); \
- rw_assert (expect == result, \
- 0, __LINE__, \
- "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
- int (sizeof s1 - 1), s1, int (sizeof s2 - 1), s2, len, \
- expect, result)
+#define TEST(str1, str2, len, expect)
\
+ ustr = make_user_string (str2, sizeof (str2));
\
+ IF_PREPARE_TEST(str1, sizeof (str1), ustr,
\
+ sizeof (str2) * sizeof (UserChar),
\
+ UserChar) {
\
+ result = rw_match ((const char*)s1,
\
+ (const UserChar*)s2, size_t (len));
\
+ rw_assert (expect == result,
\
+ 0, __LINE__,
\
+ "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu",
\
+ int (sz1 ? sz1 - 1 : 0), s1,
\
+ int (sz2 ? sz2 - 1 : 0), str2, len,
\
+ expect, result);
\
+ }
\
+ else
\
+ rw_assert (0, 0, __LINE__,
\
+ "rw_match(%{#*s}, %{#*s}, %zu) addressed after "
\
+ "end of string",
\
+ int (sz1 ? sz1 - 1 : 0), s1,
\
+ int (sz2 ? sz2 - 1 : 0), str2, len);
\
+ CLEANUP_TEST()
TEST (0, 0, -1, 0);
TEST ("", 0, -1, 0);
@@ -1053,6 +1178,8 @@
TEST ("a", "", -1, 0);
TEST ("a", "a", -1, 2);
+ //TEST (single_char, single_char, 1, 1);
+
// same as above but using the <char>@<count> directive
TEST ("[EMAIL PROTECTED]", "", -1, 0);
TEST ("[EMAIL PROTECTED]", "a", -1, 2);
@@ -1101,6 +1228,27 @@
// invalid directives
TEST ("[EMAIL PROTECTED]", "[EMAIL PROTECTED]", -1, 4);
TEST ("[EMAIL PROTECTED]@c", "[EMAIL PROTECTED]@c", -1, 6);
+
+ UserChar uch;
+
+#undef TEST
+#define TEST(ch1, ch2, expect) \
+ uch = make_char (ch2, (UserChar*)0); \
+ IF_PREPARE_TEST(&ch1, 1, &uch, sizeof (UserChar), UserChar) { \
+ result = rw_match ((const char*)s1, (const UserChar*)s2, 1); \
+ rw_assert (expect == result, \
+ 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%c\', 1) == %zu, got %zu", \
+ ch1, ch2, expect, result); \
+ } \
+ else \
+ rw_assert (0, 0, __LINE__, \
+ "rw_match(&\'%c\', &\'%c\', 1) addressed after " \
+ "end of string", \
+ ch1, ch2); \
+ CLEANUP_TEST()
+
+ TEST (ch, ch, 1);
}
/***********************************************************************/