3

I have a C program that calls a Haskell function. I want the Haskell function to be responsible for determining the size of the array (pointer) so I also want Haskell to malloc the pointer from C. I get an error when malloc_ is called in Haskell. I am not sure how to emulate the way malloc_ is called in C malloc_((void *)&ints,sizeof(int),10); into Haskell.

aux.c

void malloc_ (void **p, size_t size, int m) {
  *p = malloc(size*m);
}

main.c

int *ints;
// want to call this function in Haskell, C doesn't know how large the array is
// malloc_((void *)&ints,sizeof(int),10);

int ints_size = setIntArray(ints);

for (int i = 0; i < ints_size; i++) {
  printf("ints[%d]: %d\n", i, ints[i]);
}

Arrays.hs

#include "aux.h"
-- this might be wrong
foreign import ccall "malloc_" malloc_ :: Ptr (Ptr ()) -> CSize -> CInt -> IO ()

foreign export ccall "setIntArray" setIntArray :: Ptr CInt -> IO CInt
setIntArray :: Ptr CInt -> IO (CInt)
setIntArray is =  do
  let r = 10 :: Int

  -- if I remove this and malloc in C then it is fine
  malloc_ (castPtr is) (fromIntegral $ sizeOf is) (fromIntegral r)


  x <- addArrayElement r 0

  return $ fromIntegral x

  where
    addArrayElement :: Int -> Int -> IO Int
    addArrayElement r pointerCounter =
      case pointerCounter >= r of
        True  -> return r
        False -> do
          let x = 1234
          poke (advancePtr is pointerCounter) (x :: CInt)
          addArrayElement r (pointerCounter + 1)
3
  • Your C code in main.c is already wrong for what you want to do, since setIntArray(ints) cannot modify the value of ints itself, which it would need to do to have ints point to allocated memory after the call. Maybe you wanted to call setIntArray(&ints), with setIntArray of type Ptr (Ptr CInt) -> IO CInt? Commented Jun 6, 2015 at 17:20
  • Hmm, my code works fine if I do malloc_ in C and not Haskell and modifies the values. ints is already a pointer. If I am not mistaken the appropriate syntax should be setIntArray(ints), just double checked, if I setIntArrays(&ints) it gets a segmentation fault. I don't think it needs to be a double pointer, it is just 1D array being set. Commented Jun 6, 2015 at 17:34
  • But you had to pass &ints into malloc_, so that malloc_ could change the value of ints... the same will be true of setIntArray, if you want to move the allocation there. Commented Jun 6, 2015 at 17:43

1 Answer 1

1

Ignoring the other issues with your question, and just addressing the part about calling malloc: you have a few options.

  • malloc is already imported for you as malloc, or you can even use mallocArray in this case.

  • If you really want to import malloc yourself (maybe you actually want to use a different allocator), you'd make things more convenient for yourself by just returning the pointer value from your wrapper, like malloc itself does:

    void *malloc_ (size_t size, int m) {
      return malloc(size*m);
    }
    

    then foreign import ccall "malloc_" malloc_ :: CSize -> CInt -> IO (Ptr ()), and just call it.

  • If you really want to use this out-argument-style void malloc_ (void **p, size_t size, int m), then you have to allocate storage for a void *, so that you can pass its address as the first argument of malloc_, like you would do in C.

      my_allocated_pointer <- with nullPtr $ \pp -> do
        malloc_ pp (fromIntegral $ sizeOf (undefined :: CInt)) (fromIntegral 10)
        peek pp
    

    (This is now starting to get a bit silly, since with uses malloc internally... but it's the approach you would use in general.)

Sign up to request clarification or add additional context in comments.

3 Comments

The problem I was trying to solve is that I didn't see a way to allocate memory via the provided functions malloc or mallocArray and then mutate is to equal the memory I allocated. That's why I came up with importing malloc_. I don't fully understand with.
You can't do that regardless of malloc_ or anything else because your C type for setIntArray is wrong. That's what I was trying to explain in my comments. Just try writing the whole program in C with the allocation inside setIntArray and you will see the problem.
Ok, now I see what you mean about setInArray being wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.