Cのコンパイルエラーの話 – オレオレアドベントカレンダー18日目
最近、C言語触ってますか?
はい、触ってませんでした。でも、RPMの作成とか、Docker build時に新しいパッケージをコンパイルしたり、configure オプション変えたりしたくなるときってあるじゃないですかー。
ということで、今回はDocker buildで問題がでました。
最新版を使いたいからEdgeを使う
Alpine Linuxでopenssl-1.1.1a を使いたいなら、Edgeを使うのが結局楽ということがわかったので、edgeベースでDockerイメージを作る訳ですよ。そうすると、コンパイラがgcc6 系になるんですが、それはいいんです。
そうすると、コンパイルエラーがポコポコ出てくるんですね。
よく出るCコンパイル時のエラー
unused-parameter
error: unused parameter 'cmd' [-Werror=unused-parameter]
XXX(char *cf, char *cmd, void *conf)
はい、よくある関数内で使ってない引数問題です。いっぱいありすぎるし、互換性の問題もあるので、-W-no-unused-parameter で逃げるしか無いです。
strncat() でのサイズオーバーフロー
error: 'strncat' specified bound 1 equals source length [-Werror=stringop-overflow=]
strncat((char*)tmp_hashname.data, "#", 1)
なんでこのエラーが発生するかと言うと、”#” はたしかに1文字なんですが、バイト数的には2バイトコピーが必要です。なぜなら、文字列は”\0″ でターミネートされないといけないからです。なので最後の1は間違いだし、tmp_hashname.data がmemset()などで0パディングされてないとうまく動かないコードになります。
こういうコードは、sizeof(“#”) と修正しましょう。
-Wno-stringop-overflow でこのエラーをスキップできますね。
strncopy() でのサイズ
error: 'strncpy' output truncated before terminating nul copying 17 bytes from a string of the same length [-Werror=stringop-truncation]
strncpy((char *)libjct_sql->sc_tag->data, (char *)"$LIBINJECTION_SQL", 17);
strncat()と同じで、文字列の長さが”\0″を考慮してません。sizeof (“$LIBINJECTION_SQL”) とかしましょう。っていうか、こういう文字列は #define するなり、設定ファイルにするなりすればいいのにね。
-Wno-stringop-truncation でこのエラーをスキップできます。
型のキャストがおかしい
error: cast between incompatible function types from 'size_t (*)(ngx_http_script_engine_t *)' {aka 'long unsigned int (*)(struct <anonymous> *)'} to 'void (*)(ngx_http_script_engine_t *)' {aka 'void (*)(struct <anonymous> *)'} [-Werror=cast-function-type]
copy->code = (ngx_http_script_code_pt)
だんだん何のコンパイルしているのか隠す気がなくなってきましたが、関数型のサイズが違うと行ってますね。もう面倒くさいので、-Wno-cast-function-type で逃げて良い気がしてきました。
ということで
Cが書けない人は、-W オプションを追加して乗り切りましょう。
Cが掛ける人は、できるだけパッチを書いて送りつけて、ドヤ顔しましょう。
なお、Cは書けるけど量が多すぎて嫌になって、-Wで逃げた人がこちらです。