i have this function in my code that seems to work just fine:
-- type declaration just for reference, i don't have it in my actual code
retrieveVulkanArray :: Storable a => (Ptr Word32 -> Ptr a -> IO b) -> IO (Ptr a, Int)
retrieveVulkanArray' f =
alloca $ \arrCount -> do
f arrCount vkNullPtr
arrCount' <- fromIntegral <$> peek arrCount
allocaArray arrCount' $ \resArray -> do
f arrCount resArray
pure (resArray, arrCount')
(for context this is a helper function to get FFI arrays from Vulkan API, f might be for example vkEnumeratePhysicalDevices)
As i was reviewing my code, i noticed that it returns resArray(which from description of allocaArray seems to only be valid within the inner lambda) to its caller. In C, a code like this would be undefined behaviour. Is my intuition correct here or is there something more going on? I haven't noticed any crashes yet after all :)
The fact that it works certainly doesn't prove that it is correct, in fact this function is indeed very wrong.
alloca
, as well asallocaArray
, will allocate a HaskellMutableByteArray#
convert it to a pointer. Operate on that pointer and then ensure that the array is still alive with a specialtouch#
function. Problem is that once you loose reference to the actualMutableByteArray#
, which is what happens when you exitalloca
, GC will clean it up and thePtr a
that was pointing to that array will no longer be valid. So if you continue reading or writing into that pointerPtr a
after you return it fromretrieveVulkanArray
you are reading/writing into memory that can be used by something else and are now in real danger of a segfault and all sorts of other security vulnerabilities that come with it.The proper way would be:
ForeignPtr a
ensures that you can operate on the rawPtr a
when needed, without worrying that memory it points to is freed untilForeignPtr
is no longer used.