ツールに依存しない方法が望ましいですが
言語仕様で説明される意味規則と実際に生成される機械語がどのように対応付けられるかはわかりません。 見かけ上の動作が仕様通りであれば書いた通りにコンパイルされなくてもよいことになっています。 プログラムの字面の上でメモリリークを発生させうるものであったとしても具体的にメモリリークとして観察できるかというのはわからないのです。
試しに、私はこのような (メモリの解放をしていない) プログラムを書いてみました。
c
1#include <stdlib.h>
2#include <stdio.h>
3
4int main(void) {
5 int *x = malloc(sizeof(int)*3);
6 x[0] = 1;
7 x[1] = 2;
8 x[2] = 3;
9 for(int i=0; i<4; i++)
10 printf("%d\n", x[i]);
11}
x86-64 をターゲットにした clang 11.0.0 で -O2
オプションを使ってコンパイルしたところ、以下のようなコードが生成されました。
asm
1main: # @main
2 push rax
3 mov edi, offset .L.str
4 mov esi, 1
5 xor eax, eax
6 call printf
7 mov edi, offset .L.str
8 mov esi, 2
9 xor eax, eax
10 call printf
11 mov edi, offset .L.str
12 mov esi, 3
13 xor eax, eax
14 call printf
15 mov edi, offset .L.str
16 xor eax, eax
17 call printf
18 xor eax, eax
19 pop rcx
20 ret
21.L.str:
22 .asciz "%d\n"
これは最適化の結果、以下のように書いた場合と同じだとみなされたということです。
c
1#include <stdio.h>
2
3int main(void) {
4 printf("%d\n", 1);
5 printf("%d\n", 2);
6 printf("%d\n", 3);
7}
字面の上ではメモリリークしているにもかかわらず、実際の実行プログラムはメモリリークしません。
実行時に malloc
や free
の呼出しを乗っ取ってチェックするタイプのツールではこのような間違いを検出できないのです。 ツールを選ぶならば、コンパイラと連携するか、静的解析を指向しているものを選んだ方がよりよいでしょう。
特定のツールに頼らず大抵のコンパイラ・実行環境で出来る範囲でということならば、マクロで書き換えて機能を乗っ取ってしまうという方法が考えられます。 (言語仕様の範囲では) メモリリークが発生するというのは malloc
calloc
realloc
で得たメモリが free
されないということですから、これらの呼出しを監視すればよく、たとえば gcc のコマンドで言えば
gcc -lmyalloc -Dmalloc=mymalloc -Dfree=myfree sample.c
といった要領で自前で定義した関数に置き換えることは出来ます。 置き換えた関数でログを取った上で本来の関数を呼び出すようにしておけばメモリの確保・解放の様子を監視することが出来るでしょう。
ただ、初心者のコードだとリークよりも不正アクセスの類の方が多いでしょうし、不正アクセスの挙動は (言語仕様上は) 未定義なので言語仕様の範囲内ではどうしようもありません。 ポータブルな解決方法は無いです。