naoki86star

インターネットの片隅でなにかしら書いてみる

golangでc言語バインドみたら注意したいこと

https://golang.org/cmd/cgo/にもあるおなじみのexample

package main

// #include <stdio.h>
// #include <stdlib.h>
//
// static void myprint(char* s) {
//   printf("%s\n", s);
// }
import "C"
import "unsafe"

func main() {
        cs := C.CString("Hello from stdio")
        C.myprint(cs)
        C.free(unsafe.Pointer(cs))
}

C.freeの大事さは、これをCで書いている時は反射的に気にするくせに、今どきの言語ならきっとよしなにとか考える甘い性格です。

このワンショットな実行だったらどうでもいいけどもC.CStringをあてにしてshared-libraryとか書き出してサービスプロセスとかに組み込みだしたら、C.freeを漏れなく呼び出すかは重大なタスクです。

当初(GOPATHがなにかも知らないような頃)は、goがよしなにやってくれると能天気な思い込みをしていたのが、「アレ?」という切実な現実をチラ見してしまい、リトマス試験を実行してみます。

$valgrind ./exe_withCfree
==30607== Memcheck, a memory error detector
==30607== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==30607== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==30607== Command: ./exe_withCfree
==30607==
==30607== Warning: ignored attempt to set SIGRT32 handler in sigaction();
==30607==          the SIGRT32 signal is used internally by Valgrind
==30607== Warning: ignored attempt to set SIGRT32 handler in sigaction();
==30607==          the SIGRT32 signal is used internally by Valgrind
==30607== Warning: client switching stacks?  SP change: 0xfff000240 --> 0xc4200447d8
==30607==          to suppress, use: --max-stackframe=773648041368 or greater
==30607== Warning: client switching stacks?  SP change: 0xc420044780 --> 0xfff0002f0
==30607==          to suppress, use: --max-stackframe=773648041104 or greater
==30607== Warning: client switching stacks?  SP change: 0xfff0002f0 --> 0xc420044780
==30607==          to suppress, use: --max-stackframe=773648041104 or greater
==30607==          further instances of this message will not be shown.
Hello from stdio
==30607==
==30607== HEAP SUMMARY:
==30607==     in use at exit: 1,440 bytes in 5 blocks
==30607==   total heap usage: 13 allocs, 8 frees, 2,657 bytes allocated
==30607==
==30607== LEAK SUMMARY:
==30607==    definitely lost: 0 bytes in 0 blocks
==30607==    indirectly lost: 0 bytes in 0 blocks
==30607==      possibly lost: 1,440 bytes in 5 blocks
==30607==    still reachable: 0 bytes in 0 blocks
==30607==         suppressed: 0 bytes in 0 blocks
==30607== Rerun with --leak-check=full to see details of leaked memory
==30607==
==30607== For counts of detected and suppressed errors, rerun with: -v
==30607== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
admin@test24 ~/n-ogawa/golang/src/n-ogawa/C $valgrind ./exe_withoutCfree
==30614== Memcheck, a memory error detector
==30614== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==30614== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==30614== Command: ./exe_withoutCfree
==30614==
==30614== Warning: ignored attempt to set SIGRT32 handler in sigaction();
==30614==          the SIGRT32 signal is used internally by Valgrind
==30614== Warning: ignored attempt to set SIGRT32 handler in sigaction();
==30614==          the SIGRT32 signal is used internally by Valgrind
==30614== Warning: client switching stacks?  SP change: 0xfff000240 --> 0xc4200447d8
==30614==          to suppress, use: --max-stackframe=773648041368 or greater
==30614== Warning: client switching stacks?  SP change: 0xc420044780 --> 0xfff0002f0
==30614==          to suppress, use: --max-stackframe=773648041104 or greater
==30614== Warning: client switching stacks?  SP change: 0xfff0002f0 --> 0xc420044780
==30614==          to suppress, use: --max-stackframe=773648041104 or greater
==30614==          further instances of this message will not be shown.
Hello from stdio
==30614==
==30614== HEAP SUMMARY:
==30614==     in use at exit: 1,457 bytes in 6 blocks
==30614==   total heap usage: 13 allocs, 7 frees, 2,657 bytes allocated
==30614==
==30614== LEAK SUMMARY:
==30614==    definitely lost: 17 bytes in 1 blocks
==30614==    indirectly lost: 0 bytes in 0 blocks
==30614==      possibly lost: 1,440 bytes in 5 blocks
==30614==    still reachable: 0 bytes in 0 blocks
==30614==         suppressed: 0 bytes in 0 blocks
==30614== Rerun with --leak-check=full to see details of leaked memory
==30614==
==30614== For counts of detected and suppressed errors, rerun with: -v
==30614== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

C.free呼ばないと思いっきり陽性です。。。
こんな簡単な実験を、現実を見たくがないゆえ、今までやらずにいました。