Fix the ntstrsafe.h tests to make sense, actually succeed using ntstrsafe.h from...
authorColin Finck <colin@reactos.org>
Wed, 28 Aug 2019 20:42:52 +0000 (22:42 +0200)
committerColin Finck <colin@reactos.org>
Wed, 28 Aug 2019 20:42:52 +0000 (22:42 +0200)
modules/rostests/kmtests/rtl/RtlStrSafe.c
sdk/include/ddk/ntstrsafe.h

index 807a036..82c2fe5 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * PROJECT:         ReactOS kernel-mode tests
- * LICENSE:         GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
  * PURPOSE:         Test for ntstrsafe.h functions
  * COPYRIGHT:       Copyright 2018 HernĂ¡n Di Pietro <hernan.di.pietro@gmail.com>
+ *                  Copyright 2019 Colin Finck <colin@reactos.org>
  */
 
 #define KMT_EMULATE_KERNEL
 
 #define TESTAPI static void
 
+static const WCHAR FormatStringInts[] = L"%d %d %d";
+static const WCHAR FormatStringIntsResult[] = L"1 2 3";
+static const WCHAR FormatStringStrs[] = L"%s %s %s";
+
+
 TESTAPI
 Test_RtlUnicodeStringPrintf()
 {
-    WCHAR Buffer[1024];
-    WCHAR OvrBuffer[1024];
-    WCHAR BufferSmall[2];
-    WCHAR BufferSmall2[7];
+    NTSTATUS Status;
+    PWSTR pBuffer = NULL;
+    size_t BufferSize;
+    size_t EqualBytes;
     UNICODE_STRING UsString;
-    const WCHAR FormatStringInts[] = L"%d %d %d";
-    const WCHAR FormatStringStrs[] = L"%s %s %s";
-    const WCHAR Result[] = L"1 2 3";
-    UNICODE_STRING UsStringNull;
 
-    /* No zeros (Don't assume UNICODE_STRINGS are NULL terminated) */
-
-    RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
-    RtlFillMemory(BufferSmall, sizeof(BufferSmall), 0xAA);
-    RtlFillMemory(BufferSmall2, sizeof(BufferSmall2), 0xAA);
+    KmtStartSeh();
 
     /* STATUS_SUCCESS test */
+    BufferSize = 6 * sizeof(WCHAR);
+    pBuffer = KmtAllocateGuarded(BufferSize);
+    if (!pBuffer)
+        goto Cleanup;
+
+    RtlFillMemory(pBuffer, BufferSize, 0xAA);
+    RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
+
+    Status = RtlUnicodeStringPrintf(&UsString, FormatStringInts, 1, 2, 3);
+    EqualBytes = RtlCompareMemory(UsString.Buffer, FormatStringIntsResult, sizeof(FormatStringIntsResult));
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    ok_eq_size(EqualBytes, sizeof(FormatStringIntsResult));
+    ok_eq_uint(UsString.Length, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
+    ok_eq_uint(UsString.MaximumLength, BufferSize);    
+
+    KmtFreeGuarded(pBuffer);
+    pBuffer = NULL;
 
-    UsString.Buffer = Buffer;
-    UsString.Length = 0;
-    UsString.MaximumLength = sizeof(Buffer);
-
-    ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringInts, 1, 2, 3), STATUS_SUCCESS);
-    ok_eq_uint(UsString.Length, sizeof(Result) - sizeof(WCHAR));
-    ok_eq_uint(UsString.MaximumLength, sizeof(Buffer));
-    ok_eq_wchar(UsString.Buffer[0], L'1');
-    ok_eq_wchar(UsString.Buffer[1], L' ');
-    ok_eq_wchar(UsString.Buffer[2], L'2');
-    ok_eq_wchar(UsString.Buffer[3], L' ');
-    ok_eq_wchar(UsString.Buffer[4], L'3');
-    ok_eq_wchar(UsString.Buffer[5], (WCHAR) 0);
-    
     /* STATUS_BUFFER_OVERFLOW tests */
