Geliştirilmiş GCC 6 optimizer neden pratik C ++ kodunu kırıyor?


148

GCC 6'nın yeni bir optimize edici özelliği var : Her thiszaman boş olmadığını varsayar ve buna göre optimize eder.

Değer aralığı yayılımı artık C ++ üye işlevlerinin bu işaretçisinin boş olmadığını varsayar. Bu, genel boş işaretçi denetimlerini ortadan kaldırır, ancak bazı uygun olmayan kod tabanlarını da (Qt-5, Chromium, KDevelop gibi) bozar . Geçici bir geçici çözüm olarak -fno-delete-null-pointer-check'ler kullanılabilir. Yanlış kod -fsanitize = undefined kullanılarak tanımlanabilir.

Değişiklik belgesi bunu açıkça tehlikeli olarak nitelendiriyor çünkü şaşırtıcı miktarda sık kullanılan kodu ihlal ediyor.

Neden bu yeni varsayım pratik C ++ kodunu kıracak? Dikkatsiz veya bilgisiz programcıların bu belirli tanımlanmamış davranışa güvendiği belirli modeller var mı? Kimsenin yazdığını hayal edemiyorum if (this == NULL)çünkü bu çok doğal değil.


21
@ Umarım iyi bir şekilde demek istediniz. UB'yi çağırmamak için UB kodunun yeniden yazılması gerekir. Bu kadar basit. Heck, genellikle bunu nasıl başaracağınızı söyleyen SSS'ler vardır. Yani, gerçek bir sorun IMHO değil. Hepsi iyi.
Monica

49
Kodda kayıt dışı bırakma null işaretçiler savunan insanların görmek için hayran. Tek kelimeyle muhteşem.
SergeyA

19
@Ben, tanımsız davranışları istismar etmek çok uzun zamandır çok etkili optimizasyon taktiği oldu. Kodumu daha hızlı çalıştıran optimizasyonları sevdiğim için seviyorum.
SergeyA

17
SergeyA'ya katılıyorum. Tüm brouhaha başladı, çünkü insanlar thisörtük bir parametre olarak geçirilen gerçeğin üzerinde duruyor gibi görünüyorlar , bu yüzden daha sonra açık bir parametre gibi kullanmaya başlıyorlar. Değil. Bu bir null değerini kaldırdığınızda, tıpkı başka bir boş göstergenin kaydının kaldırıldığı gibi UB'yi çağırırsınız. Hepsi bu kadar. Nullptrs komutunu iletmek istiyorsanız , DUH adlı açık bir parametre kullanın . Daha yavaş olmayacak, herhangi bir clunkier olmayacak ve böyle bir API'ye sahip olan kod zaten iç kısımlarda derin, bu yüzden çok sınırlı bir kapsama sahip. Hikayenin sonu sanırım.
Monica'yı

41
Kudos kötü kod döngüsünü kırdığı için GCC -> kötü kodu desteklemek için verimsiz derleyici -> daha kötü kod -> daha verimsiz derleme -> ...
MM

Yanıtlar:


87

Sanırım iyi niyetli insanların çekleri ilk etapta neden yazacakları sorusu cevaplanmalıdır.

En sık karşılaşılan durum, doğal olarak oluşan özyinelemeli çağrının bir parçası olan bir sınıfınız varsa.

Olsaydı:

struct Node
{
    Node* left;
    Node* right;
};

C dilinde şunları yazabilirsiniz:

void traverse_in_order(Node* n) {
    if(!n) return;
    traverse_in_order(n->left);
    process(n);
    traverse_in_order(n->right);
}

C ++ 'da, bu bir üye işlevi yapmak güzel:

void Node::traverse_in_order() {
    // <--- What check should be put here?
    left->traverse_in_order();
    process();
    right->traverse_in_order();
}

C ++ 'ın ilk günlerinde (standardizasyondan önce), üye işlevlerin, thisparametrenin örtülü olduğu bir işlev için sözdizimsel şeker olduğu vurgulandı . Kod C ++ ile yazılmış, eşdeğer C'ye dönüştürülmüş ve derlenmiştir. thisNull ile karşılaştırmanın anlamlı olduğunu ve orijinal Cfront derleyicisinin de bundan faydalandığını gösteren açık örnekler bile vardı . C geçmişinden gelen, kontrol için bariz seçim:

if(this == nullptr) return;      

Not: Bjarne Stroustrup this, burada yıllar boyunca kuralların değiştiğinden bile bahsediyor

