LumiGuide / haskell-opencv

Haskell binding to OpenCV-3.x
Other
154 stars 44 forks source link

Fix `matToHMat emptyMat` segfaulting #151

Closed nh2 closed 3 years ago

nh2 commented 3 years ago

Fixes #150.

The copyFromVec functions call dimPositions to get all the steps and offsets to copy. That worked well for the non-empty matrices, but for the empty one, dimPositions returns [[]].

The empty matrix can have channels, e.g. S 1 in

emptyMat :: Mat (S '[]) (S 1) (S Word8)

Thus in copcode like

copyFromVec v =
  for_ (zip [0, channels ..] $ dimPositions shape) $ \(posIx, pos) -> do
    let elemPtr = matElemAddress dataPtr (fromIntegral <$> step) pos
    for_ [0 .. channels - 1] $ \channelIx ->
      pokeElemOff elemPtr (fromIntegral channelIx) $ VU.unsafeIndex v (fromIntegral $ posIx + channelIx)

or

copyToVec = do
  for_ (zip [0,channels..] $ dimPositions shape) $ \(posIx, pos) -> do
    let elemPtr = matElemAddress dataPtr step pos
    for_ [0 .. channels - 1] $ \channelIx -> do
      e <- peekElemOff elemPtr $ fromIntegral channelIx
      VUM.unsafeWrite v (fromIntegral $ posIx + channelIx) e

dimsPositions (shape = []) producing [[]] results in pos = [], and thus the poke*/peek* is executed at least once, even though there exist no elements to run on. (matElemAddress just uses sum [] in that case, thus producing an invalid element offset of 0` -- the first element, when there are none.)

This commit fixes it by making dimPositions [] = [] instead of [[]], thus the for_ loops never bring a pos = [] into being.

Also:

roelvandijk commented 3 years ago

Thanks Niklas!