目次: GCC
昨日(2018年3月23日の日記参照)でGCC 7とUbuntu 14.04のccache 3.1.9を組み合わせると、暗黙のフォールスルー警告が誤動作する現象を紹介しました。
int a(int i)
{
	switch (i) {
	case 0:
		i = 2;
		/* Fall through */
	case 1:
		i = 3;
		break;
	default:
		return 0;
	}
	return 0;
}
なぜそうなるのか、ざっと見てみました。使うのは下記のスクリプトです。引数をファイル /tmp/aaa.txtに「追記」でダンプした後、本物のGCCを起動するスクリプトです。
引数のダンプを標準出力に出さない理由は、標準出力がccacheに取られて見えないから、「追記」モードで出力する理由はccacheがgccを2回起動するからです。sleep 10を入れた理由は、引数に一時ファイルを指定されたとき消える前に見たいからです。
#!/bin/sh
echo $* >> /tmp/aaa.txt
sleep 10
gcc_ $*
使い方は /usr/bin/gccを /usr/bin/gcc_ にリネームし、このスクリプトを /usr/bin/gccとして配置するだけです。ではやってみましょうか。
-Wimplicit-fallthrough=3 -E a.c -Wimplicit-fallthrough=3 -c -o a.o a.c
最初にGCCをプリプロセッサのみ(-E)で起動し、次にGCCを元の引数(-c -o a.o a.c)で起動しています。
-Wimplicit-fallthrough=3 -c -E a.c -Wimplicit-fallthrough=3 -c -o /home/katsuhiro/.ccache/d/a/8431625291455df2df790a4c34be0d-395.o.tmp.blackbird.18397 /home/katsuhiro/.ccache/tmp/a.tmp.blackbird.18397.i
プリプロセッサのみで起動するところは同じですが、その後が違っていて、一時ファイルをコンパイルするように指定しています。このファイルが怪しいですね。
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "a.c"
int a(int i)
{
 switch (i) {
 case 0:
  i = 2;
 case 1:
  i = 3;
  break;
 default:
  return 0;
 }
 return 0;
}
見たところプリプロセッサ出力をそのまま保存しているようです。case 1: の前にあったコメント /* Fall through */ が消えていますので、-Wimplicit-fallthrough=3でも警告が出てしまいます。
GCC 6までは、元のコードと、プリプロセッサ出力(コメントが全て消える)の間で、警告内容に差は無かったのだろうと思われますが、-Wimplicit-fallthroughは「コメントの内容」によって動作が変わるオプションのため、誤動作を引き起こしたようです。
Ubuntu 14.04にGCC 7は採用されていませんが、クロスコンパイラなどでGCC 7とご対面する可能性があります(自分がそうでした)。
対策としては、
辺りが考えられます。
 この記事にコメントする
 この記事にコメントする