+    BufferSize = 2 * sizeof(WCHAR);
+    pBuffer = KmtAllocateGuarded(BufferSize);
+    if (!pBuffer)
+        goto Cleanup;
 
-    UsString.Buffer = BufferSmall;
-    UsString.Length = 0;
-    UsString.MaximumLength = sizeof(BufferSmall);
-    
-    ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_BUFFER_OVERFLOW);
+    RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
+
+    Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC");
+    EqualBytes = RtlCompareMemory(UsString.Buffer, L"AA", BufferSize);
+    ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
+    ok_eq_size(EqualBytes, BufferSize);
     ok_eq_uint(UsString.Length, UsString.MaximumLength);
-    ok_eq_char(UsString.Buffer[0], L'A');
-    ok_eq_char(UsString.Buffer[1], (WCHAR)0);
 
-    UsString.Buffer = BufferSmall2;
-    UsString.Length = 0;
-    UsString.MaximumLength = sizeof(BufferSmall2);
+    KmtFreeGuarded(pBuffer);
+    pBuffer = NULL;
+
 
-    ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"0123", L"4567", L"89AB"), STATUS_BUFFER_OVERFLOW);
+    BufferSize = 7 * sizeof(WCHAR);
+    pBuffer = KmtAllocateGuarded(BufferSize);
+    if (!pBuffer)
+        goto Cleanup;
+
+    RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
+
+    Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"0123", L"4567", L"89AB");
+    EqualBytes = RtlCompareMemory(UsString.Buffer, L"0123 45", BufferSize);
+    ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
+    ok_eq_size(EqualBytes, BufferSize);
     ok_eq_uint(UsString.Length, UsString.MaximumLength);