Ve bu uzun yıllar boyunca birçok derleyici üzerinde çalıştı. Standardizasyon gerçekleştiğinde bu değişti. Ve son zamanlarda, derleyiciler üye işlevini çağırarak yararlanarak başladı thisvarlık nullptrbu durum her zaman olduğu araçlar tanımsız davranış olduğunu falseve derleyici bunu ihmal serbesttir.

Bu, bu ağacın herhangi bir geçişini yapmak için aşağıdakilerden birini yapmanız gerektiği anlamına gelir:

  • Aramadan önce tüm kontrolleri yapın traverse_in_order

    void Node::traverse_in_order() {
        if(left) left->traverse_in_order();
        process();
        if(right) right->traverse_in_order();
    }

    Bu, HER çağrı sitesinde boş bir köke sahip olup olmadığınızı kontrol etmek anlamına da gelir.

  • Üye işlevi kullanma

    Bu, eski C stil kodunu (belki de statik bir yöntem olarak) yazdığınız ve nesneyle açıkça bir parametre olarak çağırdığınız anlamına gelir. Örneğin. çağrı Node::traverse_in_order(node);yerine yeniden yazmaya geri döndünüz node->traverse_in_order();.

  • Bu belirli örneği standartlara uygun bir şekilde düzeltmenin en kolay / en güzel yolunun aslında a yerine bir sentinel düğümü kullanmak olduğuna inanıyorum nullptr.

    // static class, or global variable
    Node sentinel;
    
    void Node::traverse_in_order() {
        if(this == &sentinel) return;
        ...
    }

İlk iki seçenekten hiçbiri çekici görünmüyor ve kod onunla this == nullptrkaçabilirken, uygun bir düzeltme kullanmak yerine kötü kod yazdılar .

Sanırım bu kod bazı bazıları this == nullptronları kontrol için gelişti .


6
1 == 0Tanımlanmamış davranışlar nasıl olabilir ? Basitçe false.
Johannes Schaub - litb

11
Çekin kendisi tanımlanmamış bir davranış değildir. Bu her zaman yanlıştır ve bu nedenle derleyici tarafından ortadan kaldırılır.
SergeyA

15
Hmm .. this == nullptrdeyim tanımlanmamış bir davranıştır, çünkü ondan önce bir nullptr nesnesinde üye işlevi çağırdınız, bu da tanımsızdır. Ve derleyici çek ihmal ücretsiz
jtlim

6
@Joshua, ilk standart 1998'de yayınlandı. Daha önce ne olursa olsun, her uygulamanın istediği buydu. Karanlık çağlar.
SergeyA

26
Heh, vay, kimsenin örnek işlevlerini çağırmaya dayanan bir kod yazdığına inanamıyorum ... örnek olmadan . İçgüdüsel olarak "traverse_in_order çağırmadan önce tüm kontrolleri yap" işaretli alıntıyı, thishiç null edilebilir olduğunu düşünmeden kullanmış olurdum . Belki de bu, SO'nun beynimdeki UB tehlikelerini oturtmak ve böyle tuhaf hackler yapmaktan vazgeçirmek için var olduğu bir çağda C ++ öğrenmenin yararıdır.
underscore_d

65

Bunu yapar çünkü "pratik" kod kırılmış ve başlamak için tanımlanmamış davranış içeriyordu. thisBir mikro optimizasyon dışında genellikle null değerinin dışında bir sıfır kullanmanın bir nedeni yoktur .

Bu tehlikeli bir uygulamadır, çünkü sınıf hiyerarşisi geçişi nedeniyle işaretçilerin ayarlanması null değeri null olmayana thisdönüştürebilir. Bu nedenle, en azından, yöntemleri null ile çalışması thisgereken sınıf, temel sınıf içermeyen bir son sınıf olmalıdır: hiçbir şeyden türeyemez ve türetilemez. Hızla pratikten çirkin-hack-ülkeye doğru yola çıkıyoruz .

Pratik açıdan, kodun çirkin olması gerekmez:

struct Node
{
  Node* left;
  Node* right;
  void process();
  void traverse_in_order() {
    traverse_in_order_impl(this);
  }
private:
  static void traverse_in_order_impl(Node * n)
    if (!n) return;
    traverse_in_order_impl(n->left);
    n->process();
    traverse_in_order_impl(n->right);
  }
};

Boş bir ağacınız varsa (ör. Root nullptr), bu çözüm hala traverse_in_order öğesini nullptr ile çağırarak tanımlanmamış davranışa güveniyordur.

