The initial patch does not pass the following test case. Have re-worked the patch and attached it to the incident, and I am also attaching it here. It passes all collate tests.

Here is the second test case:

$ cat ../../tests/localization/t.cpp; nice make t.cpp && ./t af_ZA.utf8; echo $?
#include <iostream>
#include <locale>
#include <string>

int
main (int argc, char** argv)
{
    std::locale loc (argv [1]);

    const std::collate< char >& fac =
        std::use_facet< std::collate< char > > (loc);

    char const buf [] = "a\0\0b";
    std::string s = fac.transform (buf, buf + sizeof buf - 1);

    size_t i = 0;
    for (; i < s.size () && 0 == s [i]; ++i) ;

    return !(i == 2);
}
1

On 10/10/12 08:25, Liviu Nicoara wrote:
2012-10-10  Liviu Nicoara  <lnico...@apache.org>

     * src/collate.cpp (__rw_strnxfrm): preserved embedded NULs


Index: src/collate.cpp
===================================================================
--- src/collate.cpp     (revision 1397825)
+++ src/collate.cpp     (working copy)
@@ -480,113 +480,103 @@
 {
     _STD::string res;
 
-    char buf [256];
-    char *pbuf = buf;
-
+    char buf [256], *pbuf = buf, *psrc = buf;
     size_t bufsize = sizeof buf;
-    char *psrc = buf;
 
     while (nchars) {
 
-        // using a C-style cast instead of static_cast to avoid
-        // a gcc 2.95.2 bug causing an error on some platforms:
-        //   static_cast from `void *' to `const char *'
-        const char* const last = (const char*)memchr (src, '\0', nchars);
-
-        if (0 == last) {
-
-            // no NUL found in the initial portion of the source string
-            // that fits into the local temporary buffer; copy as many
-            // characters as fit into the buffer
+        if (src [0]) {
 
-            if (bufsize <= nchars) {
-                if (pbuf != buf)
-                    delete[] pbuf;
-                pbuf = new char [nchars + 1];
+            // using a C-style cast instead of static_cast to avoid
+            // a gcc 2.95.2 bug causing an error on some platforms:
+            //   static_cast from `void *' to `const char *'
+            const char* const last = (const char*)memchr (src, '\0', nchars);
+
+            if (0 == last) {
+                // no NUL found in the initial portion of the source string
+                // that fits into the local temporary buffer; copy as many
+                // characters as fit into the buffer
+
+                if (bufsize <= nchars) {
+                    if (pbuf != buf)
+                        delete[] pbuf;
+                    pbuf = new char [nchars + 1];
+                }
+
+                psrc = pbuf;
+                memcpy (psrc, src, nchars);
+
+                // append a terminating NUL and decrement the number
+                // of characters that remain to be processed
+                psrc [nchars] = '\0';
+                src          += nchars;
+                nchars        = 0;
+            }
+            else {
+                // terminating NUL found in the source buffer
+                nchars -= (last - src) + 1;
+                psrc    = _RWSTD_CONST_CAST (char*, src);
+                src    += (last - src) + 1;
             }
 
-            psrc = pbuf;
-            memcpy (psrc, src, nchars);
+#ifdef _RWSTD_OS_SUNOS
+            // Solaris 10u5 on AMD64 overwrites memory past the end of
+            // just_in_case_buf[8], to avoid this, pass a null pointer
+            char* const just_in_case_buf = 0;
+#else
+            // provide a destination buffer to strxfrm() in case
+            // it's buggy (such as MSVC's) and tries to write to
+            // the buffer even if it's 0
+            char just_in_case_buf [8];
+#endif // _RWSTD_OS_SUNOS
 
-            // append a terminating NUL and decrement the number
-            // of characters that remain to be processed
-            psrc [nchars] = '\0';
-            src          += nchars;
-            nchars        = 0;
-        }
-        else {
+            const size_t dst_size = strxfrm (just_in_case_buf, psrc, 0);
 
-            // terminating NUL found in the source buffer
-            nchars -= (last - src) + 1;
-            psrc    = _RWSTD_CONST_CAST (char*, src);
-            src    += (last - src) + 1;
-        }
+            // check for strxfrm() errors
+            if (0 == (dst_size << 1)) {
+                if (pbuf != buf)
+                    delete[] pbuf;
 
-#ifdef _RWSTD_OS_SUNOS
-        // Solaris 10u5 on AMD64 overwrites memory past the end of
-        // just_in_case_buf[8], to avoid this, pass a null pointer
-        char* const just_in_case_buf = 0;
-#else
-        // provide a destination buffer to strxfrm() in case
-        // it's buggy (such as MSVC's) and tries to write to
-        // the buffer even if it's 0
-        char just_in_case_buf [8];
-#endif
-
-        const size_t dst_size = strxfrm (just_in_case_buf, psrc, 0);
-
-        // check for strxfrm() errors
-        if (0 == (dst_size << 1)) {
-            if (pbuf != buf)
-                delete[] pbuf;
+                return _STD::string ();
+            }
 
-            return _STD::string ();
-        }
+            size_t res_size = res.size ();
 
-        size_t res_size = res.size ();
+            _TRY {
+                // resize the result string to fit itself plus the result
+                // of the transformation including the terminating NUL
+                // appended by strxfrm()
+                res.resize (res_size + dst_size + 1);
+            }
+            _CATCH (...) {
+                if (pbuf != buf)
+                    delete[] pbuf;
+                _RETHROW;
+            }
 
-        _TRY {
-            // resize the result string to fit itself plus the result
-            // of the transformation including the terminatin NUL
-            // appended by strxfrm()
-            res.resize (res_size + dst_size + 1);
-        }
-        _CATCH (...) {
-            if (pbuf != buf)
-                delete[] pbuf;
-            _RETHROW;
+            strxfrm (&res [0] + res_size, psrc, dst_size + 1);
         }
+        else {
 
-        // transfor the source string up to the terminating NUL
-        size_t xfrm_size =
-            strxfrm (&res [0] + res_size, psrc, dst_size + 1);
+            // count and append the consecutive NULs embedded in the 
+            // input string
 
-#if defined _MSC_VER && _MSC_VER < 1400
-        // compute the correct value that should have been returned from
-        // strxfrm() after the transformation has completed (MSVC strxfrm()
-        // returns a bogus result; see PR #29935)
-        xfrm_size = strlen (&res [0] + res_size);
-#endif   // MSVC < 8.0
-
-        // increment the size of the result string by the number
-        // of transformed characters excluding the terminating NUL
-        // if strxfrm() transforms the empty string into the empty
-        // string, keep the terminating NUL, otherwise drop it
-        res_size += xfrm_size + (last && !*psrc && !xfrm_size);
+            size_t i = 0;
+            for (; i < nchars && 0 == src [i]; ++i) ;
 
-        _TRY {
-            res.resize (res_size);
-        }
-        _CATCH (...) {
-            if (pbuf != buf)
-                delete[] pbuf;
-            _RETHROW;
+            res.resize (res.size () + i);
+
+            nchars -= i;
+            src += i;
         }
     }
 
     if (pbuf != buf)
         delete[] pbuf;
 
+    if (!res.empty ())
+        res.resize (res.size () - 1);
+
     return res;
 }
 

Reply via email to