I want to call a Nim proc from C which returns a cstring, the same as the 
"gimme" example at 
<https://nim-lang.org/docs/backends.html#memory-management-strings-and-c-strings>.
 I want to check that the way I am using the char array returned to C is sound.

This is a minimal example of my current approach, where the contents of the 
cstring returned by Nim are copied over to C-managed memory for further use.

In `gimme.nim` (following 
[this](https://nim-lang.org/docs/backends.html#memory-management-strings-and-c-strings)):
    
    
    import std/random
    
    proc gimme(): cstring {.exportc.} =
      result = "Hey there C code! " & $rand(100)
    
    
    Run

In `gimme_wrapped.c`:
    
    
    #include <stdio.h>
    #include <string.h>
    #define BUFFSIZE 1024
    #define MIN(x,y) (((x) <= (y)) ? (x) : (y))
    
    extern char* gimme(void);
    extern void NimMain();
    
    void gimme_wrapper(char* output, int maxlength) {
      NimMain();
      char* data_from_nim = gimme();
      // No more calls to nim till output is copied:
      for (int i=0; i<MIN(strlen(data_from_nim), maxlength); i++) {
        output[i] = data_from_nim[i];
      }
    }
    
    int main(void) {
      char output[BUFFSIZE] = "";
      gimme_wrapper(output, BUFFSIZE);
      printf("Data passed to C from Nim:\n%s\n", output);
      return 0;
    }
    
    
    Run

Set $NIM_LIB_PATH and build with:
    
    
    nim c --noMain --noLinking gimme.nim
    gcc -o gimme_wrapped -I$HOME/.cache/nim/gimme_d -I$NIM_LIB_PATH 
$HOME/.cache/nim/gimme_d/*.c gimme_wrapped.c
    
    
    Run

This apparently works OK and prints the expected result. I assume that as long 
as I make no more calls to Nim between the call to `gimme` and the C code that 
copies its output, Nim's garbage collector can be relied on not to free the 
memory holding the data of interest. My understanding is that it is only 
further calls to Nim resulting in memory allocation by Nim that will trigger 
garbage collection and result in possible corruption of the data.

I wanted to check that my assumptions are correct and that this is a reasonable 
approach. In particular this is because a slightly earlier version of the 
documentation contained a description of this approach which has since been cut 
("However, from a practical standpoint..." at 
<https://nim-lang.org/1.6.0/backends.html#memory-management-strings-and-c-strings>).
 Are there known circumstances where it could fail, or perhaps future plans 
that mean it should not be relied on? The use of `GC_ref` and `GC_unref` seems 
straightforward when calling C code from Nim, but less so when calling Nim from 
C. 

Reply via email to