Ağaç boşsa, yani boşsa, Node* rootüzerinde statik olmayan yöntemler çağırmanız gerekmez. Dönemi. Açık bir parametre tarafından örnek işaretçisini alan C-benzeri ağaç koduna sahip olmak gayet iyi.

Buradaki argüman, bir şekilde null örnek işaretçisinden çağrılabilecek nesneler üzerinde statik olmayan yöntemler yazmaya ihtiyaç duyduğu için kaynıyor gibi görünüyor. Böyle bir ihtiyaç yok. Bu tür bir kod yazmanın nesnelerle C yolu, C ++ dünyasında hala çok daha hoştur, çünkü en azından güvenli olabilir. Temel olarak, sıfır this, bu kadar dar bir kullanım alanına sahip, öyle bir mikro optimizasyondur ki, buna izin vermemek IMHO'nun mükemmel derecede iyi olmasıdır. Hiçbir ortak API null değerine bağlı olmamalıdır this.


18
@Ben, bu kodu yazan her şeyden önce yanlıştı. MFC, Qt ve Chromium gibi korkunç projeleri isimlendirmeniz komik. Onlarla iyi kurtuluş.
SergeyA

19
@Ben, Google'daki korkunç kodlama stilleri iyi biliniyor. Google kodunun parlayan örnek olduğuna inanan birçok kişi olmasına rağmen, Google kodu (en azından halka açık olarak) genellikle kötü yazılmıştır. Bu onların kodlama stillerini (ve üzerinde bulundukları sırada yönergeleri) tekrar ziyaret etmelerini sağlayacaktır.
SergeyA

18
@Ben Kimse bu cihazlardaki Chromium'u gcc 6 kullanılarak derlenmiş Chromium ile değiştirmez. Chcrommi gcc 6 ve diğer modern derleyiciler kullanılarak derlenmeden önce düzeltilmesi gerekir. Bu da büyük bir görev değil; thisçekler kimse elle hepsini aşağı avı varmış gibi yani değil, çeşitli statik kod analizörleri tarafından toplanır. Yama muhtemelen birkaç yüz sıra önemsiz değişiklik olacaktır.
Monica

8
@Ben Pratik anlamda, boş bir thisdereference anlık bir çöküştür . Kimse kod üzerinde statik bir analiz cihazı çalıştırmayı umursmasa bile bu problemler çok çabuk öğrenilecektir. C / C ++, "yalnızca kullandığınız özellikler için ödeme yapar" mantrasını takip eder. Eğer kontrol etmek istiyorsanız, onlar hakkında açık olmalısınız thisve derleyicinin thisboş olmadığını varsayacağı için , çok geç olduğunda bunları yapmamak anlamına gelir . Aksi takdirde kontrol etmek zorunda kalacaktı thisve kodun% 99.9999'u için bu tür kontroller zaman kaybı.
Monica

10
standardın bozulduğunu düşünen herkese tavsiyem: farklı bir dil kullanın. Tanımlanmamış davranış olasılığına sahip olmayan C ++ benzeri diller eksikliği yoktur.
MM

35

Değişiklik belgesi bunu açıkça tehlikeli olarak nitelendiriyor çünkü şaşırtıcı miktarda sık kullanılan kodu ihlal ediyor.

Belge buna tehlikeli demiyor. Ayrıca şaşırtıcı miktarda kodu ihlal ettiğini iddia etmez . Bu tanımsız davranışa dayandığı bilindiğini iddia ettiği ve geçici çözüm seçeneği kullanılmadıkça değişiklik nedeniyle bozulacağı iddia edilen birkaç popüler kod tabanına dikkat çeker.

Neden bu yeni varsayım pratik C ++ kodunu kıracak?

Eğer pratik c ++ kod tanımsız davranış dayanır, o zaman tanımsız davranış kırmak anlamına dönüşür. Bu nedenle, UB'den kaçınılmalıdır, buna dayanan bir program istendiği gibi çalışıyor gibi görünse bile.

Dikkatsiz veya bilgisiz programcıların bu belirli tanımlanmamış davranışa güvendiği belirli modeller var mı?

Yaygın anti- desen olup olmadığını bilmiyorum , ancak bilgisiz bir programcı yaparak programlarını çökmesini düzeltebilir düşünebilirsiniz:

if (this)
    member_variable = 42;

Asıl hata başka bir yerde boş gösterici kaldırıyorsa.

