Why does the enhanced GCC 6 optimizer break practical C++ code?

前端 未结 5 1993
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-28 03:19

GCC 6 has a new optimizer feature: It assumes that this is always not null and optimizes based on that.

Value range propagation now assum

5条回答
  •  暗喜
    暗喜 (楼主)
    2020-11-28 03:59

    The C++ standard is broken in important ways. Unfortunately, rather than protect the users from these problems, the GCC developers have chosen to use undefined behaviour as an excuse to implement marginal optimisations, even when it has been clearly explained to them how harmful it is.

    Here a much cleverer person than I explains in great detail. (He's talking about C but the situation is the same there).

    • https://groups.google.com/forum/m/#!msg/boring-crypto/48qa1kWignU/o8GGp2K1DAAJ

    Why is it harmful?

    Simply recompiling previously working, secure code with a newer version of the compiler can introduce security vulnerabilities. While the new behaviour can be disabled with a flag, existing makefiles do not have that flag set, obviously. And since no warning is produced, it is not obvious to the developer that the previously reasonable behaviour has changed.

    In this example, the developer has included a check for integer overflow, using assert, which will terminate the program if an invalid length is supplied. The GCC team removed the check on the basis that integer overflow is undefined, therefore the check can be removed. This resulted in real in-the-wild instances of this codebase being re-made vulnerable after the issue had been fixed.

    • https://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475

    Read the whole thing. It's enough to make you weep.

    OK, but what about this one?

    Way back when, there was a fairly common idiom which went something like this:

     OPAQUEHANDLE ObjectType::GetHandle(){
        if(this==NULL)return DEFAULTHANDLE;
        return mHandle;
    
     }
    
     void DoThing(ObjectType* pObj){
         osfunction(pObj->GetHandle(), "BLAH");
     }
    

    So the idiom is: If pObj is not null, you use the handle it contains, otherwise you use a default handle. This is encapsulated in the GetHandle function.

    The trick is that calling a non-virtual function doesn't actually make any use of the this pointer, so there is no access violation.

    I still don't get it

    A lot of code exists which is written like that. If someone simply recompiles it, without changing a line, every call to DoThing(NULL) is a crashing bug - if you are lucky.

    If you are not lucky, calls to crashing bugs become remote execution vulnerabilities.

    This can occur even automatically. You've got an automated build system, right? Upgrading it to the latest compiler is harmless, right? But now it's not - not if your compiler is GCC.

    OK so tell them!

    They've been told. They are doing this in the full knowledge of the consequences.

    but... why?

    Who can say? Perhaps:

    • They value the ideal purity of the C++ language over actual code
    • They believe people should be punished for not following the standard
    • They have no understanding of the reality of the world
    • They are ... introducing bugs on purpose. Perhaps for a foreign government. Where do you live? All governments are foreign to most of the world, and most are hostile to some of the world.

    Or perhaps something else. Who can say?

提交回复
热议问题