![プログラミング プログラミング](https://srad.jp/static/topics/programming_64.png)
LLVM、定数として宣言されたメモリ領域への代入を削除する最適化を導入 160
ストーリー by hylom
そんな使い方があるのか 部門より
そんな使い方があるのか 部門より
LLVM 9.0では、定数として宣言されたメモリ領域への代入については「実行されないコード」と判定して削除するような振る舞いになったという(リリースノート、@shafikyaghmour氏のTweet、@shyouhei氏のTweet)。
これは、たとえばC/C++で「const」キーワード付きで宣言された変数をキャストを使って非constなものとして扱った際などに発生しうる。この結果、LLVMでコンパイルした際に今まで発生していなかった不具合が生じる可能性があるようだ。
キャストでconstを外すのがバグではなく (スコア:1)
その結果定数メモリへの書き込みが発生するのがバグ
Re:キャストでconstを外すのがバグではなく (スコア:1)
組み込みやってるとconst領域はROMに確保されるのが当たり前だったのでconst付シンボルの中身を書き換えてるソース見て何だこりゃ?って思ったっけ。
(そのソースをそのまま組み込み機に移植したら動かなくなったのを思い出した)
#それを相性問題で片づけたのはうちの上司
#(Windowsプログラマ部隊より立場弱くて、更に「実績のあるソースだからそのまま使え」の通達付きだった)
Re: (スコア:0)
組み込みで使われがちなbusyboxもこのバグを踏んでいたというのがなんとも
Re: (スコア:0)
>const領域はROMに確保されるのが当たり前
それをリンカに指定するまでが組み込みプログラマの責任
セクションて知ってる?
(方言でセグメントと言うかもしれん)
それにしてもすごい会社だなそこ
Re: (スコア:0)
ところで、定数が定数であることはだれの責任なんでしょう?
当時とった解決策(既設ソースは変更不可のため)。
RAMが無駄に余裕があったので、全セクションをROMに配置したのち
起動時にROM領域を全部RAMにコピーしてジャンプする疑似ブートローダーのバイナリ作って
ビルド済みライブラリとしてROMイメージにくっつけた。
#要はPC(Windows)と同じくconstも初期値付き変数も、全部RAM上ならいいんでしょ。となった。
#後にGPIOの空き端子にジャンパピンが追加され、新旧2種類のROMイメージから起動できるようになった。
#当然最初の要求仕様にはない追加仕様で泣きつかれた結果である
Re: (スコア:0)
ポインタ経由すればconst付きで宣言した変数の書換だってできますからね。
まあROMに書き込見たいときとか値を固定したいときはdefine使えと。
Re: (スコア:0)
constはその領域が定数メモリ(ROM)である事を宣言するものではないので
キャストの結果書き込みが発生しても、それはプログラマが書いた通りの挙動。
例えばBIOS ROMがFlash Memoryだとして、普段は読み出し前提でconstを付けてるけど
BIOS更新用の関数内だけはあえて非constにして書き換えを出来るようにしたとして
それはバグでもなんでもないわけです。
# そんな書き方をしたソースじゃ後でメンテで死ぬ、という話は別問題
Re: (スコア:0)
C++のconstはオブジェクトの定数性を示すものであって、定数ではない(ことにできる)。
すくなくともクラスのインスタンスは。(ref. mutable)
たとえばキャッシュを内蔵したクラスで使ってるのを見たことがある。
Re: (スコア:0)
非修飾型へのポインタを修飾型へのポインタにキャストするのは許容されているが、逆は未定義動作だろ
Re:キャストでconstを外すのがバグではなく (スコア:1)
すくなくともC++では未定義ではないな。
それ経由で書き込むと未定義。読むのはOK。
Re:キャストでconstを外すのがバグではなく (スコア:1)
C++は知らんが、Cではポインタの型変換について修飾付ける方向のしか規格に記載されていないから、const外しキャストは未定義動作になる。
strchrとか標準関数ですらreturn値でconst外してくるあたり、規格自体が狂ってる感はあるけども。
Re:キャストでconstを外すのがバグではなく (スコア:1)
strchr自体は、strを書き換えないので、引数はconstでいい。
戻りは、呼び出し元が書き換えたいニーズもあるので、裸でいい。でないとキャストがいる。
書き換えないなら、const char*な変数にでもうければいい。こっちはキャストいらない。
Re:キャストでconstを外すのがバグではなく (スコア:1)
castがお嫌いなら、Cには、unionってやつもあるけどねー。
だいたいconst剥がしキャストがC99で未定義とか誤解じゃろ。n1124読んだけど、書いてないだけで、undefinedと書いてあるわけじゃないし。
6.7.3.5には、const修飾されて定義されたobjectをnon-constなlvalue経由で書き換える行為はundefinedって書いてあるんだが。
コンパイルエラーまたは例外の方がありがたい (スコア:1)
どういったコードを想定してるの?
void main() {
const int a;
int *b;
b = (int*) &a;
*b = 1; /*この行が実行されない*/
}
て感じ?
Re:コンパイルエラーまたは例外の方がありがたい (スコア:2, おもしろおかしい)
修正してやったゾ
int main() {
extern const int a;
int *b;
b = (int*) &a;
*b = 1; /*この行が実行されない*/
}
https://godbolt.org/z/9pJHBg [godbolt.org]
Re:コンパイルエラーまたは例外の方がありがたい (スコア:1)
みんなが知りたいのは、
が1を返すのか、2を返すのか、アクセス違反で死ぬのか、だと思うけど。
https://godbolt.org/z/tqNafV [godbolt.org]
によるとどのバージョンでも、clangでは1でgccは2らしいんで、今更な気がする。クロスコンパイルができないのは、やっぱ仕様的にも未定義ってことじゃない?
規格的にはconstついてるとromに入れる動作はアリ(つまり、上の組み込み屋さんのは規格通り)らしいんで、確かにconstを取るキャストは失敗してもいいんだと思う。
Re: (スコア:0)
https://godbolt.org/z/9pJHBg [godbolt.org]
ありがとう。
久しぶりにアセンブリみたよ
Re: (スコア:0)
こうすると書き換えない?
__attribute__((noinline)) void sub01(int *b) { *b = 1; }
int main() {
extern const int a;
int *b;
b = (int*) &a;
sub01(b);
}
インライン有無で挙動が違うということ?
Re:コンパイルエラーまたは例外の方がありがたい (スコア:1)
意図なんてしてなくて、コンパイラがエラーって出すからキャストしたっていうのが多いんじゃ?
Re:コンパイルエラーまたは例外の方がありがたい (スコア:1)
こんなのもありますよ
void main() {
int b = 1; /*この行が実行されない*/
}
無警告 (スコア:1)
この話が邪悪なのはコンパイル時に無警告なこと。
普通は未使用変数があったくらいでも警告するのに、未実行で警告しないとか頭おかしい。
これが正規動作で修正されないなら LLVM 捨てるのが正解。
Re: (スコア:0)
オープンソースのプロジェクトなんだからさ、
要望があったらissue作るなりMLでリクエストするなりしたら?
Re:無警告 (スコア:1)
当然、要望は既に出てる。
警告どころか、実行不可能な文があるならコンパイル・エラーで止めるのが正しい気がする。
トラブルのわかっていて事前に対応しなかった開発者の見識が疑われる案件。
Re: (スコア:0)
要望ってどれ?
Re: (スコア:0)
開発者の見識が疑われるって誰か自分以外の偉い人が対応するのが当然てか?
こういうこと書くやつの見識こそ疑われるよ
Re: (スコア:0)
詳しい経緯聞いてからだろ。てか経緯教えろください
Re: (スコア:0)
たとえばぬるぽに書き込むコードに置き換えてくれる方が親切ではあるかもしれないわな。
Re: (スコア:0)
捨てるまではいかないが、検出できるのなら警告してくれるとありがたい
変なバグの温床になりそう (スコア:0)
理解できない振る舞いされるかもしれないから、不用意にconst使うなってルールが増えそうだね
不用意にキャストを使うな (スコア:0)
constがあれば発見できたはずのバグを見逃すリスクがまったく考慮されないのがいかにもありそう
「今まで発生していなかった不具合が生じる可能性」 (スコア:0)
これまでとの互換性を保つようなコンパイルオプションとか用意されてないのか?
Re:「今まで発生していなかった不具合が生じる可能性」 (スコア:1)
定数領域をいじるなんて未定義動作なんだから、普通にソース直せばいいだけ
ソースがいじれないほど保守的な案件なのに、コンパイラは最新バージョンのLLVMに上げろって奇妙な指示があるなら別だが
Re: (スコア:0)
理想を事も無げに言うだけじゃ、何も言ってないのと同じだわな
Re: (スコア:0)
ソース直すのが理想なわけ?
あんたんとこでは新しいコンパイラで顕在化したバグは直さないの?
Re: (スコア:0)
ソース直すのが理想なわけ?
あんたんとこでは新しいコンパイラで顕在化したバグは直さないの?
頭でっかち派とどろどろ現場動かないと意味無い派の熱い戦いですね。
理想と現実とどっちをとるかは人による。
Re: (スコア:0)
ソース直すか今使ってるコンパイラを使いつづけるのって、
業務用途の開発でも普通に選べる選択肢なんじゃねーの?
当たり前すぎて「何も言ってないのと同じ」ってならまだわかるが、
「理想」って、そんな手の届かない世界のことみたいに聞こえるのか…。
なんつーか、まぁ頑張れや。
Re: (スコア:0)
理想を事も無げに言うだけじゃ、何も言ってないのと同じだわな
未定義の動作に期待しておいて何を言ってるんだか。。。
Re: (スコア:0)
LLVMってAppleの資金とかApple信者とかが大量に入ってそうだから、
いつもの独善的なApple様の行動を鑑みるに、ないのではなかろうか(偏見)
Re: (スコア:0)
「頭悪そう」とか「自分に都合のいいことしか聞こえないのね」とか言われない?
Re: (スコア:0)
正しさの名の下に独善的な行為をしそうなのってGooglerの印象がある。
Appleは自社の得にならない事はやらんでしょ。
Re: (スコア:0)
Googleについてはそれに「自分のことは棚に上げて [it.srad.jp]」というのが加わる。
const_cast (スコア:0)
そもそも C++ には const_cast なるものがあるんだけど、
それはどうするつもりなんだろうか。
Re: (スコア:0)
型抽出メタの糖衣みたいなもんで強制mutable変換てわけじゃないやん
(Cの)const外しキャストは従来から違法だった? (スコア:0)
いきなりわけわからんTweet [twitter.com]が飛び出してきてびびった。
だったらどうしてC++のキャストは、static_cast、dynamic_cast、reinterpret_cast
そしてconstを外すだけのconst_castに分けられたんだ?
C形式のキャストだと何の為のキャストなのか見分けがつかないからだろ?
そしてconstをconst &にするconst_castなんて、かのBoostですら当たり前のように使われてる。違法でも何でもない。
テメーの中のマイルールを勝手に世間一般の常識にみたいに語るなよ。
Re:(Cの)const外しキャストは従来から違法だった? (スコア:1)
そのTweetはC++でなくてCだからね。
JISのC (C99相当)を読んでみたけど、修飾版へ変換してよいとは書いてあるけど、
逆は書いてないみたいだった。
C++は外せるけど。
const&についてだけど、C++11で確認したところ、constオブジェクトの領域は
確保する必要がないと書いてある。ただし参照されたときはそのように振る舞う
必要がある。
言語仕様を語る人は多いけど、規格票を確認する人は少ないみたい。
しかしJISもいいかげん改定してくれないかね。
Re: (スコア:0)
そのTweetはC++でなくてCだからね。
JISのC (C99相当)を読んでみたけど、修飾版へ変換してよいとは書いてあるけど、
逆は書いてないみたいだった。
C++は外せるけど。
C++ だと外せるんだ?
https://godbolt.org/z/YagQXH [godbolt.org]
https://godbolt.org/z/9pJHBg [godbolt.org]
Re: (スコア:0)
const修飾は外せるよ。
理解しにくい文章だったかなあ?
constオブジェクトの領域うんぬんは誤読だったかもしれん。
まあ、自分で規格を読んでみて。
これは内容が共有されるから (スコア:0)
指摘がそれなりにいろいろでるんだろうけど
UB的な類いで、サイレントに最適化で処理が消える系はいろいろあるので、そんなもんかなあ
という気分にはなる
# 良いかどうか微妙だけど、まあしょうがないかなあ
要するに、 (スコア:0)
.data セクションや .text セクションへの代入はできない、ってこれまで通りのことで、heap や stack にある const 変数は、const を外して代入しても OK じゃないの?
Re:要するに、 (スコア:1)
そもそもC/C++の規格はハードやOS等から独立して書かれてるわけで、
ROMだの何とかセクションだのセグメンテーションフォルトだのが規格に出てくるわけはなくて
そういうものに依存するような動作は未定義・処理系定義でどうなろうと自己責任てもんじゃないかと