Programcı yeterince bilgisiz ise, bu UB'ye dayanan daha gelişmiş (anti) desenler ortaya çıkarabileceklerinden eminim.

Kimsenin yazdığını hayal edemiyorum if (this == NULL)çünkü bu çok doğal değil.

Yapabilirim.


11
"Pratik c ++ kodu tanımsız davranışa dayanıyorsa, tanımlanmamış davranışta yapılan değişiklikler onu bozabilir. Bu yüzden UB'den kaçınılmalıdır" this * 1000
underscore_d

if(this == null) PrintSomeHelpfulDebugInformationAboutHowWeGotHere(); Bir hata ayıklayıcının size kolayca anlatamayacağı bir dizi olayın okunması kolay güzel bir günlüğü gibi. Büyük bir veri kümesinde ani bir rastgele boş değer varken yazdığınız kodda saatlerce zaman harcamadan bunu şimdi hata ayıklayın. Ve bununla ilgili UB kuralı C ++ oluşturulduktan sonra daha sonra yapıldı. Eskiden geçerliydi.
Stephane Hockenhull

@StephaneHockenhull İşte -fsanitize=nullbunun için.
eerorika

@ user2079303 Sorunlar: Bu, üretim kodunu çalışırken check-in yapamayacağınız noktaya kadar yavaşlatacak mı, şirkete çok para mı mal olacak? Bu boyut artacak ve flaşa sığmayacak mı? Bu Atmel dahil tüm hedef platformlarda çalışıyor mu? Can -fsanitize=nullSSA'sını kullanılarak Raptiyeler # 5,6,10,11 SD / MMC karta hataları log? Bu evrensel bir çözüm değil. Bazıları null bir nesneye erişmenin nesne yönelimli ilkelere aykırı olduğunu savunurken, bazı OOP dillerinin üzerinde çalışılabilen bir null nesnesi vardır, bu yüzden OOP'un evrensel bir kuralı değildir. 1/2
Stephane Hockenhull

1
... bu tür dosyalarla eşleşen normal bir ifade? Örneğin, bir lvalue'ya iki kez erişilirse, aralarında kod birkaç belirli şeyden herhangi birini yapmadıkça bir derleyicinin erişimi birleştirebileceğini söyleyerek, kodun depolamaya erişmesine izin verilen kesin durumları tanımlamaya çalışmaktan çok daha kolay olacaktır.
Supercat

25

Kırılan "pratik" ("buggy" hecelemenin komik yolu) kodlarından bazıları şöyle görünüyordu:

void foo(X* p) {
  p->bar()->baz();
}

ve p->bar()bazen boş bir işaretçi döndürdüğü gerçeğini hesaba katmayı unutur, bu da çağırmak baz()için kayıttan çıkarmanın tanımsız olduğu anlamına gelir .

Bozulan tüm kodlar açık if (this == nullptr)veya if (!p) return;kontrol içermiyordu. Bazı durumlar, herhangi bir üye değişkenine erişim sağlamayan işlevlerdi ve bu nedenle düzgün çalışıyor gibi görünüyordu . Örneğin:

struct DummyImpl {
  bool valid() const { return false; }
  int m_data;
};
struct RealImpl {
  bool valid() const { return m_valid; }
  bool m_valid;
  int m_data;
};

template<typename T>
void do_something_else(T* p) {
  if (p) {
    use(p->m_data);
  }
}

template<typename T>
void func(T* p) {
  if (p->valid())
    do_something(p);
  else 
    do_something_else(p);
}

Bu kodda func<DummyImpl*>(DummyImpl*)bir boş gösterici ile arama yaptığınızda , gösterilecek göstericinin "kavramsal" bir referansı vardır p->DummyImpl::valid(), ancak aslında üye işlevi falseerişmeden geri döner *this. Bu return falsesatır içi işaretlenebilir ve bu nedenle pratikte işaretçiye hiç erişilmesine gerek yoktur. Yani bazı derleyiciler ile Tamam gibi görünüyor: nere dereferencing için segfault yok p->valid(), yanlış, bu yüzden boş çağırıcılar için do_something_else(p)denetler ve hiçbir şey yapmaz , kod çağrıları . Çökme veya beklenmedik davranış gözlenmez.

