Search code examples
smalltalkvisualworksgemstone

Create a const char ** in Visual Works image


How i should create a (const char **) to pass it to a C function ?

Let say my const char ** is named prompts then:

user := 'User:' copyToHeap: #malloc:.    
pwd := 'Password:' copyToHeap: #malloc:.
prompts := (ByteArray new: 64) copyToHeap: #malloc:.
prompts copyAt: 0 from: (user referentAddress asByteArraySize: 32) size: 4 startingAt: 1.
prompts copyAt: 31 from: (pwd referentAddress asByteArraySize: 32) size: 4 startingAt: 1.

So prompts is an array of 64bits where the first 32bits are a pointer to user and the secods 32bits are a pointer to pwd.

But the C function is not working. In GemStone is working ok with:

prompts := CByteArray gcMalloc: 16.
user := CByteArray withAll: 'User:'.
pwd := CByteArray withAll: 'Password:'.
prompts uint64At: 0 put: user memoryAddress.
prompts uint64At: 8 put: pwd memoryAddress.

Solution

  • DLLCC offers some API very close to C. You need an array of two char pointers.

    prompts := CIntegerType char pointerType gcMalloc: 2.
    

    Then you can populate this array like this:

    prompts at: 0 put: user.
    prompts at: 1 put: pwd.
    

    Note that the indices mimic C like prompts[0]=user; prompts[1]=pwd;.

    Last thing, everything you malloc, you must then free, otherwise you'll get memory leaks.

    That means that you shall better protect all this code with some

    ["your protected code here"]
        ensure: [prompts free. user free. pwd free]`
    

    ...or worse...

    ["your protected code here"]
        ensure:
            [prompts isNil ifFalse: [prompts free].
            "etc..."]`.
    

    In early development, I suggest that you shall better use gcMalloc and gcMalloc:.

    AFTER THOUGHTS

    gcMalloc is maybe not a such good idea for userand pwd.

    This is because prompts will get a copy of the address of memory contained in user and pwd objects: it will point to same memory zone, but will not point to the Smalltalk objects...

    gcMalloc only monitor the garbage collection of Smalltalk objects. Hence, if Smalltalk objects are not more used, C heap might get freed prematurely despite some other objects point to the same C heap...

    Example:

    fillPrompts
        | user pwd prompts |
        user := 'User:' copyToHeap: #gcMalloc:.    
        pwd := 'Password:' copyToHeap: #gcMalloc:.
        prompts := CIntegerType char pointerType gcMalloc: 2.
        prompts at: 0 put: user.
        prompts at: 1 put: pwd.
        ^prompts
    

    copyToHeap: creates a CPointer object. As long as the method is active, its context point to those objects (thru slots on the stack).
    But after return of this method, there is not any object pointing to the CPointer objects.
    If some garbage collection occur, their associated pointer to C heap will be freed.

    But prompts still contain reference to already freed memory (the so called dangling pointers).

    DLLCC being very close to C, one must adopt the same care as when writing C code... And double pointers is a source of bugs for the vast majority of C programmers.