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 athat was pointing to that array will no longer be valid. So if you continue reading or writing into that pointerPtr aafter you return it fromretrieveVulkanArrayyou 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 aensures that you can operate on the rawPtr awhen needed, without worrying that memory it points to is freed untilForeignPtris no longer used.