warning: leak of ‘malloc’
警告:メモリ解放漏れ
[-Wanalyzer-malloc-leak]
■malloc-leakの例
#include <malloc.h>
void f1(void)
{
char *cp1 = malloc(100) ;
if(cp1 == NULL) {
return ;
}
char *cp2 = malloc(100) ;
if(cp2 == NULL) {
return ; // 先に確保済みの cp1 の解放忘れ!!
}
// 処理色々~~~~~~~
// 後始末
free(cp1);
free(cp2);
}
malloc()で確保した領域を解放し忘れると解放漏れ(メモリリーク)が発生します。
この例では cp1 の解放漏れが発生します。
■malloc-leak対策(推奨しないdo-while(0))
#include <malloc.h>
void f2(void)
{
char *cp1 = NULL ;
char *cp2 = NULL ;
do {
cp1 = malloc(100) ;
if(cp1 == NULL) {
break ;
}
cp2 = malloc(100) ;
if(cp2 == NULL) {
break ;
}
} while(0) ;
// 処理色々~~~~~~~
// 後始末
if(cp1) free(cp1);
if(cp2) free(cp2);
}
メジャールールで「関数の出口は一つだけ」と規定しているため、エラーが発生しても return ができないので
do ~ while(0) で全体処理を囲ってエラーが発生したら break するスタイルを採用しているプロジェクトが多くあります。
このメジャールールは
以前は「必須」だったのですが
現在は「推奨」に降格しています。
本来[関数の出口一つ]はコードを読みやすくするために構造化定理で提案されたものですが、do~while(0)構文を使用したこのコードは
読みにくなっているので本末転倒と言えるでしょう。
■malloc-leak対策(推奨)
#include <malloc.h>
void f3(void)
{
char *cp1 = NULL ;
char *cp2 = NULL ;
cp1 = malloc(100) ;
if(cp1 == NULL) {
goto err ;
}
cp2 = malloc(100) ;
if(cp2 == NULL) {
goto err ;
}
// 処理色々~~~~~~
err:
// 後始末
if(cp1) free(cp1);
if(cp2) free(cp2);
}
このように動的資源を複数回獲得した場合解放漏れが発生しやすいので 関数末尾にクリーナップ処理を設けそこにエラー発生時 goto で飛ぶ方法を推奨します。
注意事項:
cp1,cp2は関数の先頭でNULLで初期化する必要があります。
C99式に使用する直前で変数宣言すると
クリーンナップ処理で未初期化変数を参照する可能性があります。

参考: