The Following Code Causes Segfault in Clang

  • If your are looking for code to break a C compiler, you can try my tool Quest https://github.com/lindig/quest. It tries to to generate code that shows that a C compiler handles parameter passing wrong. I usually run it in a loop, like here on Mac OS X 10.9.4 witch gcc:

        :quest $ gcc --version
         Configured with: --prefix=/Library/Developer/CommandLineTools/usr  --with-gxx-include-dir=/usr/include/c++/4.2.1
         Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
         Target: x86_64-apple-darwin13.3.0
         Thread model: posix
    
        :quest $ while true; do 
         > ./main.native -test gcc -n 1 > foo.c
         > gcc -O2 -o foo foo.c 
         > ./foo || break
         > echo -n .
         > done
         ................................................................
         ................................................................
         .................................................
         Assertion failed: (b32 == b43), function callee_b0f, file foo.c, line 128.
         Abort trap: 6
    
    This means the tool found C code where parameter passing is not compiled properly. It took about 10 seconds to find this. The test case is pretty small:

        :quest $ wc foo.c 
    	 140     444    3485 foo.c
    
    The generated code that where the assertion checks that parameters are received correctly looks like this:

        static
        union bt8 *
        callee_b0f(struct bt4 *bp7,
    	double *bp8,
    	struct bt6 bp9,
    	float bp10,
    	struct bt7 bp11,
    	double bp12,
    	short int bp13,
    	...)
        {
    	va_list ap;
    	typedef int bd0;
    	typedef struct bt0 bd1;
    	typedef int bd2;
    	typedef union bt3 bd3;
    	bd0 b41;
    	bd1 b42;
    	bd2 b43;
    	bd3 b44;
    	
    	/* seed: 2040 */
    	va_start(ap, bp13);
    	QUEST_ASSERT(b34 == bp7);
    	QUEST_ASSERT(b35 == bp8);
    	QUEST_ASSERT(b36.b24.b18 == bp9.b24.b18);
    	QUEST_ASSERT(b36.b24.b19 == bp9.b24.b19);
    	QUEST_ASSERT(b36.b24.b20 == bp9.b24.b20);
    	QUEST_ASSERT(b36.b24.b21 == bp9.b24.b21);
    	QUEST_ASSERT(b36.b24.b22 == bp9.b24.b22);
    	QUEST_ASSERT(b36.b24.b23 == bp9.b24.b23);
    	QUEST_ASSERT(b36.b25 == bp9.b25);
    	QUEST_ASSERT(b36.b26 == bp9.b26);
    	QUEST_ASSERT(b37 == bp10);
    	QUEST_ASSERT(b38.b27 == bp11.b27);
    	QUEST_ASSERT(b39 == bp12);
    	QUEST_ASSERT(b40 == bp13);
    	b41 = va_arg(ap, bd0);
    	b42 = va_arg(ap, bd1);
    	b43 = va_arg(ap, bd2);
    	b44 = va_arg(ap, bd3);
    	QUEST_ASSERT(b30 == b41);
    	QUEST_ASSERT(b31.b0 == b42.b0);
    	QUEST_ASSERT(b32 == b43);
    	QUEST_ASSERT(b33.b10.b1 == b44.b10.b1);
    	va_end(ap);
    	return b29;
        }

  • While we're at segfaulting compiler's, here's what I found just a few days ago:

        python -S -c 'print("void f(){} int main(){return (" + "*"*10**7 + "f)();}")' | gcc -xc -
    
    (This is legal C -- look it up. Don't argue with me over the practical relevance of this please)

  • Hmm...

        Unable to find instantiation of declaration!
        UNREACHABLE executed at SemaTemplateInstantiateDecl.cpp:4384!
    
    Not quite so unreachable...

    https://gist.github.com/cwgreene/d689f010619310dbbc77

    https://github.com/llvm-mirror/clang/blob/b310439121c875937d...

  • Something I found last week that crashes with clang-503.0.40:

        template<class T> class foo
        {
        public:
    
            ~ foo()
            {
            }
    
            foo &operator = (const foo &rhs)
            {
                foo::~foo();
                new (this) foo (rhs);
    
                return *this;
            }
        };
    
        int main(int argc, char * argv[])
        {
            foo<int> a, b;
            b = a;
        }

  • Is there some legitimate reason to want to have A's destructor called twice on a single instance?

  • Something tells me C++ isn't the best thing to implement a compiler with.