-    ok_eq_char(UsString.Buffer[0], L'0');
-    ok_eq_char(UsString.Buffer[1], L'1');
-    ok_eq_char(UsString.Buffer[2], L'2');
-    ok_eq_char(UsString.Buffer[3], L'3');
-    ok_eq_char(UsString.Buffer[4], L' ');
-    ok_eq_char(UsString.Buffer[5], L'4');
-    ok_eq_char(UsString.Buffer[6], (WCHAR) 0);
-
-    ///* STATUS_INVALID_PARAMETER tests */
-
-    ok_eq_hex(RtlUnicodeStringPrintf(NULL, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
-    ok_eq_hex(RtlUnicodeStringPrintf(&UsString, NULL, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
-
-    UsStringNull.Buffer = (PWCH)NULL;
-    UsStringNull.Length = 0;
-    UsStringNull.MaximumLength = 0;
-    ok_eq_bool(RtlUnicodeStringPrintf(&UsStringNull, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_INVALID_PARAMETER);
-
-    /* Test  for buffer overruns */
-
-    RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
-    RtlFillMemory(OvrBuffer, sizeof(OvrBuffer), 0xAA);
-    UsString.Buffer = Buffer;
-    UsString.Length = 0;
-    UsString.MaximumLength = 16 * sizeof(WCHAR);
-
-    ok_eq_hex(RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"abc", L"def", L"ghi"), STATUS_SUCCESS);
-    ok_eq_uint(UsString.Length, sizeof(L"abc def ghi") -sizeof(WCHAR));
-    ok_eq_char(UsString.Buffer[11], (WCHAR)0);
-    ok_eq_uint(0, memcmp(OvrBuffer + 12, Buffer + 12, sizeof(Buffer) - (12 * sizeof(WCHAR))));
+
+    KmtFreeGuarded(pBuffer);
+    pBuffer = NULL;
+
+    // Note: RtlUnicodeStringPrintf returns STATUS_BUFFER_OVERFLOW here while RtlUnicodeStringPrintfEx returns STATUS_INVALID_PARAMETER!
+    // Documented on MSDN and verified with the Win10 version of ntstrsafe.h
+    RtlInitEmptyUnicodeString(&UsString, NULL, 0);
+    Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC");
+    ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
+
+
+Cleanup:
+    if (pBuffer)
+        KmtFreeGuarded(pBuffer);
+
+    // None of these functions should have crashed.
+    KmtEndSeh(STATUS_SUCCESS);
 }
 
 TESTAPI
 Test_RtlUnicodeStringPrintfEx()
 {
-    WCHAR Buffer[32];
-    WCHAR BufferSmall[8] = { 0 };
-    WCHAR OvrBuffer[1024];
-    UNICODE_STRING UsString, RemString;
-    const WCHAR FormatStringInts[] = L"%d %d %d";
-    const WCHAR FormatStringStrs[] = L"%s %s %s";
-    const WCHAR Result[] = L"1 2 3";
+    NTSTATUS Status;
+    PWSTR pBuffer = NULL;
+    size_t BufferSize;
+    size_t EqualBytes;
+    UNICODE_STRING RemString;
+    UNICODE_STRING UsString;
+    WCHAR FillResult[10];
 
-    /* No zeros (Don't assume UNICODE_STRINGS are NULL terminated) */
+    RtlFillMemory(FillResult, sizeof(FillResult), 0xAA);
 
-    RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
+    KmtStartSeh();
 
-    UsString.Buffer = Buffer;
-    UsString.Length = 0;
-    UsString.MaximumLength = sizeof(Buffer);
+    /* STATUS_SUCCESS test, fill behind flag: low-byte as fill character */
+    BufferSize = sizeof(FormatStringIntsResult) - sizeof(UNICODE_NULL) + sizeof(FillResult);
+    pBuffer = KmtAllocateGuarded(BufferSize);
+    if (!pBuffer)
+        goto Cleanup;
+
+    RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
+    RtlInitEmptyUnicodeString(&RemString, NULL, 0);
+
+    Status = RtlUnicodeStringPrintfEx(&UsString, &RemString, STRSAFE_FILL_BEHIND | 0xAA, FormatStringInts, 1, 2, 3);
+    EqualBytes = RtlCompareMemory(UsString.Buffer, FormatStringIntsResult, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    ok_eq_size(EqualBytes, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
+    ok_eq_uint(UsString.Length, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
+    ok_eq_uint(UsString.MaximumLength, BufferSize);
+
+    ok_eq_pointer(RemString.Buffer, &UsString.Buffer[UsString.Length / sizeof(WCHAR)]);
+    ok_eq_uint(RemString.Length, 0);
+    ok_eq_uint(RemString.MaximumLength, UsString.MaximumLength - UsString.Length);
 
-    RemString.Buffer = (PWCH)NULL;
-    RemString.Length = 0;
-    RemString.MaximumLength = 0;
+    EqualBytes = RtlCompareMemory(RemString.Buffer, FillResult, RemString.MaximumLength);
+    ok_eq_size(EqualBytes, sizeof(FillResult));
+
+    KmtFreeGuarded(pBuffer);
+    pBuffer = NULL;
 
-    /* STATUS_SUCCESS test, fill behind flag: low-byte as fill character */
 
-    ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, STRSAFE_FILL_BEHIND | 0xFF, FormatStringInts, 1, 2, 3), STATUS_SUCCESS);
-    
-    ok_eq_uint(UsString.Length, sizeof(Result) - sizeof(WCHAR));
-    ok_eq_uint(UsString.MaximumLength, sizeof(Buffer));
-    ok_eq_uint(memcmp(UsString.Buffer, Result, sizeof(Result) - sizeof(WCHAR)), 0);
+    /* STATUS_BUFFER_OVERFLOW test  */
+    BufferSize = 8 * sizeof(WCHAR);
+    pBuffer = KmtAllocateGuarded(BufferSize);
+    if (!pBuffer)
+        goto Cleanup;
+
+    RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
+    RtlInitEmptyUnicodeString(&RemString, NULL, 0);
+
+    Status = RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC");
+    EqualBytes = RtlCompareMemory(UsString.Buffer, L"AAA BBB ", UsString.Length);
+    ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
+    ok_eq_size(EqualBytes, UsString.Length);
+    ok_eq_uint(UsString.Length, UsString.MaximumLength);
 
-    ok_eq_pointer(RemString.Buffer, UsString.Buffer + (UsString.Length / sizeof(WCHAR)));
+    ok_eq_pointer(RemString.Buffer, &UsString.Buffer[UsString.Length / sizeof(WCHAR)]);
     ok_eq_uint(RemString.Length, 0);
-    ok_eq_uint(RemString.MaximumLength, UsString.MaximumLength - UsString.Length);
+    ok_eq_uint(RemString.MaximumLength, 0);
 
-    /* STATUS_BUFFER_OVERFLOW test  */
+    KmtFreeGuarded(pBuffer);
+    pBuffer = NULL;
 
-    UsString.Buffer = BufferSmall;
-    UsString.Length = 0;
-    UsString.MaximumLength = sizeof(BufferSmall);
 
-    RemString.Buffer = (PWCH)NULL;
-    RemString.Length = 0;
-    RemString.MaximumLength = 0;
-    
-    ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC"), STATUS_BUFFER_OVERFLOW);
-    ok_eq_uint(UsString.Length, UsString.MaximumLength);
-    ok_eq_char(UsString.Buffer[0], L'A');
-    ok_eq_char(UsString.Buffer[1], L'A');
-    ok_eq_char(UsString.Buffer[2], L'A');
-    ok_eq_char(UsString.Buffer[3], L' ');
-    ok_eq_char(UsString.Buffer[4], L'B');
-    ok_eq_char(UsString.Buffer[5], L'B');
-    ok_eq_char(UsString.Buffer[6], L'B');
-    ok_eq_char(UsString.Buffer[7], (WCHAR)0);
-
-    // Takes \0 into account
-    ok_eq_pointer(RemString.Buffer, UsString.Buffer + (UsString.Length - 1) / sizeof(WCHAR));
-    ok_eq_uint(RemString.Length, 0); 
-    ok_eq_uint(RemString.MaximumLength, 2);
-
-    /* Test  for buffer overruns */
-
-    RtlFillMemory(Buffer, sizeof(Buffer), 0xAA);
-    RtlFillMemory(OvrBuffer, sizeof(OvrBuffer), 0xAA);
-    UsString.Buffer = Buffer;
-    UsString.Length = 0;
-    UsString.MaximumLength = 16 * sizeof(WCHAR);
-
-    ok_eq_hex(RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"abc", L"def", L"ghi"), STATUS_SUCCESS);
-    ok_eq_uint(UsString.Length, sizeof(L"abc def ghi") - sizeof(WCHAR));
-    ok_eq_char(UsString.Buffer[11], (WCHAR)0);
-    ok_eq_uint(0, memcmp(OvrBuffer + 12, Buffer + 12, sizeof(Buffer) - (12 * sizeof(WCHAR))));
+    // Note: RtlUnicodeStringPrintf returns STATUS_BUFFER_OVERFLOW here while RtlUnicodeStringPrintfEx returns STATUS_INVALID_PARAMETER!
+    // Documented on MSDN and verified with the Win10 version of ntstrsafe.h
+    RtlInitEmptyUnicodeString(&UsString, NULL, 0);
+    Status = RtlUnicodeStringPrintfEx(&UsString, NULL, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC");
+    ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+
+
+Cleanup:
+    if (pBuffer)
+        KmtFreeGuarded(pBuffer);
+
+    // None of these functions should have crashed.
+    KmtEndSeh(STATUS_SUCCESS);
 }
 
 START_TEST(RtlStrSafe)
index fac1a46..2780efe 100644 (file)
 #pragma warning(disable:28719) /* disable banned api usage warning */
 #endif /* _MSC_VER */
 
-#ifndef C_ASSERT
-#ifdef _MSC_VER
-# define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
-#else
-# define C_ASSERT(e) extern void __C_ASSERT__(int [(e)?1:-1])
-#endif
-#endif /* C_ASSERT */
-
-#ifdef __cplusplus
-#define _STRSAFE_EXTERN_C extern "C"
-#else
-#define _STRSAFE_EXTERN_C extern
-#endif
-
 #define NTSTRSAFEAPI static __inline NTSTATUS NTAPI
 #define NTSTRSAFEVAPI static __inline NTSTATUS __cdecl
 #define NTSTRSAFE_INLINE_API static __inline NTSTATUS NTAPI
@@ -92,10 +78,8 @@ NTSTRSAFEAPI RtlStringCatNExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_
 NTSTRSAFEAPI RtlStringCatNExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, size_t cchToAppend, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
 NTSTRSAFEAPI RtlStringVPrintfWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszFormat, va_list argList);
 NTSTRSAFEAPI RtlStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat, va_list argList);
-NTSTRSAFEAPI RtlStringVPrintfWorkerLenW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat, size_t* pcchDestNewLen, va_list argList);
 NTSTRSAFEAPI RtlStringVPrintfExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCSTR pszFormat, va_list argList);
 NTSTRSAFEAPI RtlStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat, va_list argList);
