Bug in llvm/ADT/ArrayRef.h?

Hi,

I think I ran into a rather subtle bug inside llvm/ADT/ArrayRef.h which only shows up when compiling the code with GCC-4.8 with switched-off optimizations. (Both clang and GCC-4.7 don’t trigger the bug.)

I already filed a bug against GCC-4.8 which was rejected by the GCC-folks as being invalid, because the code (basically ArrayRef.h) “is doing something bad - it’s retaining a pointer to a temporary object across a function call.” They also provided a detailed explanation for their opinion, which I think is correct. See this link for the full story: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61015

The following program demonstrates the bug using LLVM’s own ArrayRef:
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS

#include
#include <llvm/ADT/ArrayRef.h>

class Obj {};
class SpecialObj : public Obj {};

int main()
{
SpecialObj* pSpecial = new SpecialObj();

llvm::ArrayRef<Obj*> arrayRef( pSpecial ); //Breaks on GCC-4.8.

/* Obj* pObj = pSpecial;
llvm::ArrayRef<Obj*> arrayRef( pObj ); //Possible Workaround */

int someStackArray[500];
memset( someStackArray, 0xdd, sizeof(someStackArray) );

if( arrayRef[0] != pSpecial )
printf( “This shouldn’t happen: %p\n”, arrayRef[0] );
else
printf( “Expected behaviour.\n” );
return 0;
}

Compiling (and then executing) this program with
g+±4.8 -Wall -O0 -std=c++11 -I./LLVM_SVN/installed/include main.cpp
prints: “This shouldn’t happen: 0xdddddddddddddddd”

Compiling with
clang++ -Wall -O0 -std=c++11 -I./LLVM_SVN/installed/include main.cpp
prints: “Expected behaviour.”

I think (as a quick fix) we should remove the const qualifier from ArrayRef’s CTor argument, so that the above code won’t compile anymore and thus avoiding a silent failure.
To be precise:
Change llvm/ADT/ArrayRef.h:57 from
ArrayRef(const T &OneElt)
: Data(&OneElt), Length(1) {}
to
ArrayRef(T &OneElt)
: Data(&OneElt), Length(1) {}

Best regards,
Andreas

I think you may have misread the explanation. I’m not entirely sure the explanation of the spec behaviour is correct, but let’s leave that discussion to people more knowledgeable then myself. If I’m reading the link above right, the issue is that you used: llvm::ArrayRef<Obj*> arrayRef( pSpecial ); Instead of: llvm::ArrayRef<SpecialObj*> arrayRef( pSpecial ); The former requires the creation of a temporary variable; the latter does not. GCC 4.8 exploits that temporary variable. Clang should if we don’t already. :slight_smile:

Hi,

I think I ran into a rather subtle bug inside llvm/ADT/ArrayRef.h which only
shows up when compiling the code with GCC-4.8 with switched-off
optimizations. (Both clang and GCC-4.7 don't trigger the bug.)

I already filed a bug against GCC-4.8 which was rejected by the GCC-folks as
being invalid, because the code (basically ArrayRef.h) "is doing something
bad - it's retaining a pointer to a temporary object across a function
call." They also provided a detailed explanation for their opinion, which I
think is correct. See this link for the full story:
61015 – Stack corruption with templates and pass-by-reference

I think you may have misread the explanation. I'm not entirely sure the
explanation of the spec behaviour is correct, but let's leave that
discussion to people more knowledgeable then myself.

If I'm reading the link above right, the issue is that you used:

llvm::ArrayRef<Obj*> arrayRef( pSpecial );
Instead of:
llvm::ArrayRef<SpecialObj*> arrayRef( pSpecial );

The former requires the creation of a temporary variable; the latter does
not. GCC 4.8 exploits that temporary variable. Clang should if we don't
already. :slight_smile:

Arnaud seems to be working on that (
http://llvm.org/viewvc/llvm-project?rev=213379&view=rev - though its
been reverted pending investigation of some failures it caused).