GCC 6 ile hala çağrıyı alırsınız p->valid(), ancak derleyici şimdi bu ifadeden pboş olmamalıdır (aksi takdirde p->valid()tanımsız davranış olacaktır) ve bu bilgileri not eder. Çıkarılan bilgi optimize edici tarafından kullanılır, böylece çağrıyı do_something_else(p)satır içine alırsa, if (p)kontrol artık gereksiz kabul edilir, çünkü derleyici boş olmadığını hatırlar ve böylece kodu satır içine alır :

template<typename T>
void func(T* p) {
  if (p->valid())
    do_something(p);
  else {
    // inlined body of do_something_else(p) with value propagation
    // optimization performed to remove null check.
    use(p->m_data);
  }
}

Bu gerçekten boş bir işaretçi dereference ve bu nedenle daha önce çalışmak için görünen kod çalışmayı durdurur.

Bu örnekte, funcönce null olup olmadığını denetleyen hata (veya arayanlar bunu asla null ile çağırmamış olmalıdır):

template<typename T>
void func(T* p) {
  if (p && p->valid())
    do_something(p);
  else 
    do_something_else(p);
}

Unutulmaması gereken önemli bir nokta, bunun gibi çoğu optimizasyonun derleyicinin "ah, programcı bu işaretçiyi null'a karşı test ettiğini, sadece sinir bozucu olarak kaldıracağımı" söylemesi değil. Olan şey şu ki, satır içi ve değer aralığı yayılımı gibi çeşitli fabrika işletmesi optimizasyonları, bu kontrolleri gereksiz kılmak için bir araya geliyor, çünkü daha önceki bir kontrol veya bir dereference'den sonra geliyorlar. Derleyici, bir işlevde A noktasında bir işaretçinin boş olmadığını biliyorsa ve aynı işlevde daha sonraki bir B noktasından önce işaretçi değiştirilmezse, B'de de boş olmadığını bilir. A ve B noktaları aslında başlangıçta ayrı işlevlerde olan kod parçaları olabilir, ancak şimdi tek bir kod parçası halinde birleştirilmiştir ve derleyici, işaretçinin daha fazla yerde boş olmadığı bilgisini uygulayabilir.


GCC 6'yı, bu tür kullanımlarla karşılaştığında derleme zamanı uyarıları vermesi mümkün müdür this?
jotik


3
@jotik, ^ ^ ^ TC ne dedi. Bu mümkün olabilir, ancak TÜM KOD, TÜM ZAMAN için bu uyarıyı alırsınız . Değer aralığı yayılımı, hemen hemen her kodu, her yerde etkileyen en yaygın optimizasyonlardan biridir. Optimize ediciler, basitleştirilebilen kodu görürler. "Aptal UB'leri optimize edilirse uyarılmak isteyen bir salak tarafından yazılmış bir kod parçası" görmüyorlar. Derleyicinin "programlayıcının optimize edilmesini isteyip istemediğini kontrol et" ve "programlayıcının yardımcı olacağını düşündüğü, ancak gereksiz olduğunu fazladan kontrol" arasındaki farkı anlatması kolay değildir.
Jonathan Wakely

1
Kodunuzu geçersiz kullanımları da dahil olmak üzere çeşitli UB türleri için çalışma zamanı hataları vermek üzere kullanmak istiyorsanız this, sadece kullanın-fsanitize=undefined
Jonathan Wakely


-25

C ++ standardı önemli şekillerde kırılmıştır. Ne yazık ki, kullanıcıları bu sorunlardan korumak yerine, GCC geliştiricileri, tanımlanmamış davranışı, onlara ne kadar zararlı olduğu açık bir şekilde açıklanmış olsa bile, marjinal optimizasyonları uygulamak için bir bahane olarak kullanmayı seçmiştir.

Burada ayrıntılı olarak açıkladığımdan çok daha zeki bir insan. (C hakkında konuşuyor ama durum orada aynı).

Neden zararlıdır?

Basitçe, daha önce çalışan derleyicinin daha yeni bir sürümüyle güvenli kodu yeniden derlemek güvenlik açıkları oluşturabilir . Yeni davranış bir bayrakla devre dışı bırakılabilirken, varolan marka dosyalarında bu bayrak ayarlanmamıştır. Hiçbir uyarı üretilmediğinden, geliştiricinin daha önce makul olan davranışın değiştiği açık değildir.

Bu örnekte, geliştirici assertgeçersiz bir uzunluk sağlanırsa programı sonlandıracak olan tamsayı taşması için bir denetim ekledi . GCC ekibi, tamsayı taşmasının tanımsız olması nedeniyle denetimi kaldırmıştır, bu nedenle denetim kaldırılabilir. Bu, sorun çözüldükten sonra bu kod tabanının gerçek vahşi örneklerinin yeniden savunmasız kalmasına neden oldu.

