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で書いている時は反射的に気にするくせに、今どきの言語ならきっとよしなにとか考える甘い性格です。
このワンショットな実行だったらどうでもいいけども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@test-server ~/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呼ばないと思いっきり陽性です。。。
こんな簡単な実験を、現実を見たくがないゆえ、今までやらずにいました。