NULL-deref veya sıfıra bölme gibi genellikle endişelendiğimiz çoğu UB türü çalışma zamanı UB'dir. Çalışma zamanı UB neden olacak bir işlev Derleme idam eğer derleyici çökmesine neden olmamalıdır. Belki sürece bu işlevi (ve görev ekseninde yol) kesinlikle kanıtlayabilirim olacak program tarafından yürütülecek.
(İkinci düşünceler: belki derleme zamanında şablon / constexpr gerekli değerlendirmeyi düşünmemiştim. Muhtemelen bu sırada UB, sonuçta ortaya çıkan işlev asla çağrılmasa bile çeviri sırasında keyfi tuhaflığa neden olabilir.)
Çeviri sırasında davranıyor ISO C ++ alıntı parçası Masalcı cevabı @ de ISO C standardında kullanılan dilin benzer. C şablonları içermez veyaconstexpr
, derleme zamanında zorunlu değerlendirmeyi .
Ancak eğlenceli gerçek : ISO C, bir notta, çevirinin sonlandırılması durumunda bir teşhis mesajı ile birlikte olması gerektiğini söylüyor. Veya "çeviri sırasında ... belgelenmiş bir şekilde davranmak". "Durumu tamamen görmezden gelmenin" çeviriyi durdurmayı içerdiğini düşünmüyorum.
Çeviri zamanı UB'yi öğrenmeden önce yazılmış eski cevap. Runtime-UB için doğrudur ve bu nedenle potansiyel olarak hala yararlıdır.
UB diye bir şey yoktur olur derleme sırasında. Bu olabilir görünür yürütmenin belli bir yol boyunca derleyici, ancak C ++ açısından bu henüz oldu yürütme varıncaya kadar bir fonksiyonu sayesinde icra yolu olduğu.
Bir programdaki derlemeyi bile imkansız kılan kusurlar UB değildir, sözdizimi hatalarıdır. Böyle bir program C ++ terminolojisine göre "iyi biçimlendirilmemiş" değildir (eğer standartlarım doğru ise). Bir program iyi biçimlendirilebilir ancak UB içerebilir. Tanımsız Davranış ve Kötü Biçim arasındaki fark, teşhis mesajı gerekmez
Bir şeyi yanlış anlamıyorsam, ISO C ++ bu programın doğru bir şekilde derlenmesini ve yürütülmesini gerektirir , çünkü yürütme asla sıfıra bölmeye ulaşmaz. (Pratikte ( Godbolt ), iyi derleyiciler sadece çalışan yürütülebilir dosyalar yaparlar. Gcc / clang bu konuda uyarır x / 0
, ancak bu konuda uyarır , ancak optimize ederken bile. Ancak yine de, düşük ISO C ++ 'nın uygulama kalitesinin ne kadar düşük olmasına izin verdiğini anlatmaya çalışıyoruz . / clang, programı doğru yazdığımı doğrulamak dışında pek kullanışlı bir test değildir.)
int cause_UB() {
int x=0;
return 1 / x;
}
int main(){
if (0)
cause_UB();
}
Bunun için bir kullanım durumu, C ön işlemcisini veya constexpr
değişkenleri ve bu değişkenler üzerinde dallanmayı içerebilir; bu, bu sabitlerin seçimleri için hiçbir zaman ulaşılamayan bazı yollarda anlamsızlığa yol açar.
Derleme zamanında görünür UB'ye neden olan yürütme yollarının hiçbir zaman alınmayacağı varsayılabilir, örneğin, x86 için bir derleyici ud2
, tanımı olarak bir (geçersiz talimat istisnasına neden olabilir) yayabilir cause_UB()
. Veya bir işlev içinde, bir tarafın kanıtlanabilir UB'ye if()
yol açması durumunda, dal kaldırılabilir.
Ancak derleyicinin diğer her şeyi mantıklı ve doğru bir şekilde derlemesi gerekir . Tüm yollar yok karşılaşma (veya karşılaşma kanıtlanamayan) UB hala yürütür olarak eğer C ++ soyut makine çalışan olduğu asm derlenmelidir.
Koşulsuz derleme zamanında görünür UB girişinin main
bu kuralın bir istisnası olduğunu iddia edebilirsiniz . Veya başka türlü derleme zamanı kanıtlanabilir olan yürütmemain
aslında garantili UB'ye ulaşır.
Ben hala yasal derleyici davranışları bir el bombası olduğunu patlar üreten içerir iddia ediyorum eğer koşmak. Ya da daha makul bir şekilde, bunun tanımı main
tek bir yasadışı talimattan ibarettir. Programı hiç çalıştırmazsanız, henüz UB'nin olmadığını iddia ediyorum . Derleyicinin kendisinin patlamasına izin verilmez, IMO.
Dalların içinde olası veya kanıtlanabilir UB içeren işlevler
Herhangi bir yürütme yolu boyunca UB, önceki tüm kodu "kirletmek" için zamanda geriye doğru gider. Ancak pratikte derleyiciler bu kuraldan yalnızca yürütme yollarının derleme zamanında görünür UB'ye yol açtığını gerçekten kanıtlayabildiklerinde yararlanabilirler. Örneğin
int minefield(int x) {
if (x == 3) {
*(char*)nullptr = x/0;
}
return x * 5;
}
Derleyici, INT_MIN ve INT_MAX'ta işaretli taşma UB'ye neden x
olan noktalara kadar, 3 dışındaki tüm kullanıcılar için çalışan bir asm x * 5
yapmalıdır. Bu işlev asla çağrılmazsa x==3
, program elbette UB içermez ve yazıldığı gibi çalışmalıdır.
if(x == 3) __builtin_unreachable();
Derleyiciye bunun x
kesinlikle 3 olmadığını söylemek için GNU C'de yazmış olabiliriz .
Pratikte normal programlarda her yerde "mayın tarlası" kodu vardır. örneğin bir tamsayıya göre herhangi bir bölme, derleyiciye sıfır olmadığını vaat eder. Herhangi bir işaretçi deref, derleyiciye NULL olmadığını vaat eder.