Quellcode durchsuchen

[linux-port] Correct char convert size in/out (#1411)

MultiByteToWideChar and WideCharToMultiByte were returning -1 on
failure, which caused failures to be ignored. When successful, they
were returning the number of characters converted excluding the
terminating null character because that's what the std:: functions
used for the implementation do. Both are inconsistent with the
original Windows implementations.

Simply adding one to the return value works in all cases save those
where the number of characters converted was limited by the parameter
In this case, the number of characters converted doesn't include
the terminating null. So no addition is warrented.

Added addition errors in keeping with the function descriptions.

The CW2A conversion class left out the terminating null character
when calculating the max size of the converted string.
Greg Roth vor 7 Jahren
Ursprung
Commit
051a7b639e
2 geänderte Dateien mit 33 neuen und 5 gelöschten Zeilen
  1. 3 1
      include/dxc/Support/WinAdapter.h
  2. 30 4
      lib/DxcSupport/Unicode.cpp

+ 3 - 1
include/dxc/Support/WinAdapter.h

@@ -111,6 +111,8 @@
 #define ERROR_IO_DEVICE EIO
 #define ERROR_INVALID_HANDLE EBADF
 #define ERROR_ARITHMETIC_OVERFLOW EOVERFLOW
+#define ERROR_INSUFFICIENT_BUFFER ENOBUFS
+#define ERROR_INVALID_PARAMETER EINVAL
 
 // Used by HRESULT <--> WIN32 error code conversion
 #define SEVERITY_ERROR 1
@@ -841,7 +843,7 @@ public:
       return;
     }
 
-    int len = wcslen(psz) * 4;
+    int len = (wcslen(psz) + 1) * 4;
     m_psz = new char[len];
     std::wcstombs(m_psz, psz, len);
   }

+ 30 - 4
lib/DxcSupport/Unicode.cpp

@@ -24,6 +24,12 @@
 int MultiByteToWideChar(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
                         const char *lpMultiByteStr, int cbMultiByte,
                         wchar_t *lpWideCharStr, int cchWideChar) {
+
+  if (cbMultiByte == 0) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
+
   // if cbMultiByte is -1, it indicates that lpMultiByteStr is null-terminated
   // and the entire string should be processed.
   if (cbMultiByte == -1) {
@@ -38,10 +44,18 @@ int MultiByteToWideChar(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
     wchar_t *tempStr = (wchar_t *)malloc(cbMultiByte * sizeof(wchar_t));
     size_t requiredSize = mbstowcs(tempStr, lpMultiByteStr, cbMultiByte);
     free(tempStr);
-    return requiredSize;
+    if (requiredSize == (size_t)cbMultiByte) return requiredSize;
+    return requiredSize + 1;
+  }
+
+  if (cchWideChar < cbMultiByte) {
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return 0;
   }
 
-  return mbstowcs(lpWideCharStr, lpMultiByteStr, cbMultiByte);
+  size_t rv = mbstowcs(lpWideCharStr, lpMultiByteStr, cbMultiByte);
+  if (rv == (size_t)cbMultiByte) return rv;
+  return rv + 1; // mbstowcs excludes the terminating character
 }
 
 // WideCharToMultiByte is a Windows-specific method.
@@ -54,6 +68,10 @@ int WideCharToMultiByte(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
                         bool * /*lpUsedDefaultChar*/) {
   // if cchWideChar is -1, it indicates that lpWideCharStr is null-terminated
   // and the entire string should be processed.
+  if (cchWideChar == 0) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
   if (cchWideChar == -1) {
     for (cchWideChar = 0; lpWideCharStr[cchWideChar] != '\0'; ++cchWideChar)
       ;
@@ -66,10 +84,18 @@ int WideCharToMultiByte(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
     char *tempStr = (char *)malloc(cchWideChar * sizeof(char));
     size_t requiredSize = wcstombs(tempStr, lpWideCharStr, cchWideChar);
     free(tempStr);
-    return requiredSize;
+    if (requiredSize == (size_t)cchWideChar) return requiredSize;
+    return requiredSize + 1;
+  }
+
+  if (cbMultiByte < cchWideChar) {
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return 0;
   }
 
-  return wcstombs(lpMultiByteStr, lpWideCharStr, cchWideChar);
+  size_t rv = wcstombs(lpMultiByteStr, lpWideCharStr, cchWideChar);
+  if (rv == (size_t)cchWideChar) return rv;
+  return rv + 1; // mbstowcs excludes the terminating character
 }
 #endif // _WIN32