So recently I have been working with Vulkan-Hpp
(The official c++ bindings of Vulkan Api, Github Link).
Looking into the source, I have found that they create wrapper classes around native Vulkan structs (e.g. vk::InstanceCreateInfo
wraps around VkInstanceCreateInfo
). (Note: Wrapping around, not deriving from)
When calling native Vulkan API, the pointers to wrapper classes are reinterpret_cast
ed into the native Vulkan structs. An example using vk::InstanceCreateInfo
:
//definition of vk::InstanceCreateInfo
struct InstanceCreateInfo
{
/* member function omitted */
private:
StructureType sType = StructureType::eInstanceCreateInfo;
public:
const void* pNext = nullptr;
InstanceCreateFlags flags;
const ApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
};
//definition of VkInstanceCreateInfo
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
//And the usage where reinterpret_cast takes place
template<typename Dispatch>
VULKAN_HPP_INLINE ResultValueType<Instance>::type createInstance( const InstanceCreateInfo &createInfo, Optional<const AllocationCallbacks> allocator, Dispatch const &d )
{
Instance instance;
Result result = static_cast<Result>( d.vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkInstance*>( &instance ) ) );
return createResultValue( result, instance, VULKAN_HPP_NAMESPACE_STRING"::createInstance" );
}
So my question is: vk::InstanceCreateInfo
and VkInstanceCreateInfo
are two different types. Moreover, VkInstanceCreateInfo
is standard layout but vk::InstanceCreateInfo
is not (since it has mixed access specifiers). Is reinterpret_cast
ing between the pointer of those two types (as done by Vulkan-Hpp
) legal? Does this violate the strict aliasing rule?
Note: you can assume that VkInstanceCreateFlags
and vk::InstanceCreateFlags
are interchangeable in this case (otherwise it would make my question recursive)
As far as the standard is concerned, yes, accessing a vk::InstanceCreateInfo
object through a pointer to a VkInstanceCreateInfo
object violates strict aliasing. And it would still violate strict aliasing even if both types were standard layout with equivalent layout. The standard doesn't allow you to just pretend that one class type is another, even if they have equivalent layouts.
So this code is relying on some implementation-specific behavior.
Is that wrong? Would doing an additional copy for every single Vulkan interface function call make you feel better about it, even if it would work without it? It's ultimately up to you how much UB you feel like tolerating.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With