libvulkan: refactor for _FORTIFY_SOURCE=3 support.
You can't use malloc_usable_size() when built with _FORTIFY_SOURCE=3, so pull out the allocator into a file that can be built _FORTIFY_SOURCE=2 while still getting the benefits for the rest of the code.
Bug: http://b/291762537
Change-Id: Ic3a71bd8eadeb2da167edc0ba28becba2f95f82e
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 879d2d0..7e7fdc4 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -41,14 +41,9 @@
aconfig_declarations: "libvulkan_flags",
}
-cc_library_shared {
- name: "libvulkan",
- llndk: {
- symbol_file: "libvulkan.map.txt",
- export_llndk_headers: [
- "vulkan_headers",
- ],
- },
+cc_defaults {
+ name: "libvulkan_defaults",
+
sanitize: {
misc_undefined: ["integer"],
},
@@ -81,6 +76,34 @@
"-Wno-global-constructors",
"-Wno-zero-length-array",
],
+}
+
+cc_library {
+ name: "libvulkanallocator",
+ defaults: ["libvulkan_defaults"],
+ cflags: [
+ // This code uses malloc_usable_size(),
+ // and thus can't be built with _FORTIFY_SOURCE=3.
+ "-U_FORTIFY_SOURCE",
+ "-D_FORTIFY_SOURCE=2",
+ ],
+ srcs: [
+ "allocator.cpp",
+ ],
+ header_libs: [
+ "vulkan_headers",
+ ],
+}
+
+cc_library_shared {
+ name: "libvulkan",
+ defaults: ["libvulkan_defaults"],
+ llndk: {
+ symbol_file: "libvulkan.map.txt",
+ export_llndk_headers: [
+ "vulkan_headers",
+ ],
+ },
srcs: [
"api.cpp",
@@ -124,6 +147,7 @@
],
static_libs: [
"libgrallocusage",
+ "libvulkanallocator",
"libvulkanflags",
],
}
diff --git a/vulkan/libvulkan/allocator.cpp b/vulkan/libvulkan/allocator.cpp
new file mode 100644
index 0000000..2ca0586
--- /dev/null
+++ b/vulkan/libvulkan/allocator.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "allocator.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include <log/log.h>
+
+// #define ENABLE_ALLOC_CALLSTACKS 1
+#if ENABLE_ALLOC_CALLSTACKS
+#include <utils/CallStack.h>
+#define ALOGD_CALLSTACK(...) \
+ do { \
+ ALOGD(__VA_ARGS__); \
+ android::CallStack callstack; \
+ callstack.update(); \
+ callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
+ } while (false)
+#else
+#define ALOGD_CALLSTACK(...) \
+ do { \
+ } while (false)
+#endif
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+VKAPI_ATTR void* DefaultAllocate(void*,
+ size_t size,
+ size_t alignment,
+ VkSystemAllocationScope) {
+ void* ptr = nullptr;
+ // Vulkan requires 'alignment' to be a power of two, but posix_memalign
+ // additionally requires that it be at least sizeof(void*).
+ int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
+ ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
+ ret, ptr);
+ return ret == 0 ? ptr : nullptr;
+}
+
+// This function is marked `noinline` so that LLVM can't infer an object size
+// for FORTIFY through it, given that it's abusing malloc_usable_size().
+__attribute__((__noinline__))
+VKAPI_ATTR void* DefaultReallocate(void*,
+ void* ptr,
+ size_t size,
+ size_t alignment,
+ VkSystemAllocationScope) {
+ if (size == 0) {
+ free(ptr);
+ return nullptr;
+ }
+
+ // TODO(b/143295633): Right now we never shrink allocations; if the new
+ // request is smaller than the existing chunk, we just continue using it.
+ // Right now the loader never reallocs, so this doesn't matter. If that
+ // changes, or if this code is copied into some other project, this should
+ // probably have a heuristic to allocate-copy-free when doing so will save
+ // "enough" space.
+ size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
+ if (size <= old_size)
+ return ptr;
+
+ void* new_ptr = nullptr;
+ if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
+ return nullptr;
+ if (ptr) {
+ memcpy(new_ptr, ptr, std::min(old_size, size));
+ free(ptr);
+ }
+ return new_ptr;
+}
+
+VKAPI_ATTR void DefaultFree(void*, void* ptr) {
+ ALOGD_CALLSTACK("Free: %p", ptr);
+ free(ptr);
+}
+
+} // anonymous namespace
+
+const VkAllocationCallbacks& GetDefaultAllocator() {
+ static const VkAllocationCallbacks kDefaultAllocCallbacks = {
+ .pUserData = nullptr,
+ .pfnAllocation = DefaultAllocate,
+ .pfnReallocation = DefaultReallocate,
+ .pfnFree = DefaultFree,
+ };
+
+ return kDefaultAllocCallbacks;
+}
+
+} // namespace driver
+} // namespace vulkan
diff --git a/vulkan/libvulkan/allocator.h b/vulkan/libvulkan/allocator.h
new file mode 100644
index 0000000..9095e92
--- /dev/null
+++ b/vulkan/libvulkan/allocator.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace driver {
+
+const VkAllocationCallbacks& GetDefaultAllocator();
+
+} // namespace driver
+} // namespace vulkan
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7d0f545..28c1b5f 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -50,22 +50,6 @@
extern "C" android_namespace_t* android_get_exported_namespace(const char*);
-// #define ENABLE_ALLOC_CALLSTACKS 1
-#if ENABLE_ALLOC_CALLSTACKS
-#include <utils/CallStack.h>
-#define ALOGD_CALLSTACK(...) \
- do { \
- ALOGD(__VA_ARGS__); \
- android::CallStack callstack; \
- callstack.update(); \
- callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
- } while (false)
-#else
-#define ALOGD_CALLSTACK(...) \
- do { \
- } while (false)
-#endif
-
namespace vulkan {
namespace driver {
@@ -829,54 +813,6 @@
}
}
-VKAPI_ATTR void* DefaultAllocate(void*,
- size_t size,
- size_t alignment,
- VkSystemAllocationScope) {
- void* ptr = nullptr;
- // Vulkan requires 'alignment' to be a power of two, but posix_memalign
- // additionally requires that it be at least sizeof(void*).
- int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
- ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
- ret, ptr);
- return ret == 0 ? ptr : nullptr;
-}
-
-VKAPI_ATTR void* DefaultReallocate(void*,
- void* ptr,
- size_t size,
- size_t alignment,
- VkSystemAllocationScope) {
- if (size == 0) {
- free(ptr);
- return nullptr;
- }
-
- // TODO(b/143295633): Right now we never shrink allocations; if the new
- // request is smaller than the existing chunk, we just continue using it.
- // Right now the loader never reallocs, so this doesn't matter. If that
- // changes, or if this code is copied into some other project, this should
- // probably have a heuristic to allocate-copy-free when doing so will save
- // "enough" space.
- size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
- if (size <= old_size)
- return ptr;
-
- void* new_ptr = nullptr;
- if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
- return nullptr;
- if (ptr) {
- memcpy(new_ptr, ptr, std::min(old_size, size));
- free(ptr);
- }
- return new_ptr;
-}
-
-VKAPI_ATTR void DefaultFree(void*, void* ptr) {
- ALOGD_CALLSTACK("Free: %p", ptr);
- free(ptr);
-}
-
InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
void* data_mem = allocator.pfnAllocation(
allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
@@ -916,17 +852,6 @@
return Hal::Open();
}
-const VkAllocationCallbacks& GetDefaultAllocator() {
- static const VkAllocationCallbacks kDefaultAllocCallbacks = {
- .pUserData = nullptr,
- .pfnAllocation = DefaultAllocate,
- .pfnReallocation = DefaultReallocate,
- .pfnFree = DefaultFree,
- };
-
- return kDefaultAllocCallbacks;
-}
-
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
const ProcHook* hook = GetProcHook(pName);
if (!hook)
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 4b855e5..fa85dd5 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -27,6 +27,7 @@
#include <vulkan/vulkan.h>
#include <hardware/hwvulkan.h>
+#include "allocator.h"
#include "api_gen.h"
#include "driver_gen.h"
#include "debug_report.h"
@@ -102,7 +103,6 @@
};
bool OpenHAL();
-const VkAllocationCallbacks& GetDefaultAllocator();
void QueryPresentationProperties(
VkPhysicalDevice physicalDevice,