[libc-commits] [libc] POC: add snmalloc as an alternative allocator to libc (PR #122284)

via libc-commits libc-commits at lists.llvm.org
Wed Jan 15 22:22:36 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

<details>
<summary>Changes</summary>

Does not work yet. I need to work out a lot more details. This is for collecting ideas.

`snmalloc` is already supported in LLVM for windows CRT replacement, we can also use it as an implementation of our allocator:

https://github.com/llvm/llvm-project/blob/aa0191e3feccf8253f16594922ee924b38e7760d/llvm/lib/Support/CMakeLists.txt#L101

Adding snmalloc will push forward our support on windows/macos easily. It also provides linux target with a modern allocator alternative.

I have made snmalloc buildable with clean C headers in https://github.com/microsoft/snmalloc/pull/722, hence, it can now be used in a way largely similar to scudo standalone allocator.

`malloc.cpp.o` is already buildable with some ad-hoc fixes, so I think there is no technical obstacle. 



---
Full diff: https://github.com/llvm/llvm-project/pull/122284.diff


10 Files Affected:

- (modified) libc/src/stdlib/CMakeLists.txt (+40-1) 
- (added) libc/src/stdlib/snmalloc/CMakeLists.txt (+119) 
- (added) libc/src/stdlib/snmalloc/aligned_alloc.cpp (+17) 
- (added) libc/src/stdlib/snmalloc/calloc.cpp (+17) 
- (added) libc/src/stdlib/snmalloc/free.cpp (+17) 
- (added) libc/src/stdlib/snmalloc/malloc.cpp (+17) 
- (added) libc/src/stdlib/snmalloc/mallopt.cpp (+13) 
- (added) libc/src/stdlib/snmalloc/override.h (+32) 
- (added) libc/src/stdlib/snmalloc/realloc.cpp (+17) 
- (modified) libc/test/src/stdlib/CMakeLists.txt (+3-1) 


``````````diff
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 40ba9ead9a7ae6..7d0dfd1aa9da4b 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -324,7 +324,46 @@ add_entrypoint_object(
 )
 
 if(NOT LIBC_TARGET_OS_IS_BAREMETAL AND NOT LIBC_TARGET_OS_IS_GPU)
-  if(LLVM_LIBC_INCLUDE_SCUDO)
+  if (NOT "${LLVM_LIBC_INCLUDE_SNMALLOC}" STREQUAL "")
+    message(STATUS "Including snmalloc as the allocator, source directory: ${LLVM_LIBC_INCLUDE_SNMALLOC}")
+    add_subdirectory(snmalloc)
+    add_entrypoint_object(
+      malloc
+      ALIAS
+      DEPENDS
+        .snmalloc.malloc
+    )
+    add_entrypoint_object(
+      calloc
+      ALIAS
+      DEPENDS
+        .snmalloc.calloc
+    )
+    add_entrypoint_object(
+      realloc
+      ALIAS
+      DEPENDS
+        .snmalloc.realloc
+    )
+    add_entrypoint_object(
+      aligned_alloc
+      ALIAS
+      DEPENDS
+        .snmalloc.aligned_alloc
+    )
+    add_entrypoint_object(
+      free
+      ALIAS
+      DEPENDS
+        .snmalloc.free
+    )
+    add_entrypoint_object(
+      mallopt
+      ALIAS
+      DEPENDS
+        .snmalloc.mallopt
+    )
+  elseif(LLVM_LIBC_INCLUDE_SCUDO)
     set(SCUDO_DEPS "")
 
     include(${LIBC_SOURCE_DIR}/../compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake)
diff --git a/libc/src/stdlib/snmalloc/CMakeLists.txt b/libc/src/stdlib/snmalloc/CMakeLists.txt
new file mode 100644
index 00000000000000..e360b36f5fb3ad
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/CMakeLists.txt
@@ -0,0 +1,119 @@
+set(SNMALLOC_USE_SELF_VENDORED_STL ON CACHE BOOL "use freestanding snmalloc setup" FORCE)
+set(SNMALLOC_BUILD_TESTING OFF CACHE BOOL "disable snmalloc tests" FORCE)
+set(SNMALLOC_HEADER_ONLY_LIBRARY ON CACHE BOOL "use snmalloc as header only library" FORCE)
+
+# Disable installation
+macro (install)
+endmacro ()
+
+add_subdirectory(${LLVM_LIBC_INCLUDE_SNMALLOC} ${CMAKE_CURRENT_BINARY_DIR}/snmalloc EXCLUDE_FROM_ALL)
+
+target_compile_options(
+  snmalloc 
+  INTERFACE 
+    -ffreestanding
+    -nostdinc 
+    -Wno-newline-eof 
+    -Wno-extra-semi
+    -Wno-unused-command-line-argument
+    -Wno-ctad-maybe-unsupported
+    # TODO: define this
+    -DSTDERR_FILENO=2
+    -DSNMALLOC_USE_PTHREAD_DESTRUCTORS
+    # include_directories does not propagate, use options instead
+    -include ${CMAKE_CURRENT_SOURCE_DIR}/override.h
+    -isystem ${COMPILER_RESOURCE_DIR}/include
+    -isystem ${LIBC_INCLUDE_DIR}
+)
+
+add_dependencies(snmalloc libc-headers)
+
+set(SNMALLOC_DEPS
+  # includes
+  libc.include.errno
+  libc.include.fcntl
+  libc.include.limits
+  libc.include.pthread
+  libc.include.stdio
+  libc.include.stdint
+  libc.include.stdlib
+  libc.include.string
+  libc.include.strings
+  libc.include.sys_mman
+  libc.include.sys_prctl
+  libc.include.sys_random
+  libc.include.sys_syscall
+  libc.include.sys_uio
+  libc.include.unistd
+  # symbols
+  libc.src.errno.errno
+  libc.src.fcntl.open
+  libc.src.pthread.pthread_key_create
+  libc.src.pthread.pthread_setspecific
+  libc.src.stdlib.abort
+  libc.src.stdlib.atexit
+  libc.src.string.memset
+  libc.src.string.strlen
+  libc.src.sys.mman.madvise
+  libc.src.sys.mman.mmap
+  libc.src.sys.uio.writev
+  libc.src.time.clock_gettime
+  libc.src.unistd.__llvm_libc_syscall
+  libc.src.unistd.close
+  libc.src.unistd.fsync
+  libc.src.unistd.getentropy
+  libc.src.unistd.read
+)
+
+add_entrypoint_object(
+  malloc
+  SRCS
+    malloc.cpp
+  DEPENDS
+    snmalloc
+)
+
+add_entrypoint_object(
+  calloc
+  SRCS
+    calloc.cpp
+  DEPENDS
+    snmalloc
+    ${SNMALLOC_DEPS}
+)
+
+add_entrypoint_object(
+  realloc
+  SRCS
+    realloc.cpp
+  DEPENDS
+    snmalloc
+    ${SNMALLOC_DEPS}
+)
+
+add_entrypoint_object(
+  aligned_alloc
+  SRCS
+    aligned_alloc.cpp
+  DEPENDS
+    snmalloc
+    ${SNMALLOC_DEPS}
+)
+
+add_entrypoint_object(
+  free
+  SRCS
+    free.cpp
+  DEPENDS
+    snmalloc
+    ${SNMALLOC_DEPS}
+)
+
+add_entrypoint_object(
+  mallopt
+  SRCS
+    mallopt.cpp
+  DEPENDS
+    snmalloc
+    ${SNMALLOC_DEPS}
+)
diff --git a/libc/src/stdlib/snmalloc/aligned_alloc.cpp b/libc/src/stdlib/snmalloc/aligned_alloc.cpp
new file mode 100644
index 00000000000000..ee1d74ca9c778c
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/aligned_alloc.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of aligned_alloc -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/aligned_alloc.h"
+#include "snmalloc/snmalloc.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, aligned_alloc, (size_t alignment, size_t size)) {
+  return snmalloc::libc::aligned_alloc(alignment, size);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/snmalloc/calloc.cpp b/libc/src/stdlib/snmalloc/calloc.cpp
new file mode 100644
index 00000000000000..39af67607bf709
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/calloc.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of calloc ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/calloc.h"
+#include "snmalloc/snmalloc.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, calloc, (size_t num, size_t size)) {
+  return snmalloc::libc::calloc(num, size);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/snmalloc/free.cpp b/libc/src/stdlib/snmalloc/free.cpp
new file mode 100644
index 00000000000000..eb403710fffada
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/free.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of free --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/free.h"
+#include "snmalloc/snmalloc.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void, free, (void *ptr)) {
+  return snmalloc::libc::free(ptr);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/snmalloc/malloc.cpp b/libc/src/stdlib/snmalloc/malloc.cpp
new file mode 100644
index 00000000000000..ab58e63743016a
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/malloc.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of malloc ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/malloc.h"
+#include "snmalloc/snmalloc.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, malloc, (size_t size)) {
+  return snmalloc::libc::malloc(size);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/snmalloc/mallopt.cpp b/libc/src/stdlib/snmalloc/mallopt.cpp
new file mode 100644
index 00000000000000..c52d68e3d52230
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/mallopt.cpp
@@ -0,0 +1,13 @@
+//===-- Implementation of mallopt stub ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(int, mallopt, (int, int)) { return 0; }
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/snmalloc/override.h b/libc/src/stdlib/snmalloc/override.h
new file mode 100644
index 00000000000000..a36a6316790fbd
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/override.h
@@ -0,0 +1,32 @@
+//===-- Macro Override for SnMalloc ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// skip special headers
+#define LLVM_LIBC_COMMON_H
+#define LLVM_LIBC_ERRNO_H
+
+// define common macros
+#define __BEGIN_C_DECLS namespace LIBC_NAMESPACE {
+#define __END_C_DECLS                                                          \
+  }                                                                            \
+  using namespace LIBC_NAMESPACE;
+
+#define _Noreturn [[noreturn]]
+#define _Alignas alignas
+#define _Static_assert static_assert
+#define _Alignof alignof
+#define _Thread_local thread_local
+
+// Use empty definition to avoid spec mismatching
+// We are building internally anyway, hence noexcept does not matter here
+#define __NOEXCEPT
+
+// Enforce internal errno implementation
+#include "hdr/errno_macros.h"
+#include "src/errno/libc_errno.h"
+#define errno libc_errno
diff --git a/libc/src/stdlib/snmalloc/realloc.cpp b/libc/src/stdlib/snmalloc/realloc.cpp
new file mode 100644
index 00000000000000..36972e0a2232ec
--- /dev/null
+++ b/libc/src/stdlib/snmalloc/realloc.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of realloc -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/realloc.h"
+#include "snmalloc/snmalloc.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(void *, realloc, (void *ptr, size_t size)) {
+  return snmalloc::libc::realloc(ptr, size);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index 8cc0428632ba39..2346a8bae08f87 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -420,7 +420,9 @@ if(LLVM_LIBC_FULL_BUILD)
   )
 
   # Only baremetal and GPU has an in-tree 'malloc' implementation.
-  if(LIBC_TARGET_OS_IS_BAREMETAL OR LIBC_TARGET_OS_IS_GPU)
+  if(LIBC_TARGET_OS_IS_BAREMETAL
+      OR LIBC_TARGET_OS_IS_GPU
+      OR NOT "${LLVM_LIBC_INCLUDE_SNMALLOC}" STREQUAL "")
     add_libc_test(
       malloc_test
       HERMETIC_TEST_ONLY

``````````

</details>


https://github.com/llvm/llvm-project/pull/122284


More information about the libc-commits mailing list