tl; drasprintf一時的なポインタを呼び出さずに、単純に連結に使用できますか?
asprintfGNUによって導入され、他のいくつかのclib実装で採用された関数は、次のようなスキームを使用したcでの任意の連結に対する魅力的なソリューションです。
int i=0;
char *str = strdup(argv[i]);
while (argv[++i]) {
asprintf(&str,"%s %s",argv[i],str); // <=== This line
}
asprintf(&str,"%s\n",str);
メインと必要なインクルードに包まれているとき、これは私にとってはうまくいきます。
だが...
あちこちでメモリリークが発生していますか?Valgrindはそれが私の箱にあると言います。これはバグですか?
目の前にあるmanページには
asprintf()およびvasprintf()関数は、* retを、フォーマットされた文字列を保持するのに十分な大きさのバッファーへのポインターになるように設定します。このポインタをfree(3)に渡して、割り当てられたストレージが不要になったときに解放する必要があります。十分なスペースを割り当てることができない場合、asprintf()とvasprintf()は-1を返し、retをNULLポインターに設定します。
「新しいバッファへのポインタに設定する[...]」*retというフレーズがないので、関数がrealloc同じように使用していると思いがちですgetline。
何が問題になるのでしょうか?
int asprintf(char **ret, const char *format, ...);具体性のために署名を使用します。
asprintf実行がrealloc早すぎます。realloc(*ret)元のバッファーをエイリアスしたvarargsの1つを逆参照する前に実行できるように、関数を離れた場所に実装するとします。そのバッファは解放されており、これは技術的に未定義の動作です。これはバグを表します。asprintfバッファを読み取る前に、バッファに書き込みます。上記のコードでは、引数のすべての前にの内容argv[1]をコピーする関数をイメージできます。私が引用するマンページは、このケースを除外していないようです。*retva_argstrasprintffree *ret直接またはを使用してではありませんrealloc。これにより、問題番号(1)は回避されますが、上記のように使用するとメモリがリークします。繰り返しますが、そのマニュアルページはそれを除外していないようです。
回避策
asprintf上記のすべては、への単一の呼び出しをに置き換えることで回避できます。
{
char *newStr = NULL;
asprintf(newStr,"%s %s",argv[i],str);
free(str);
str = newStr;
}
しかし、それはかなり不格好です。
コンセンサス実装は、最初のコードサンプルが安全で正しいことを保証しますか?