> -----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);
 }
 
 /***********************************************************************/

Reply via email to