https://git.reactos.org/?p=reactos.git;a=commitdiff;h=774ef4e80e8fe150f854cd9c009253c434096add

commit 774ef4e80e8fe150f854cd9c009253c434096add
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Fri Apr 24 17:45:43 2020 +0900
Commit:     GitHub <[email protected]>
CommitDate: Fri Apr 24 17:45:43 2020 +0900

    [SDK][RTL][NTDLL_APITEST] Add RtlMultipleAllocateHeap and 
RtlMultipleFreeHeap (#2641)
    
    - Add RtlMultipleAllocateHeap and RtlMultipleFreeHeap functions (2k3+).
    - Add a testcase for two functions.
    CORE-12026
---
 modules/rostests/apitests/ntdll/CMakeLists.txt     |   1 +
 .../apitests/ntdll/RtlMultipleAllocateHeap.c       | 286 +++++++++++++++++++++
 modules/rostests/apitests/ntdll/testlist.c         |   2 +
 sdk/include/ndk/rtlfuncs.h                         |  13 +-
 sdk/lib/rtl/heap.c                                 |  62 ++++-
 5 files changed, 351 insertions(+), 13 deletions(-)

diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt 
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index d03b29806c9..ac1804728fc 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -61,6 +61,7 @@ list(APPEND SOURCE
     RtlImageRvaToVa.c
     RtlIsNameLegalDOS8Dot3.c
     RtlMemoryStream.c
+    RtlMultipleAllocateHeap.c
     RtlNtPathNameToDosPathName.c
     RtlpEnsureBufferSize.c
     RtlQueryTimeZoneInfo.c
diff --git a/modules/rostests/apitests/ntdll/RtlMultipleAllocateHeap.c 
b/modules/rostests/apitests/ntdll/RtlMultipleAllocateHeap.c
new file mode 100644
index 00000000000..b2eb3132afa
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/RtlMultipleAllocateHeap.c
@@ -0,0 +1,286 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Test for RtlMultipleAllocateHeap and RtlMultipleFreeHeap
+ * COPYRIGHT:   Copyright 2020 Katayama Hirofumi MZ 
([email protected])
+ */
+#include "precomp.h"
+
+typedef ULONG (NTAPI *FN_RtlMultipleAllocateHeap)(IN PVOID, IN ULONG, IN 
SIZE_T, IN ULONG, OUT PVOID *);
+typedef ULONG (NTAPI *FN_RtlMultipleFreeHeap)(IN PVOID, IN ULONG, IN ULONG, 
OUT PVOID *);
+
+static FN_RtlMultipleAllocateHeap g_alloc = NULL;
+static FN_RtlMultipleFreeHeap g_free = NULL;
+
+#define 
TEST_ALLOC(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array)
 \
+    threw = 0; \
+    SetLastError(-1); \
+    _SEH2_TRY { \
+        ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \
+        err = GetLastError(); \
+    } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
+        threw = _SEH2_GetExceptionCode(); \
+    } \
+    _SEH2_END \
+    ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), 
(ret)); \
+    ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), 
(err)); \
+    ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", 
(threw_excepted), (threw));
+
+#define 
TEST_ALLOC_NO_RET(err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array)
 \
+    threw = 0; \
+    SetLastError(-1); \
+    _SEH2_TRY { \
+        ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \
+        err = GetLastError(); \
+    } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
+        threw = _SEH2_GetExceptionCode(); \
+    } \
+    _SEH2_END \
+    ok((err) == (err_expected), "err excepted %d, but %d", (err_expected), 
(err)); \
+    ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", 
(threw_excepted), (threw));
+
+#define 
TEST_FREE(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Count,Array)
 \
