勝手に添削

Twitterで見かけたC言語プログラムを添削させていただく。C言語は10年近く触っているけど、ここ3年は離れていたので苦戦しました。

2008-05-30 – yaottiの日記 – ハチロク世代

まず問題なのがgetcharでの標準入力の取得にバッファオーバーランの脆弱性があることでしょう。終了条件がEOFの入力だけなので、10文字以上入力された場合、変数sの領域を超えてしまいます。終了条件を「EOFが入力された」「10文字入力された」の両方にします。

続いて入力を格納する変数の型がintなのが気になります。char型が適切なので変更します。char型配列には終端文字’\0’を入れるための領域が必要なため、それぞれの配列長を1バイト拡張します。11と21になるのですが、わかりにくいため、定数を使い、MAX_INPUT_LENGTH+1, MAX_INPUT_LENGTH*2+1とします。

続いて処理本体であるescape関数ですが、最初のチェック処理は動作しません。この館数に引数が渡された時点で最大長の情報は失っています。どちらも「int型の配列へのポインタ」となり、sizeof演算子を適用すると同じ数字が返ります。このチェックは常に偽となります。関数側で安全に処理できるかチェックしようとする心遣いは素晴らしいのですが、C言語では不可能なため、呼び出し側が責任を持って必要な長さの配列で呼び出すようにするしかありません。

処理本体ですが、処理内容は全く問題ありませんでした。なんとなく好みで作り替えてみました。for文に管理させる変数がi, jの二つだったのをiだけにしました。jは各caseが必要なだけ移動させるようにしています。タブと改行の際の処理が泥臭く感じられたので、strcpy関数に変えました。元のバージョンの方が処理効率はいいです。さらにstrconcat関数にすると変数jが不要になりますが、パフォーマンスは悪化します。

最後にソース。

#include 
#include 
#define MAX_INPUT_LENGTH 10
void escape(char s[], char t[]);
int main(int argc, char *argv[])
{
int	i;
char s[MAX_INPUT_LENGTH+1], t[MAX_INPUT_LENGTH*2+1];
printf("type characters less than %d.\n", MAX_INPUT_LENGTH);
for (i = 0; i < MAX_INPUT_LENGTH; i++) {
s[i] = getchar();
if (s[i] == EOF) break;
}
s[i] = '\0';
escape(s, t);
printf("%s\nend\n", t);
return 0;
}
void escape(char s[], char t[]) {
int i, j;
for (i = j = 0; s[i]; i++) {
switch (s[i]) {
case '\t':
strcpy(&t[j], "\\t");
j+=2;
break;
case '\n':
strcpy(&t[j], "\\n");
j+=2;
break;
default:
t[j] = s[i];
j++;
break;
}
}
t[j] = '\0';
return;
}

シェアする

  • このエントリーをはてなブックマークに追加

フォローする