"Instruksi perangkat keras ilegal" dari kode yang sangat sederhana

9

Saat menyelidiki klaim yang meragukan , saya menulis program uji kecil ininoway.c

int proveit()
{
    unsigned int n = 0;
    while (1) n++;
    return 0;
}

int main()
{
    proveit();
    return 0;
}

Menguji ini, saya mendapatkan:

$ clang -O noway.c
$ ./a.out
zsh: illegal hardware instruction  ./a.out

Wat.

Jika saya kompilasi tanpa optimisasi, itu hang seperti yang diharapkan. Saya melihat ke pertemuan, dan tanpa semua lonceng dan peluit, mainfungsinya terlihat seperti ini:

_main:                                  ## @main
    pushq   %rbp
    movq    %rsp, %rbp
    ud2

Di mana ud2rupanya adalah instruksi khusus untuk perilaku yang tidak terdefinisi. Klaim meragukan yang disebutkan di atas, "Fungsi yang tidak pernah kembali adalah UB", diperkuat. Saya masih merasa sulit untuk percaya. Betulkah!? Anda tidak dapat dengan aman menulis putaran putaran?

Jadi saya kira pertanyaan saya adalah:

  1. Apakah ini pembacaan yang benar tentang apa yang sedang terjadi?
  2. Jika demikian, dapatkah seseorang mengarahkan saya ke sumber daya resmi yang memverifikasinya?
  3. Apa situasi di mana Anda ingin jenis optimasi terjadi?

Info yang relevan

$ clang --version
Apple clang version 11.0.0 (clang-1100.0.20.17)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
luqui
sumber
3
IIRC, yang ditandatangani adalah overflow UB.
wildplasser
1
^^^^ ie int n = 0===> unsigned int n = 0;atau lebih baik lagi ..while (1);
WhozCraig
1
Hmmm ... Dentang Penjelajah Kompiler mendapatkan instruksi lompat sasaran sendiri dengan -O gcc.godbolt.org/z/NTCQYT dan terjemahan baris demi baris tanpa itu. Tampak konsisten di banyak versi. Tapi saya juga ingat (meskipun tidak akan mencarinya) bahwa standar C mengatakan non-terminasi adalah ub jika efek sampingnya gratis . Inilah Hans Boehm yang menjelaskan bahwa ini memungkinkan optimisasi kompiler yang dinyatakan tidak mungkin: open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
Gene
1
Perilaku tidak terdefinisi ditandai integer overflow, bukan loop infinite. Anda dapat memperbaikinya dengan menggunakanunsigned int
MM
2
@ Gen Saya tidak berpikir itu mengatakan itu. Loop bebas efek samping dengan ekspresi non-const yang mengendalikan dapat diasumsikan berakhir ( port70.net/~nsz/c/c11/n1570.html#6.8.5p6 ) tetapi looping sibuk harus baik-baik saja. UB dalam integer overflow, meskipun saya tidak dapat mereproduksi contoh dengan instruksi UD.
PSkocik

Jawaban:

3

Jika Anda mendapatkan ud2 untuk kode yang sekarang ada dalam pertanyaan, maka kompiler bukanlah kompiler C yang sesuai. Anda dapat melaporkan bug kompilator.

Perhatikan bahwa dalam C ++ kode ini sebenarnya adalah UB. Ketika utas ditambahkan (masing-masing C11 dan C ++ 11), ada jaminan kemajuan kemajuan untuk utas apa pun, termasuk utas eksekusi utama dari program yang tidak multi-utas.

Dalam C ++ semua utas akhirnya harus berkembang, tanpa pengecualian. Namun dalam C, loop yang ekspresi pengontrolnya adalah ekspresi konstan tidak diperlukan untuk maju. Pemahaman saya adalah bahwa C menambahkan pengecualian ini karena sudah menjadi praktik yang umum dalam embedded coding untuk menggunakan a while(1) {}untuk menggantung utas.

Pertanyaan serupa dengan jawaban yang lebih terperinci

MM
sumber
Ya saya memang mendapatkan ud2dari kode C, tapi terima kasih telah menyertakan info tentang C ++ forward progress guarantee (sebuah istilah yang kelihatannya saya akan dapat meneliti) yang sebenarnya saya tanyakan tetapi mendapat, eh, dioptimalkan sebagai Saya sedang mempersiapkan pertanyaan.
luqui
Ungkapan yang lebih baik dari apa yang saya pikir Komite Standar coba katakan adalah bahwa jika menunda segala sesuatu dalam satu lingkaran melewati operasi tertentu tidak akan mempengaruhi perilaku program, menunda pelaksanaan loop sebagai keseluruhan masa lalu bahwa operasi tidak akan dianggap sebagai perubahan perilaku yang dapat diamati.
supercat