Тот факт, что она работает, определенно не доказывает ее правильность, на самом деле эта функция действительно очень неправильная.
alloca
, а также allocaArray
, выделит Haskell MutableByteArray#
преобразовать его в указатель. Работайте с этим указателем, а затем убедитесь, что массив все еще жив, с помощью специальной функции touch#
. Проблема в том, что как только вы потеряете ссылку на фактический MutableByteArray#
, что происходит при выходе из alloca
, G C очистит его, и Ptr a
, который указывал на этот массив, больше не будет действительным. Итак, если вы продолжите чтение или запись в этот указатель Ptr a
после того, как вы вернете его из retrieveVulkanArray
, вы читаете / записываете в память, которая может использоваться чем-то еще, и теперь вы находитесь в реальной опасности segfault и всевозможных других мер безопасности. уязвимости, которые связаны с ним.
Правильный способ:
retrieveVulkanArray
:: Storable a => (Ptr Word32 -> Ptr a -> IO b) -> IO (ForeignPtr a, Int)
retrieveVulkanArray' f =
alloca $ \arrCount -> do
f arrCount vkNullPtr
arrCount' <- fromIntegral <$> peek arrCount
resArray <- mallocForeignPtrArray arrCount'
_ <- withForeignPtr resArray (f arrCount)
pure (resArray, arrCount')
ForeignPtr a
гарантирует, что вы можете работать с необработанными Ptr a
при необходимости, не беспокоясь о памяти, которую он указывает to освобождается до тех пор, пока ForeignPtr
не перестанет использоваться.