+    threw = 0; \
+    SetLastError(-1); \
+    _SEH2_TRY { \
+        ret = g_free((HeapHandle), (Flags), (Count), (Array)); \
+        err = GetLastError(); \
+    } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
+        threw = _SEH2_GetExceptionCode(); \
+    } \
+    _SEH2_END \
+    ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), 
(ret)); \
+    ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), 
(err)); \
+    ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", 
(threw_excepted), (threw));
+
+#define ASSUME_ARRAY_ITEMS_ARE_NULL() \
+    ok(Array[0] == NULL, "Array[0] is expected as NULL\n"); \
+    ok(Array[1] == NULL, "Array[1] is expected as NULL\n"); \
+    ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
+
+#define INT_EXPECTED(var,value) \
+    ok((var) == (value), #var " expected %d, but %d\n", (value), (var))
+
+static void
+set_array(PVOID *array, PVOID p0, PVOID p1, PVOID p2)
+{
+    array[0] = p0;
+    array[1] = p1;
+    array[2] = p2;
+}
+
+static void
+MultiHeapAllocTest()
+{
+    INT ret, threw, err;
+    HANDLE HeapHandle = GetProcessHeap();
+    PVOID Array[3] = {NULL, NULL, NULL};
+
+    // HeapHandle is non-NULL and array is NULL
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, NULL);
+    TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 0, 1, NULL);
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, NULL);
+    TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 1, 1, NULL);
+
+    // Array is non-NULL and contents are NULL
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array);
+    ASSUME_ARRAY_ITEMS_ARE_NULL();
+
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] == NULL, "Array[1] is expected as NULL\n");
+    ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
+
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array);
+    ASSUME_ARRAY_ITEMS_ARE_NULL();
+
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] == NULL, "Array[1] is expected as NULL\n");
+    ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
+
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
+    ok(Array[2] == NULL, "Array[2] is expected as NULL\n");
+
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
+    ok(Array[2] != NULL, "Array[2] is expected as non-NULL\n");
+
+    // Array is non-NULL and contents are invalid pointers
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array);
+    ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n");
+    ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
+    ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
+
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
+    ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
+
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array);
+    ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n");
+    ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n");
+    ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
+
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] == (PVOID)2, "Array[1] is expected as non-NULL\n");
+    ok(Array[2] == (PVOID)3, "Array[2] is expected as NULL\n");
+
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
+    ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n");
+
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array);
+    ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n");
+    ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n");
+    ok(Array[2] != NULL, "Array[2] is expected as non-NULL\n");
+
+    // Array is non-NULL and too large to allocate
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0, HeapHandle, 0, 0x5FFFFFFF, 
3, Array);
+    ok(ret != 3, "excepted not allocated");
+    set_array(Array, NULL, NULL, NULL);
+    TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0xC0000017, HeapHandle, 
HEAP_GENERATE_EXCEPTIONS, 0x5FFFFFFF, 3, Array);
+    ok(ret != 3, "excepted not allocated");
+}
+
+static void
+MultiHeapFreeTest()
+{
+    INT ret, threw, err;
+    HANDLE HeapHandle = GetProcessHeap();
+    PVOID Array[3] = {NULL, NULL, NULL};
+
+    // HeapHandle is non-NULL and array is NULL
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL);
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL);
+    TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 1, NULL);
+    TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 2, NULL);
+    TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 3, NULL);
+
+    // Array is non-NULL and contents are NULL
+    set_array(Array, NULL, NULL, NULL);
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
+    set_array(Array, NULL, NULL, NULL);
+    TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
+    set_array(Array, NULL, NULL, NULL);
+    TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array);
+    set_array(Array, NULL, NULL, NULL);
+    TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
+
+    // Array is non-NULL and contents are invalid pointers
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 1, Array);
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array);
+    set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3);
+    TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array);
+
+    // Array is non-NULL and contents are 1 valid pointer and 2 NULLs
+    set_array(Array, NULL, NULL, NULL);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
+
+    set_array(Array, NULL, NULL, NULL);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
+
+    set_array(Array, NULL, NULL, NULL);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array);
+
+    set_array(Array, NULL, NULL, NULL);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
+
+    // Array is non-NULL and contents are 1 valid pointer and 2 invalids
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array);
+
+    // Array is non-NULL and contents are 1 valid pointer and 2 invalids 
(generate exceptions)
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(0, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 0, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 1, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 
HEAP_GENERATE_EXCEPTIONS, 2, Array);
+
+    set_array(Array, NULL, (PVOID)2, (PVOID)3);
+    ret = g_alloc(HeapHandle, 0, 1, 1, Array);
+    INT_EXPECTED(ret, 1);
+    TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 
HEAP_GENERATE_EXCEPTIONS, 3, Array);
+
+    // Array is non-NULL and contents are 3 valid pointers
+    set_array(Array, NULL, NULL, NULL);
+    ret = g_alloc(HeapHandle, 0, 3, 3, Array);
+    INT_EXPECTED(ret, 3);
+    TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array);
+}
+
+START_TEST(RtlMultipleAllocateHeap)
+{
+    HINSTANCE ntdll = LoadLibraryA("ntdll");
+
+    g_alloc = (FN_RtlMultipleAllocateHeap)GetProcAddress(ntdll, 
"RtlMultipleAllocateHeap");
+    g_free = (FN_RtlMultipleFreeHeap)GetProcAddress(ntdll, 
"RtlMultipleFreeHeap");
+
+    if (!g_alloc || !g_free)
+    {
+        skip("RtlMultipleAllocateHeap or RtlMultipleFreeHeap not found\n");
+    }
+    else
+    {
+        MultiHeapAllocTest();
+        MultiHeapFreeTest();
+    }
+
+    FreeLibrary(ntdll);
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c 
b/modules/rostests/apitests/ntdll/testlist.c
index 7b3155314eb..95efbb0f6d8 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -60,6 +60,7 @@ extern void func_RtlHandle(void);
 extern void func_RtlImageRvaToVa(void);
 extern void func_RtlIsNameLegalDOS8Dot3(void);
 extern void func_RtlMemoryStream(void);
+extern void func_RtlMultipleAllocateHeap(void);
 extern void func_RtlNtPathNameToDosPathName(void);
 extern void func_RtlpEnsureBufferSize(void);
 extern void func_RtlQueryTimeZoneInformation(void);
@@ -129,6 +130,7 @@ const struct test winetest_testlist[] =
     { "RtlImageRvaToVa",                func_RtlImageRvaToVa },
     { "RtlIsNameLegalDOS8Dot3",         func_RtlIsNameLegalDOS8Dot3 },
     { "RtlMemoryStream",                func_RtlMemoryStream },
+    { "RtlMultipleAllocateHeap",        func_RtlMultipleAllocateHeap },
     { "RtlNtPathNameToDosPathName",     func_RtlNtPathNameToDosPathName },
     { "RtlpEnsureBufferSize",           func_RtlpEnsureBufferSize },
     { "RtlQueryTimeZoneInformation",    func_RtlQueryTimeZoneInformation },
diff --git a/sdk/include/ndk/rtlfuncs.h b/sdk/include/ndk/rtlfuncs.h
index 1e386af2861..d8764771eb7 100644
--- a/sdk/include/ndk/rtlfuncs.h
+++ b/sdk/include/ndk/rtlfuncs.h
@@ -992,27 +992,26 @@ RtlLockHeap(
     _In_ HANDLE Heap
 );
 
-_Must_inspect_result_
 NTSYSAPI
-NTSTATUS
+ULONG
 NTAPI
-RtlMultipleAllocateHeap (
+RtlMultipleAllocateHeap(
     _In_ HANDLE HeapHandle,
     _In_ ULONG Flags,
     _In_ SIZE_T Size,
     _In_ ULONG Count,
     _Out_cap_(Count) _Deref_post_bytecap_(Size) PVOID * Array
-    );
+);
 
 NTSYSAPI
-NTSTATUS
+ULONG
 NTAPI
-RtlMultipleFreeHeap (
+RtlMultipleFreeHeap(
     _In_ HANDLE HeapHandle,
     _In_ ULONG Flags,
     _In_ ULONG Count,
     _In_count_(Count) /* _Deref_ _Post_invalid_ */ PVOID * Array
-    );
+);
 
 NTSYSAPI
 NTSTATUS
diff --git a/sdk/lib/rtl/heap.c b/sdk/lib/rtl/heap.c
index ccdb7d1ef29..ad4f6a1513d 100644
--- a/sdk/lib/rtl/heap.c
+++ b/sdk/lib/rtl/heap.c
@@ -4,6 +4,7 @@
  * FILE:            lib/rtl/heap.c
  * PURPOSE:         RTL Heap backend allocator
  * PROGRAMMERS:     Copyright 2010 Aleksey Bragin
+ *                  Copyright 2020 Katayama Hirofumi MZ
  */
 
 /* Useful references:
@@ -3972,7 +3973,8 @@ RtlQueryHeapInformation(HANDLE HeapHandle,
     return STATUS_UNSUCCESSFUL;
 }
 
-NTSTATUS
+/* @implemented */
+ULONG
 NTAPI
 RtlMultipleAllocateHeap(IN PVOID HeapHandle,
                         IN ULONG Flags,
@@ -3980,19 +3982,67 @@ RtlMultipleAllocateHeap(IN PVOID HeapHandle,
                         IN ULONG Count,
                         OUT PVOID *Array)
 {
-    UNIMPLEMENTED;
-    return 0;
+    ULONG Index;
+    EXCEPTION_RECORD ExceptionRecord;
+
+    for (Index = 0; Index < Count; ++Index)
+    {
+        Array[Index] = RtlAllocateHeap(HeapHandle, Flags, Size);
+        if (Array[Index] == NULL)
+        {
+            /* ERROR_NOT_ENOUGH_MEMORY */
+            RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY);
+
+            if (Flags & HEAP_GENERATE_EXCEPTIONS)
+            {
+                ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY;
+                ExceptionRecord.ExceptionRecord = NULL;
+                ExceptionRecord.NumberParameters = 0;
+                ExceptionRecord.ExceptionFlags = 0;
+
+                RtlRaiseException(&ExceptionRecord);
+            }
+            break;
+        }
+    }
+
+    return Index;
 }
 
-NTSTATUS
+/* @implemented */
+ULONG
 NTAPI
 RtlMultipleFreeHeap(IN PVOID HeapHandle,
                     IN ULONG Flags,
                     IN ULONG Count,
                     OUT PVOID *Array)
 {
-    UNIMPLEMENTED;
-    return 0;
+    ULONG Index;
+
+    for (Index = 0; Index < Count; ++Index)
+    {
+        if (Array[Index] == NULL)
+            continue;
+
+        _SEH2_TRY
+        {
+            if (!RtlFreeHeap(HeapHandle, Flags, Array[Index]))
+            {
+                /* ERROR_INVALID_PARAMETER */
+                
RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
+                break;
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* ERROR_INVALID_PARAMETER */
+            
RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER);
+            break;
+        }
+        _SEH2_END;
+    }
+
+    return Index;
 }
 
 /*

Reply via email to