[PATCH 1/2] include: Add generic HeapAlloc() wrappers

Michael Stefaniuc mstefani at winehq.org
Sun Jan 21 15:05:34 CST 2018


Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>
---
I know that Alexandre and Jacek wanted to work on the HeapAlloc
wrappers. But I don't remember if I had promised (or not) at the last
WineConf to dig up my old patch and polish it up and submit it to serve
as a discussion start point. Anyway, here it is with some explanations.

The _nofail variants should not "fail" memory allocations and will raise an
exception on out of memory conditions.
heap_alloc_nofail thus will never return NULL.
heap_realloc_nofail can still return NULL but *only* when the alloc size
is 0 and thus functions as heap_free. Checking the returned pointer for
NULL is not needed when the size != 0. And the "assign to temp pointer
to prevent mem leak on failure" workaround is never needed.

The _nofail variants should be used only for small allocations that are
not application driven.
Preferabely the allocation sizes should be known at compile time.
Careful when allocating memory for COM and other objects: The main
object should not be allocated with the _nofail variants. Subsequent
small allocations in the same object could use the _nofail version.

heap_alloc_zero was renamed to heap_zalloc to shorten it. Especially
heap_alloc_zero_nofail would be too long. Same for heap_realloc_zero.
The rename shouldn't be too painful: On a quick grep I found just a
handfull of heap_realloc_zero and about 470 heap_alloc_zero.
I'm also expecting that a good part of those heap_alloc_zero would be
changed anyway to the _nofail variant or to heap_calloc.

Also adding "z" in front of the alloc function name is common:
The Linux kernel uses kzalloc and
$ man -k alloc_zero
alloc_zero: nothing appropriate.
$ man -k zalloc
CRYPTO_secure_zalloc (3ssl) - secure heap storage
CRYPTO_zalloc (3ssl) - Memory allocation functions
OPENSSL_secure_zalloc (3ssl) - secure heap storage
OPENSSL_zalloc (3ssl) - Memory allocation functions

heap_realloc variants follow the sane POSIX / C realloc behavior:
- Passing size 0 will free the old memory.
- Passing NULL as memory pointer will allocate new memory.

heap_free() returns void like free():
- No existing use of the heap_free() return value.
- There are a few "return HeapFree()" statements but more than half of
those are just in heap_free() wrappers.
- The rest of "return HeapFree()" are in "destroy object" style
functions, mostly in gdi32. Most are internal helpers but I didn't
bother tracing them if the return value is needed or not.

Added heap_calloc() that matches the calloc behavior and always zeroes
the memory. Thus there is no heap_zcalloc().
heap_calloc() (differently named) is already used in the D3D related
dlls. I could also immediately make use of it in vbscript.
I'm not sure if a heap_calloc_nofail would make sense. Can be added
later if there is a real need for it.

Now let the bikeshedding begin!


 include/Makefile.in |   1 +
 include/wine/heap.h | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 128 insertions(+)
 create mode 100644 include/wine/heap.h

diff --git a/include/Makefile.in b/include/Makefile.in
index 430c4733af..d107cf7919 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -678,6 +678,7 @@ HEADER_SRCS = \
 	windowsx.h \
 	wine/debug.h \
 	wine/exception.h \
+	wine/heap.h \
 	wine/library.h \
 	wine/unicode.h \
 	winerror.h \
diff --git a/include/wine/heap.h b/include/wine/heap.h
new file mode 100644
index 0000000000..ec10db67be
--- /dev/null
+++ b/include/wine/heap.h
@@ -0,0 +1,127 @@
+/*
+ * Wine heap memory allocation wrappers
+ *
+ * Copyright 2006 Jacek Caban for CodeWeavers
+ * Copyright 2013,2018 Michael Stefaniuc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_WINE_HEAP_H
+#define __WINE_WINE_HEAP_H
+
+#include <windef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* HeapAlloc wrappers
+
+ * "zalloc" variants
+ *      The returned memory is initialized with zero.
+
+ * "nofail" variants
+ *      The returned pointer is never NULL and an exception is raised in out of memory conditions.
+ *      Use only for small allocations that are not application driven.
+ *      Preferabely the allocation size should be known at compile time.
+ */
+static inline void * __WINE_ALLOC_SIZE(1) heap_alloc(SIZE_T len)
+{
+    return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+static inline void * __WINE_ALLOC_SIZE(1) heap_alloc_nofail(SIZE_T len)
+{
+    return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, len);
+}
+
+static inline void * __WINE_ALLOC_SIZE(1) heap_zalloc(SIZE_T len)
+{
+    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+}
+
+static inline void * __WINE_ALLOC_SIZE(1) heap_zalloc_nofail(SIZE_T len)
+{
+    return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, len);
+}
+
+/* HeapReAlloc wrappers with POSIX / C realloc() behavior:
+ *      Passing size 0 will free the old memory.
+ *      Passing NULL as memory pointer will allocate new memory.
+
+ * "zalloc" variants
+ *      The returned memory is initialized with zero.
+
+ * "nofail" variants
+ *      The returned pointer is NULL only when the size == 0 and the memory is freed,
+ *      Raises an exception in out of memory conditions.
+ *      Use only for small allocations that are not application driven.
+ *      Preferabely the allocation size should be known at compile time.
+ */
+static inline void * __WINE_ALLOC_SIZE(2) _heap_realloc(void *mem, SIZE_T len, DWORD flags)
+{
+    if (len) {
+        if (mem)
+            return HeapReAlloc(GetProcessHeap(), flags, mem, len);
+        else
+            return HeapAlloc(GetProcessHeap(), flags, len);
+    } else {
+        HeapFree(GetProcessHeap(), 0, mem);
+        return NULL;
+    }
+}
+
+static inline void * __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, SIZE_T len)
+{
+    return _heap_realloc(mem, len, 0);
+}
+
+static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_nofail(void *mem, SIZE_T len)
+{
+    return _heap_realloc(mem, len, HEAP_GENERATE_EXCEPTIONS);
+}
+
+static inline void * __WINE_ALLOC_SIZE(2) heap_zrealloc(void *mem, SIZE_T len)
+{
+    return _heap_realloc(mem, len, HEAP_ZERO_MEMORY);
+}
+
+static inline void * __WINE_ALLOC_SIZE(2) heap_zrealloc_nofail(void *mem, SIZE_T len)
+{
+    return _heap_realloc(mem, len, HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY);
+}
+
+/* heap_calloc
+ *      calloc() like wrapper that zeroes the returned memory.
+ */
+static inline void * __WINE_ALLOC_SIZE(2) heap_calloc(SIZE_T count, SIZE_T size)
+{
+    if (count > ~(SIZE_T)0 / size)
+        return NULL;
+    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * size);
+}
+
+
+static inline void heap_free(void *mem)
+{
+    HeapFree(GetProcessHeap(), 0, mem);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __WINE_WINE_HEAP_H */
-- 
2.14.3




More information about the wine-devel mailing list