-NTSTRSAFEAPI RtlStringVPrintfExWorkerLenW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat, size_t* pcchDestNewLen, va_list argList);
 NTSTRSAFEAPI RtlUnicodeStringValidate(PCUNICODE_STRING SourceString);
 
 NTSTRSAFEAPI
@@ -1366,6 +1350,7 @@ RtlStringCbPrintfExW(
     {
         if (cchDest > 0)
             *pszDest = L'\0';
+
         return STATUS_INVALID_PARAMETER;
     }
 
@@ -2842,6 +2827,29 @@ NTSTRSAFEAPI RtlStringVPrintfWorkerA(
     return Status;
 }
 
+NTSTRSAFEAPI RtlpArrayVPrintfWorkerW(
+    STRSAFE_LPWSTR pszDest,
+    size_t cchDest,
+    STRSAFE_LPCWSTR pszFormat,
+    size_t* pcchDestNewLen,
+    va_list argList)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    int iRet = _vsnwprintf(pszDest, cchDest, pszFormat, argList);
+
+    if ((iRet < 0) || (((size_t)iRet) > cchDest))
+    {
+        Status = STATUS_BUFFER_OVERFLOW;
+        *pcchDestNewLen = cchDest;
+    }
+    else
+    {
+        *pcchDestNewLen = iRet;
+    }
+
+    return Status;
+}
+
 NTSTRSAFEAPI RtlpStringVPrintfWorkerW(
     STRSAFE_LPWSTR pszDest,
     size_t cchDest,
@@ -2883,19 +2891,6 @@ NTSTRSAFEAPI RtlStringVPrintfWorkerW(
     return RtlpStringVPrintfWorkerW(pszDest, cchDest, pszFormat, NULL, argList);
 }
 
-NTSTRSAFEAPI RtlStringVPrintfWorkerLenW(
-    STRSAFE_LPWSTR pszDest,
-    size_t cchDest,
-    STRSAFE_LPCWSTR pszFormat,
-    size_t* pcchDestNewLen,
-    va_list argList)
-{
-    if (cchDest == 0 || pcchDestNewLen == 0)
-        return STATUS_INVALID_PARAMETER;
-
-    return RtlpStringVPrintfWorkerW(pszDest, cchDest, pszFormat, pcchDestNewLen, argList);
-}
-
 NTSTRSAFEAPI RtlStringVPrintfExWorkerA(
     STRSAFE_LPSTR pszDest,
     size_t cchDest,
@@ -3068,35 +3063,19 @@ NTSTRSAFEAPI RtlpStringVPrintfExWorkerW(
             }
             else
             {
-                int iRet;
-                size_t cchMax = cchDest - 1;
-                iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
-                if ((iRet < 0) || (((size_t)iRet) > cchMax))
-                {
-                    pszDestEnd = pszDest + cchMax;
-                    cchRemaining = 1;
-                    *pszDestEnd = L'\0';
-                    Status = STATUS_BUFFER_OVERFLOW;
-                }
-                else if (((size_t)iRet) == cchMax)
-                {
-                    pszDestEnd = pszDest + cchMax;
-                    cchRemaining = 1;
-                    *pszDestEnd = L'\0';
-                }
-                else if (((size_t)iRet) < cchMax)
-                {
-                    pszDestEnd = pszDest + iRet;
-                    cchRemaining = cchDest - iRet;
+                size_t cchDestNewLen = 0;
 
-                    if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
-                    {
-                        memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
-                    }
+                Status = RtlpArrayVPrintfWorkerW(pszDest, cchDest, pszFormat, &cchDestNewLen, argList);
+                pszDestEnd = pszDest + cchDestNewLen;
+                cchRemaining = cchDest - cchDestNewLen;
+
+                if (NT_SUCCESS(Status) && (dwFlags & STRSAFE_FILL_BEHIND) && cchRemaining)
+                {
+                    memset(pszDestEnd, STRSAFE_GET_FILL_PATTERN(dwFlags), (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
                 }
 
                 if (pcchDestNewLen)
-                    *pcchDestNewLen = iRet == -1 ? cchDest : iRet;
+                    *pcchDestNewLen = cchDestNewLen;
             }
         }
     }
@@ -3120,6 +3099,7 @@ NTSTRSAFEAPI RtlpStringVPrintfExWorkerW(
                     *pszDestEnd = L'\0';
                 }
             }
+
             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
             {
                 if (cchDest > 0)
@@ -3157,24 +3137,6 @@ NTSTRSAFEAPI RtlStringVPrintfExWorkerW(
     return RtlpStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, NULL, argList);
 }
 
-NTSTRSAFEAPI RtlStringVPrintfExWorkerLenW(
-    STRSAFE_LPWSTR pszDest,
-    size_t cchDest,
-    size_t cbDest,
-    STRSAFE_LPWSTR *ppszDestEnd,
-    size_t *pcchRemaining,
-    STRSAFE_DWORD dwFlags,
-    STRSAFE_LPCWSTR pszFormat,
-    size_t* pcchDestNewLen,
-    va_list argList)
-{
-    if (pcchDestNewLen == 0)
-        return STATUS_INVALID_PARAMETER;
-
-    return RtlpStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, pcchDestNewLen, argList);
-}
-
-
 NTSTRSAFEAPI
 RtlStringLengthWorkerA(
     _In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
@@ -3285,7 +3247,7 @@ RtlUnicodeStringPrintf(
     size_t   cchFinalLength;
     va_list  argList;
 
-    if (DestinationString == NULL || pszFormat == NULL || DestinationString->Buffer == NULL)
+    if (DestinationString == NULL || pszFormat == NULL)
     {
         Status = STATUS_INVALID_PARAMETER;
     }
@@ -3296,7 +3258,7 @@ RtlUnicodeStringPrintf(
         {
             va_start(argList, pszFormat);
 
-            Status = RtlStringVPrintfWorkerLenW(DestinationString->Buffer,
+            Status = RtlpArrayVPrintfWorkerW(DestinationString->Buffer,
                 DestinationString->MaximumLength / sizeof(WCHAR),
                 pszFormat,
                 &cchFinalLength,
@@ -3328,7 +3290,7 @@ RtlUnicodeStringPrintfEx(
 
     va_start(argList, pszFormat);
 
-    Status = RtlStringVPrintfExWorkerLenW(DestinationString->Buffer,
+    Status = RtlpStringVPrintfExWorkerW(DestinationString->Buffer,
         DestinationString->MaximumLength / sizeof(WCHAR),
         DestinationString->MaximumLength,
         &RemainingString->Buffer,