mirror of
https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
synced 2025-05-15 01:08:39 +00:00

Some checks failed
ci / build_and_test (Debug, macos-latest) (push) Has been cancelled
ci / build_and_test (Debug, ubuntu-22.04) (push) Has been cancelled
ci / build_and_test (Debug, ubuntu-24.04) (push) Has been cancelled
ci / build_and_test (Debug, windows-latest) (push) Has been cancelled
ci / build_and_test (Release, macos-latest) (push) Has been cancelled
ci / build_and_test (Release, ubuntu-22.04) (push) Has been cancelled
ci / build_and_test (Release, ubuntu-24.04) (push) Has been cancelled
ci / build_and_test (Release, windows-latest) (push) Has been cancelled
ci / windows-arm64 (push) Has been cancelled
ci / android (arm64-v8a) (push) Has been cancelled
ci / android (armeabi-v7a) (push) Has been cancelled
ci / reuse (push) Has been cancelled
ci / chromium (push) Has been cancelled
ci / generate_source (push) Has been cancelled
format / clang-format (push) Has been cancelled
Calling memcpy with either src or dst as nullptr is undefined even if the count is 0. Discovered by running tests with -fsanitize=undefined safe_struct.extension_add_remove specifcially
126 lines
4.4 KiB
C++
126 lines
4.4 KiB
C++
/***************************************************************************
|
|
*
|
|
* Copyright (c) 2015-2024 The Khronos Group Inc.
|
|
* Copyright (c) 2015-2024 Valve Corporation
|
|
* Copyright (c) 2015-2024 LunarG, Inc.
|
|
* Copyright (c) 2015-2024 Google Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
****************************************************************************/
|
|
|
|
#pragma once
|
|
#include <vulkan/vulkan.h>
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
namespace vku {
|
|
|
|
// State that elements in a pNext chain may need to be aware of
|
|
struct PNextCopyState {
|
|
// Custom initialization function. Returns true if the structure passed to init was initialized, false otherwise
|
|
std::function<bool(VkBaseOutStructure* /* safe_sruct */, const VkBaseOutStructure* /* in_struct */)> init;
|
|
};
|
|
|
|
void* SafePnextCopy(const void* pNext, PNextCopyState* copy_state = {});
|
|
void FreePnextChain(const void* pNext);
|
|
char* SafeStringCopy(const char* in_string);
|
|
|
|
template <typename Base, typename T>
|
|
bool AddToPnext(Base& base, const T& data) {
|
|
assert(base.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
|
|
auto** prev = reinterpret_cast<VkBaseOutStructure**>(const_cast<void**>(&base.pNext));
|
|
auto* current = *prev;
|
|
while (current) {
|
|
if (data.sType == current->sType) {
|
|
return false;
|
|
}
|
|
prev = reinterpret_cast<VkBaseOutStructure**>(¤t->pNext);
|
|
current = *prev;
|
|
}
|
|
*prev = reinterpret_cast<VkBaseOutStructure*>(SafePnextCopy(&data));
|
|
return true;
|
|
}
|
|
|
|
template <typename Base>
|
|
bool RemoveFromPnext(Base& base, VkStructureType t) {
|
|
assert(base.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
|
|
auto** prev = reinterpret_cast<VkBaseOutStructure**>(const_cast<void**>(&base.pNext));
|
|
auto* current = *prev;
|
|
while (current) {
|
|
if (t == current->sType) {
|
|
*prev = current->pNext;
|
|
current->pNext = nullptr;
|
|
FreePnextChain(current);
|
|
return true;
|
|
}
|
|
prev = reinterpret_cast<VkBaseOutStructure**>(¤t->pNext);
|
|
current = *prev;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename CreateInfo>
|
|
uint32_t FindExtension(CreateInfo& ci, const char* extension_name) {
|
|
assert(ci.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
|
|
for (uint32_t i = 0; i < ci.enabledExtensionCount; i++) {
|
|
if (strcmp(ci.ppEnabledExtensionNames[i], extension_name) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
return ci.enabledExtensionCount;
|
|
}
|
|
|
|
template <typename CreateInfo>
|
|
bool AddExtension(CreateInfo& ci, const char* extension_name) {
|
|
assert(ci.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
|
|
uint32_t pos = FindExtension(ci, extension_name);
|
|
if (pos < ci.enabledExtensionCount) {
|
|
// already present
|
|
return false;
|
|
}
|
|
char** exts = new char*[ci.enabledExtensionCount + 1];
|
|
if (ci.ppEnabledExtensionNames) {
|
|
memcpy(exts, ci.ppEnabledExtensionNames, sizeof(char*) * ci.enabledExtensionCount);
|
|
}
|
|
exts[ci.enabledExtensionCount] = SafeStringCopy(extension_name);
|
|
delete[] ci.ppEnabledExtensionNames;
|
|
ci.ppEnabledExtensionNames = exts;
|
|
ci.enabledExtensionCount++;
|
|
return true;
|
|
}
|
|
|
|
template <typename CreateInfo>
|
|
bool RemoveExtension(CreateInfo& ci, const char* extension_name) {
|
|
assert(ci.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
|
|
uint32_t pos = FindExtension(ci, extension_name);
|
|
if (pos >= ci.enabledExtensionCount) {
|
|
// not present
|
|
return false;
|
|
}
|
|
if (ci.enabledExtensionCount == 1) {
|
|
delete[] ci.ppEnabledExtensionNames[0];
|
|
delete[] ci.ppEnabledExtensionNames;
|
|
ci.ppEnabledExtensionNames = nullptr;
|
|
ci.enabledExtensionCount = 0;
|
|
return true;
|
|
}
|
|
uint32_t out_pos = 0;
|
|
char** exts = new char*[ci.enabledExtensionCount - 1];
|
|
for (uint32_t i = 0; i < ci.enabledExtensionCount; i++) {
|
|
if (i == pos) {
|
|
delete[] ci.ppEnabledExtensionNames[i];
|
|
} else {
|
|
exts[out_pos++] = const_cast<char*>(ci.ppEnabledExtensionNames[i]);
|
|
}
|
|
}
|
|
delete[] ci.ppEnabledExtensionNames;
|
|
ci.ppEnabledExtensionNames = exts;
|
|
ci.enabledExtensionCount--;
|
|
return true;
|
|
}
|
|
|
|
} // namespace vku
|