C言語の罠ポイント(文字列)

久しぶりに素のC言語
やっぱりC言語の文字列周りは鬼門。
strcpyはバッファオーバーフローの危険があるから使わないようにってのはいいんだけど、対策として推奨されてるstrncpyがやっかい。

ダメパターン(バッファオーバーフローあり)

int _tmain(int argc, _TCHAR* argv[])
{
	char source[] = "teststrings";
	char copyed[4];
	strcpy(copyed, source);
	printf(copyed);

	return 0;
}

とりあえず、strcpyをstrncpyにしてみます。

int _tmain(int argc, _TCHAR* argv[])
{
	char source[] = "teststrings";
	char copyed[4];
	strncpy(copyed, source, sizeof(copyed));
	printf(copyed);

	return 0;
}

これでバッファオーバーフローはない・・・のですが問題があります。
実行結果がこちら

printfで表示してる文字が4文字以上になっています。
これはstrncpyの動作に罠があって

strncpy関数
char *strncpy(char * restrict s1,const char * restrict s2,size_tn);
s2が指す配列からs1が指す配列に文字をコピーするが、n文字を超えてコピーはしない。また、NULL文字より後の文字はコピーしない。
よって、s2が指す配列の最初のn文字の中にNULL文字がなければ、s1に格納される文字列はNULLで終端されない。

ぎりぎりサイズまでコピーするとNULLで終端されないのでprintfがバッファを越えて、NULLがでてくるまで表示し続けたわけです。

ちゃんとやるならこんな感じでしょうか。

int _tmain(int argc, _TCHAR* argv[])
{
	char source[] = "teststrings";
	char copyed[4];
	strncpy(copyed, source, sizeof(copyed));
	copyed[sizeof(copyed) - 1] = '\0';
	printf(copyed);

	return 0;
}

これ、忘れるよ・・・

参考:
sprintfのかわりのsnprintfはNULL終端されるのでこの問題は気にしなくてOK