Her şeyi okuyun. Seni ağlatmak için yeterli.

Tamam, peki ya bu?

O zamanlar, böyle bir şeye giden oldukça yaygın bir deyim vardı:

 OPAQUEHANDLE ObjectType::GetHandle(){
    if(this==NULL)return DEFAULTHANDLE;
    return mHandle;

 }

 void DoThing(ObjectType* pObj){
     osfunction(pObj->GetHandle(), "BLAH");
 }

Yani deyim şudur: pObjBoş değilse , içerdiği tutamacı kullanırsınız, aksi takdirde varsayılan tutamaç kullanırsınız. Bu GetHandleişlevde kapsüllenmiştir .

İşin püf noktası, sanal olmayan bir işlev çağırmanın aslında thisişaretçiyi kullanmamasıdır , bu nedenle erişim ihlali yoktur.

Hala anlamıyorum

Bu şekilde yazılmış birçok kod var. Birisi sadece bir satırı değiştirmeden yeniden derlerse, her çağrı DoThing(NULL)bir çökme hatasıdır - şanslıysanız.

Şanslı değilseniz, kilitlenen hatalara yapılan çağrılar uzaktan yürütme güvenlik açıkları haline gelir.

Bu otomatik olarak da gerçekleşebilir. Otomatik bir derleme sisteminiz var, değil mi? En son derleyiciye yükseltmek zararsız değil mi? Ama şimdi değil - derleyiciniz GCC ise değil.

Tamam, söyle onlara!

Onlara söylendi. Bunu sonuçların tam bilgisi ile yapıyorlar.

ama neden?

Kim söyleyebilir? Belki:

  • C ++ dilinin gerçek koda göre ideal saflığına değer verirler.
  • İnsanların standarda uymadığı için cezalandırılması gerektiğine inanıyorlar
  • Dünyanın gerçekliğini anlamıyorlar
  • Onlar ... bilerek böcekleri tanýtýyorlar. Belki yabancı bir hükümet için. Nerede yaşıyorsun? Bütün hükümetler dünyanın çoğuna yabancıdır ve çoğu dünyaya düşmanca davranır.

Ya da belki başka bir şey. Kim söyleyebilir?


32
Cevabın her satırına katılmıyorum. Sıkı takma adlandırma optimizasyonları için de aynı yorumlar yapıldı ve umarım bunlar reddedildi. Çözüm, kötü geliştirme alışkanlıklarına dayalı optimizasyonları önlemek değil, geliştiricileri eğitmektir.
SergeyA

30
Dediğin gibi her şeyi okudum ve okudum ve gerçekten ağladım, ama esas olarak Felix'in aptallığında, karşılaşmaya çalıştığın şey olduğunu sanmıyorum ...
Mike Vine

33
Yararsız rant için düşürüldü. "Onlar ... kasıtlı olarak böcek getiriyorlar. Belki de yabancı bir hükümet için." Gerçekten mi? Bu / r / komplo değil.
isanae

31
Terbiyeli programcılar tekrar tekrar mantra tekrarlamak tanımlanmamış davranış çağırmak değil , yine de bu nonks ileri gitti ve yine de yaptı. Bakın ne oldu. Hiç sempati duymuyorum. Bu geliştiricilerin hatası, bu kadar basit. Sorumluluk almaları gerekiyor. Bunu hatırla? Kişisel sorumluluk? İnsanlar "ama pratikte !" bu durum ilk etapta tam olarak nasıl ortaya çıktı. Bunun gibi saçmalıklardan kaçınmak, ilk etapta standartların var olmasının nedenidir. Standartları kodlayın ve bir sorununuz olmayacak. Dönemi.
Yörüngedeki Hafiflik Yarışları

18
"Daha önce çalışan, güvenli kod derleyicinin daha yeni bir sürümüyle yeniden derlemek, güvenlik açıkları oluşturabilir" - bu her zaman olur . Bir derleyicinin bir sürümünün sonsuzluğun geri kalanında izin verilecek tek derleyici olmasını istemiyorsanız. Linux çekirdeği sadece tam gcc 2.7.2.1 ile derlendiğinde hatırlıyor musunuz? Gcc projesi bile çatallandı çünkü insanlar bulcraptan bıkmışlardı. Bunu aşmak uzun zaman aldı.
MM
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.