目次: GCC
会社で超ハマったのでメモしておきます。
GCC 7からswitch-case文において、暗黙のフォールスルーを警告する機能 -Wimplicit-fallthroughが実装されました。動作の仕様についてはRedHatの解説(リンク)が詳しいです。
フォールスルーの警告オプションは -Wimplicit-fallthrough=3のように指定しますが、オプションを直接指定するより-Wextraの指定により勝手にONにされている、というパターンが多いのではないでしょうか。ちなみに -WallではONになりません。
Ubuntu 14.04のccache 3.1.9とこのフォールスルー警告オプションを組み合わせると変な挙動を示します。まずはこんなプログラムを用意します。
int a(int i)
{
	switch (i) {
	case 0:
		i = 2;
		/* Fall through */
	case 1:
		i = 3;
		break;
	default:
		return 0;
	}
	return 0;
}
このプログラムは、フォールスルーの警告オプションのレベルを4以上にすると、警告が発生します。ちなみにデフォルトの警告レベルは3ですから、レベルを指定しない場合や、-Wextraなどでは警告は発生しません。
$ gcc --version gcc (Debian 7.3.0-11) 7.3.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc -Wextra a.c -c -o a.o ★警告無し★ $ gcc -Wimplicit-fallthrough a.c -c -o a.o ★警告無し★ $ gcc -Wimplicit-fallthrough=3 a.c -c -o a.o ★警告無し★ $ gcc -Wimplicit-fallthrough=4 a.c -c -o a.o a.c: In function ‘a’: a.c:5:5: warning: this statement may fall through [-Wimplicit-fallthrough=] i = 2; ~~^~~ a.c:7:2: note: here case 1: ^~~~
しかしUbuntu 14.04の古いccacheを経由してGCCを起動すると、おかしなことが起きます。警告されないはずのレベルを指定しても警告が出てしまうのです……。
$ ./ccache --version ccache version 3.1.9 Copyright (C) 2002-2007 Andrew Tridgell Copyright (C) 2009-2011 Joel Rosdahl This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. $ gcc -Wimplicit-fallthrough=3 a.c -c -o a.o ★警告無し★ $ ./ccache gcc -Wimplicit-fallthrough=3 a.c -c -o a.o a.c: In function ‘a’: a.c:5:5: warning: this statement may fall through [-Wimplicit-fallthrough=] i = 2; ~~^~~ a.c:7:2: note: here case 1: ^~~~ ★なぜか警告が出る★
とても不思議ですが、新しいccacheだとこの現象は発生しません。
$ ccache --version ccache version 3.4.1 Copyright (C) 2002-2007 Andrew Tridgell Copyright (C) 2009-2018 Joel Rosdahl This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. $ ccache gcc -Wimplicit-fallthrough=3 a.c -c -o a.o ★警告無し★
推測の域を出ませんがccacheのバグなんだろうなあとは思います。
Ubuntu 14.04のGCCは4.8なので、無関係かと思うかもしれませんが、外部から持ってきたクロスコンパイル用のツールチェーンでも同じことが起きます。x86用だろうがARM用だろうが、GCC 7のとある警告オプションを使うとハマります。
 この記事にコメントする
 この記事にコメントする
名古屋旅行の一つの目的である、リアル脱出ゲーム(進撃の巨人とのコラボ作品)に参加しました。少なくとも5回は参加していると思いますが、初めてクリアできました。やった。名古屋まで来た甲斐がありました。
一緒に参加した仲間に恵まれました皆さん経験者なのはもちろんのこと、問題解決のスピードも質も最高でした。
初クリアにして、パーフェクト(※)に解けました。充実感が凄い。
(※)問題が解けないけど、当てずっぽうで答えを推測などせず、全ての答えを導いてクリアしたという意味で使っています。
クリアしたチームは23チーム中4チームでした。
クリアして初めて分かったのですが、今まで参加したリアル脱出ゲームは、到底クリアできないペースだったことが良くわかりました……。脱出成功のときの、問題を解くペースは凄まじく早いです。
今回は6人チームで、チェックポイントごとに6問同時に問題が出るタイプでしたが、1人1問ずつ問題を即答しないと時間が足りません。
悩んで止まるとほぼクリアは無理です。
制限時間60分で、最終問題の答えを出した段階で、残り時間は10分くらいでした。
もしや一番最初にクリアできたか?と思ったのですが、一番ではありませんでした。上には上がいますねー。
メモ: 技術系の話はFacebookから転記しておくことにした。
 この記事にコメントする
 この記事にコメントする
| < | 2018 | > | ||||
| << | < | 03 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 | 
| - | - | - | - | 1 | 2 | 3 | 
| 4 | 5 | 6 | 7 | 8 | 9 | 10 | 
| 11 | 12 | 13 | 14 | 15 | 16 | 17 | 
| 18 | 19 | 20 | 21 | 22 | 23 | 24 | 
| 25 | 26 | 27 | 28 | 29 | 30 | 31 | 
 wiki
 wiki Linux JM
 Linux JM Java API
 Java API 2002年
 2002年 2003年
 2003年 2004年
 2004年 2005年
 2005年 2006年
 2006年 2007年
 2007年 2008年
 2008年 2009年
 2009年 2010年
 2010年 2011年
 2011年 2012年
 2012年 2013年
 2013年 2014年
 2014年 2015年
 2015年 2016年
 2016年 2017年
 2017年 2018年
 2018年 2019年
 2019年 2020年
 2020年 2021年
 2021年 2022年
 2022年 2023年
 2023年 2024年
 2024年 2025年
 2025年 過去日記について
 過去日記について アクセス統計
 アクセス統計 サーバ一覧
 サーバ一覧 サイトの情報
 サイトの情報合計: 
本日: