Juan Lang : oleaut32: Correctly handle NULLs embedded in BSTRs, with tests.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Jun 22 06:17:05 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: 2a0c37d8b99f2c1aae3bf988588cac095e78048d
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=2a0c37d8b99f2c1aae3bf988588cac095e78048d

Author: Juan Lang <juan_lang at yahoo.com>
Date:   Wed Jun 21 23:56:58 2006 +0200

oleaut32: Correctly handle NULLs embedded in BSTRs, with tests.

---

 dlls/oleaut32/tests/vartype.c |  109 ++++++++++++++++++++++++++++++++++++++---
 dlls/oleaut32/vartype.c       |   29 ++++++++---
 2 files changed, 122 insertions(+), 16 deletions(-)

diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c
index 347b256..5e2de4d 100644
--- a/dlls/oleaut32/tests/vartype.c
+++ b/dlls/oleaut32/tests/vartype.c
@@ -4898,8 +4898,8 @@ #undef BSTR_DEC64
 #define _VARBSTRCMP(left,right,lcid,flags,result) \
         hres = pVarBstrCmp(left,right,lcid,flags); \
         ok(hres == result, "VarBstrCmp: expected " #result ", got hres=0x%lx\n", hres)
-#define VARBSTRCMP(left,right,result) \
-        _VARBSTRCMP(left,right,lcid,0,result)
+#define VARBSTRCMP(left,right,flags,result) \
+        _VARBSTRCMP(left,right,lcid,flags,result)
 
 static void test_VarBstrCmp(void)
 {
@@ -4907,7 +4907,11 @@ static void test_VarBstrCmp(void)
     HRESULT hres;
     static const WCHAR sz[] = {'W','u','r','s','c','h','t','\0'};
     static const WCHAR szempty[] = {'\0'};
-    BSTR bstr, bstrempty;
+    static const WCHAR sz1[] = { 'a',0 };
+    static const WCHAR sz2[] = { 'A',0 };
+    static const WCHAR s1[] = { 'a',0 };
+    static const WCHAR s2[] = { 'a',0,'b' };
+    BSTR bstr, bstrempty, bstr2;
 
     CHECKPTR(VarBstrCmp);
     
@@ -4916,13 +4920,34 @@ static void test_VarBstrCmp(void)
     bstrempty = SysAllocString(szempty);
     
     /* NULL handling. Yepp, MSDN is totaly wrong here */
-    VARBSTRCMP(NULL,NULL,VARCMP_EQ);
-    VARBSTRCMP(bstr,NULL,VARCMP_GT);
-    VARBSTRCMP(NULL,bstr,VARCMP_LT);
+    VARBSTRCMP(NULL,NULL,0,VARCMP_EQ);
+    VARBSTRCMP(bstr,NULL,0,VARCMP_GT);
+    VARBSTRCMP(NULL,bstr,0,VARCMP_LT);
 
     /* NULL and empty string comparisions */
-    VARBSTRCMP(bstrempty,NULL,VARCMP_EQ);
-    VARBSTRCMP(NULL,bstrempty,VARCMP_EQ);
+    VARBSTRCMP(bstrempty,NULL,0,VARCMP_EQ);
+    VARBSTRCMP(NULL,bstrempty,0,VARCMP_EQ);
+
+    SysFreeString(bstr);
+    bstr = SysAllocString(sz1);
+
+    bstr2 = SysAllocString(sz2);
+    VARBSTRCMP(bstr,bstr2,0,VARCMP_LT);
+    VARBSTRCMP(bstr,bstr2,NORM_IGNORECASE,VARCMP_EQ);
+    SysFreeString(bstr2);
+    /* These two strings are considered equal even though one is
+     * NULL-terminated and the other not.
+     */
+    bstr2 = SysAllocStringLen(s1, sizeof(s1) / sizeof(WCHAR));
+    VARBSTRCMP(bstr,bstr2,0,VARCMP_EQ);
+    SysFreeString(bstr2);
+
+    /* These two strings are not equal */
+    bstr2 = SysAllocStringLen(s2, sizeof(s2) / sizeof(WCHAR));
+    VARBSTRCMP(bstr,bstr2,0,VARCMP_LT);
+    SysFreeString(bstr2);
+
+    SysFreeString(bstr);
 }
 
 /* Get the internal representation of a BSTR */
@@ -5175,6 +5200,73 @@ static void test_BstrCopy(void)
   }
 }
 
+static void test_VarBstrCat(void)
+{
+    static const WCHAR sz1[] = { 'a',0 };
+    static const WCHAR sz2[] = { 'b',0 };
+    static const WCHAR sz1sz2[] = { 'a','b',0 };
+    static const WCHAR s1[] = { 'a',0 };
+    static const WCHAR s2[] = { 'b',0 };
+    static const WCHAR s1s2[] = { 'a',0,'b',0 };
+    HRESULT ret;
+    BSTR str1, str2, res;
+
+    /* Crash
+    ret = VarBstrCat(NULL, NULL, NULL);
+     */
+
+    /* Concatenation of two NULL strings works */
+    ret = VarBstrCat(NULL, NULL, &res);
+    ok(ret == S_OK, "VarBstrCat failed: %08lx\n", ret);
+    ok(res != NULL, "Expected a string\n");
+    ok(SysStringLen(res) == 0, "Expected a 0-length string\n");
+    SysFreeString(res);
+
+    str1 = SysAllocString(sz1);
+
+    /* Concatenation with one NULL arg */
+    ret = VarBstrCat(NULL, str1, &res);
+    ok(ret == S_OK, "VarBstrCat failed: %08lx\n", ret);
+    ok(res != NULL, "Expected a string\n");
+    ok(SysStringLen(res) == SysStringLen(str1), "Unexpected length\n");
+    ok(!memcmp(res, sz1, SysStringLen(str1)), "Unexpected value\n");
+    SysFreeString(res);
+    ret = VarBstrCat(str1, NULL, &res);
+    ok(ret == S_OK, "VarBstrCat failed: %08lx\n", ret);
+    ok(res != NULL, "Expected a string\n");
+    ok(SysStringLen(res) == SysStringLen(str1), "Unexpected length\n");
+    ok(!memcmp(res, sz1, SysStringLen(str1)), "Unexpected value\n");
+    SysFreeString(res);
+
+    /* Concatenation of two zero-terminated strings */
+    str2 = SysAllocString(sz2);
+    ret = VarBstrCat(str1, str2, &res);
+    ok(ret == S_OK, "VarBstrCat failed: %08lx\n", ret);
+    ok(res != NULL, "Expected a string\n");
+    ok(SysStringLen(res) == sizeof(sz1sz2) / sizeof(WCHAR) - 1,
+     "Unexpected length\n");
+    ok(!memcmp(res, sz1sz2, sizeof(sz1sz2)), "Unexpected value\n");
+    SysFreeString(res);
+
+    SysFreeString(str2);
+    SysFreeString(str1);
+
+    /* Concatenation of two strings with embedded NULLs */
+    str1 = SysAllocStringLen(s1, sizeof(s1) / sizeof(WCHAR));
+    str2 = SysAllocStringLen(s2, sizeof(s2) / sizeof(WCHAR));
+
+    ret = VarBstrCat(str1, str2, &res);
+    ok(ret == S_OK, "VarBstrCat failed: %08lx\n", ret);
+    ok(res != NULL, "Expected a string\n");
+    ok(SysStringLen(res) == sizeof(s1s2) / sizeof(WCHAR),
+     "Unexpected length\n");
+    ok(!memcmp(res, s1s2, sizeof(s1s2)), "Unexpected value\n");
+    SysFreeString(res);
+
+    SysFreeString(str2);
+    SysFreeString(str1);
+}
+
 /* IUnknown */
 
 static void test_IUnknownClear(void)
@@ -5940,6 +6032,7 @@ START_TEST(vartype)
   test_SysReAllocString();
   test_SysReAllocStringLen();
   test_BstrCopy();
+  test_VarBstrCat();
 
   test_IUnknownClear();
   test_IUnknownCopy();
diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c
index e08a7c0..519c9e0 100644
--- a/dlls/oleaut32/vartype.c
+++ b/dlls/oleaut32/vartype.c
@@ -6584,27 +6584,31 @@ HRESULT WINAPI VarBstrFromDisp(IDispatch
  */
 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
 {
-  unsigned int len;
+  unsigned int lenLeft, lenRight;
+
+  TRACE("%s,%s,%p\n",
+   debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
+   debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
 
   if (!pbstrOut)
     return E_INVALIDARG;
 
-  len = pbstrLeft ? strlenW(pbstrLeft) : 0;
-  if (pbstrRight)
-    len += strlenW(pbstrRight);
+  lenLeft = pbstrLeft ? SysStringLen(pbstrLeft) : 0;
+  lenRight = pbstrRight ? SysStringLen(pbstrRight) : 0;
 
-  *pbstrOut = SysAllocStringLen(NULL, len);
+  *pbstrOut = SysAllocStringLen(NULL, lenLeft + lenRight);
   if (!*pbstrOut)
     return E_OUTOFMEMORY;
 
   (*pbstrOut)[0] = '\0';
 
   if (pbstrLeft)
-    strcpyW(*pbstrOut, pbstrLeft);
+    memcpy(*pbstrOut, pbstrLeft, lenLeft * sizeof(WCHAR));
 
   if (pbstrRight)
-    strcatW(*pbstrOut, pbstrRight);
+    memcpy(*pbstrOut + lenLeft, pbstrRight, lenRight * sizeof(WCHAR));
 
+  TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
   return S_OK;
 }
 
@@ -6629,6 +6633,12 @@ HRESULT WINAPI VarBstrCat(BSTR pbstrLeft
  */
 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
 {
+    HRESULT hres;
+
+    TRACE("%s,%s,%ld,%08lx\n",
+     debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
+     debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
+
     if (!pbstrLeft || !*pbstrLeft)
     {
       if (!pbstrRight || !*pbstrRight)
@@ -6638,7 +6648,10 @@ HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft
     else if (!pbstrRight || !*pbstrRight)
         return VARCMP_GT;
 
-    return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
+    hres = CompareStringW(lcid, dwFlags, pbstrLeft, SysStringLen(pbstrLeft),
+            pbstrRight, SysStringLen(pbstrRight)) - 1;
+    TRACE("%ld\n", hres);
+    return hres;
 }
 
 /*




More information about the wine-cvs mailing list