user13582790
user13582790

Reputation:

How to get realpath with CGO?

I have a little bit of C code for getting the realpath that seems to work:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

char* getrpath(char *symlink) {
    char *symlinkpath = symlink;
    char actualpath [PATH_MAX];
    symlink = realpath(symlinkpath, actualpath);
    return symlink;
}


int main(int argc, char *argv[]) {
    char *symlinkpath = argv[0];
    symlinkpath = getrpath(symlinkpath);
    printf("%s\n", symlinkpath);
    return 0;
}

I am attempting to create a wrapper for it (for learning purposes only):

package main

/*
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

char* getrpath(char *symlink) {
    char *symlinkpath = symlink;
    char actualpath [PATH_MAX];
    symlink = realpath(symlinkpath, actualpath);
    return symlink;
}
*/
import "C"
import (
    "fmt"
    "os"
    "path"
    "unsafe"
)

func getArgv() string {
    return fmt.Sprintf("./%s", path.Base(os.Args[0]))
}

func main() {
    slink := C.CString(getArgv())
    defer C.free(unsafe.Pointer(slink))
    ret := C.getrpath(slink)
    fmt.Println(C.GoString(ret))
}

I am unable to get the the value back into the main() Golang function. If I place a print in the C getrpath() function, it prints the path. Any tips are greatly appreciated.

Upvotes: 1

Views: 235

Answers (2)

user13582790
user13582790

Reputation:

Okay ended up getting it but had to call C.realpath directly:

package main

/*
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func currentDir() []byte {
    return []byte{0x2e, 0x2f}
}

func rpath() string {
    relativePath := currentDir()
    limit := make([]byte, C.PATH_MAX)
    slink := make([]byte, len(relativePath)+1)
    copy(slink, relativePath)
    C.realpath(
        (*C.char)(unsafe.Pointer(&slink[0])),
        (*C.char)(unsafe.Pointer(&limit[0])))
    return C.GoString((*C.char)(unsafe.Pointer(&limit[0])))
}

func main() {
    fmt.Println(rpath())
}

Also I am not checking to see if it returns anything... might be better to check if actually using this.

Upvotes: 0

Paul Hankin
Paul Hankin

Reputation: 58349

The problem is that your C function is returning memory allocated on the C stack, which is undefined behavior in C (and likely to result in garbage values in practice):

char* getrpath(char *symlink) {
    char *symlinkpath = symlink;
    char actualpath [PATH_MAX];
    symlink = realpath(symlinkpath, actualpath);
    return symlink;
}

You need to return heap-allocated memory instead. Like this:

char* getrpath(char *symlink) {
    char *actualpath = malloc(PATH_MAX);
    return realpath(symlink, actualpath);
}

Or more simply -- because getpath is defined to malloc memory itself if you pass in NULL for the second argument:

char *getrpath(char *symlink) {
    return realpath(symlink, 0);
}

(I also removed the variable you introduced, but that's not the important part of the edit).

Upvotes: 1

Related Questions