↓こういうツイートがバズっていたので、実際に組んでみた。
修士の頃、授業の課題でC言語書いてる時にどうしても謎のエラーが出て困っていた。それを見たSE経験(金融系)がある社会人大学院生の同期の女性が「ここにスペースを入れてみて」「もっと沢山、もっともっと」と言い出して、スペースを11個ほどコードに挟み込んだらエラーが消えた。怖かった
— ふくさんのグッドフクサニティ賞 (@fukusanity) February 20, 2020
バグのあるコード
たとえば、”hogehoge”という文字列の、”o”を”piyopiyo”に置換する、というプログラムをこう書く。
(2/22 11時追記:destのナル終端忘れていたので修正しました。ナル終端は今回のバグとは関係ないです)
#include <stdio.h>
void replace(char *dest, char *src) {
while (*src != '\0') {
if (*src != 'o') {
*dest++ = *src++;
} else {
*dest++ = 'p';
*dest++ = 'i';
*dest++ = 'y';
*dest++ = 'o';
*dest++ = 'p';
*dest++ = 'i';
*dest++ = 'y';
*dest++ = 'o';
*src++;
}
}
*dest = '\0';
}
void hoge() {
char str1[] = "fuga";
char str2[] = "";
char str3[] = "hogehoge";
replace(str2,str3);
printf("%s\n", str2);
}
void main() {
hoge();
}
実行してみる
hpiyopiyogehpiyopiyoge
Segmentation fault
この通り、なんとか動きはするがセグメンテーション違反を起こす。
ちなみにコンパイラはgcc。他の環境だと別の挙動になるかもしれない。
直ったコード
一見無関係に見える、”fuga”の部分にスペースを大量に注入する。
#include <stdio.h>
void replace(char *dest, char *src) {
while (*src != '\0') {
if (*src != 'o') {
*dest++ = *src++;
} else {
*dest++ = 'p';
*dest++ = 'i';
*dest++ = 'y';
*dest++ = 'o';
*dest++ = 'p';
*dest++ = 'i';
*dest++ = 'y';
*dest++ = 'o';
*src++;
}
}
*dest = '\0';
}
void hoge() {
char str1[] = "fuga "; // スペース注入
char str2[] = "";
char str3[] = "hogehoge";
replace(str2,str3);
printf("%s\n", str2);
}
void main() {
hoge();
}
実行してみる
hpiyopiyogehpiyopiyoge
セグメンテーション違反しなくなる。
問題
さてここで問題です。
- そもそもなぜセグメンテーション違反していたのでしょうか。
- スペースを入れることでセグメンテーション違反が解決したのはなぜでしょうか。
- この直し方はもちろん正攻法ではありません。どう直すべきでしょうか。
C言語を学ぶ人は考えてみてください。正解はまわりのC言語ユーザーに聞いてみてね。
そしてC言語を学ばない人は「こんなクソみたいな言語一生使わんわ滅びろ」って思ってください。