Przeglądaj źródła

[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 7 lat temu
rodzic
commit
051a7b639e
2 zmienionych plików z 33 dodań i 5 usunięć
  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_IO_DEVICE EIO
 #define ERROR_INVALID_HANDLE EBADF
 #define ERROR_INVALID_HANDLE EBADF
 #define ERROR_ARITHMETIC_OVERFLOW EOVERFLOW
 #define ERROR_ARITHMETIC_OVERFLOW EOVERFLOW
+#define ERROR_INSUFFICIENT_BUFFER ENOBUFS
+#define ERROR_INVALID_PARAMETER EINVAL
 
 
 // Used by HRESULT <--> WIN32 error code conversion
 // Used by HRESULT <--> WIN32 error code conversion
 #define SEVERITY_ERROR 1
 #define SEVERITY_ERROR 1
@@ -841,7 +843,7 @@ public:
       return;
       return;
     }
     }
 
 
-    int len = wcslen(psz) * 4;
+    int len = (wcslen(psz) + 1) * 4;
     m_psz = new char[len];
     m_psz = new char[len];
     std::wcstombs(m_psz, psz, 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*/,
 int MultiByteToWideChar(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
                         const char *lpMultiByteStr, int cbMultiByte,
                         const char *lpMultiByteStr, int cbMultiByte,
                         wchar_t *lpWideCharStr, int cchWideChar) {
                         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
   // if cbMultiByte is -1, it indicates that lpMultiByteStr is null-terminated
   // and the entire string should be processed.
   // and the entire string should be processed.
   if (cbMultiByte == -1) {
   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));
     wchar_t *tempStr = (wchar_t *)malloc(cbMultiByte * sizeof(wchar_t));
     size_t requiredSize = mbstowcs(tempStr, lpMultiByteStr, cbMultiByte);
     size_t requiredSize = mbstowcs(tempStr, lpMultiByteStr, cbMultiByte);
     free(tempStr);
     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.
 // WideCharToMultiByte is a Windows-specific method.
@@ -54,6 +68,10 @@ int WideCharToMultiByte(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
                         bool * /*lpUsedDefaultChar*/) {
                         bool * /*lpUsedDefaultChar*/) {
   // if cchWideChar is -1, it indicates that lpWideCharStr is null-terminated
   // if cchWideChar is -1, it indicates that lpWideCharStr is null-terminated
   // and the entire string should be processed.
   // and the entire string should be processed.
+  if (cchWideChar == 0) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
   if (cchWideChar == -1) {
   if (cchWideChar == -1) {
     for (cchWideChar = 0; lpWideCharStr[cchWideChar] != '\0'; ++cchWideChar)
     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));
     char *tempStr = (char *)malloc(cchWideChar * sizeof(char));
     size_t requiredSize = wcstombs(tempStr, lpWideCharStr, cchWideChar);
     size_t requiredSize = wcstombs(tempStr, lpWideCharStr, cchWideChar);
     free(tempStr);
     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
 #endif // _WIN32