bin/187103: clang 3.4 miscompiles nsAppRunner.cpp from firefox firefox-27.0.1,1 in i386
Don Lewis
truckman at FreeBSD.org
Fri Feb 28 07:05:11 UTC 2014
I managed to boil down the offending code to an almost reaonsable test
case.
If I compile the code below with clang thusly:
/usr/bin/clang++ -o sigill.s -S -fvisibility=hidden -fPIC \
-Qunused-arguments -Wall -Wpointer-arith -Woverloaded-virtual \
-Werror=return-type -Wtype-limits -Wempty-body -Wsign-compare \
-Wno-invalid-offsetof -Wno-c++0x-extensions -Wno-extended-offsetof \
-Wno-unknown-warning-option -Wno-return-type-c-linkage \
-Wno-mismatched-tags -O2 -pipe -march=athlon64 -fno-strict-aliasing \
-fno-exceptions -fno-strict-aliasing -fno-rtti -ffunction-sections \
-fdata-sections -fno-exceptions -fno-math-errno -std=gnu++0x -pipe \
-fno-omit-frame-pointer -pthread -D_THREAD_SAFE sigill.cpp
I get the following assembly code (note the ud2 instruction):
.file "sigill.cpp"
.section .text._Z9gensigillv,"ax", at progbits
.hidden _Z9gensigillv
.globl _Z9gensigillv
.align 16, 0x90
.type _Z9gensigillv, at function
_Z9gensigillv: # @_Z9gensigillv
# BB#0: # %entry
pushl %ebp
movl %esp, %ebp
pushl %ebx
andl $-8, %esp
subl $8, %esp
calll .L0$pb
.L0$pb:
popl %ebx
.Ltmp0:
addl $_GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb), %ebx
movl $0, (%esp)
leal (%esp), %eax
calll _ZN13nsCOMPtr_base16begin_assignmentEv at PLT
ud2
.Ltmp1:
.size _Z9gensigillv, .Ltmp1-_Z9gensigillv
.ident "FreeBSD clang version 3.4 (tags/RELEASE_34/final 197956) 20140216"
.section ".note.GNU-stack","", at progbits
Here's the source code:
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <sys/types.h>
#define NS_ERROR_MODULE_BASE_OFFSET 0x45
/* Helpers for defining our enum, to be undef'd later */
#define NS_ERROR_SEVERITY_SUCCESS 0
#define NS_ERROR_SEVERITY_ERROR 1
#define SUCCESS_OR_FAILURE(sev, module, code) \
((uint32_t)(sev) << 31) | \
((uint32_t)(module + NS_ERROR_MODULE_BASE_OFFSET) << 16) | \
(uint32_t)(code)
#define SUCCESS(code) \
SUCCESS_OR_FAILURE(NS_ERROR_SEVERITY_SUCCESS, MODULE, code)
#define FAILURE(code) \
SUCCESS_OR_FAILURE(NS_ERROR_SEVERITY_ERROR, MODULE, code)
typedef enum class tag_nsresult : uint32_t
{
#undef ERROR
#define ERROR(key, val) key = val
ERROR(NS_OK, 0)
#undef ERROR
} nsresult;
#define NS_OK nsresult::NS_OK
inline uint32_t NS_FAILED_impl(nsresult _nsresult) {
return static_cast<uint32_t>(_nsresult) & 0x80000000;
}
# define MOZ_LIKELY(x) (!!(x))
# define MOZ_UNLIKELY(x) (!!(x))
#define NS_FAILED(_nsresult) ((bool)MOZ_UNLIKELY(NS_FAILED_impl(_nsresult)))
#define NS_SUCCEEDED(_nsresult) ((bool)MOZ_LIKELY(!NS_FAILED_impl(_nsresult)))
//--
#define NSCAP_FEATURE_USE_BASE
#define NS_COM_GLUE
#define NS_FASTCALL __attribute__ ((regparm (3), stdcall))
#define NS_CONSTRUCTOR_FASTCALL __attribute__ ((regparm (3), stdcall))
#define NS_METHOD_(type) type
#define NS_METHOD NS_METHOD_(nsresult)
#define NS_IMETHOD_(type) virtual type
#define NS_IMETHOD NS_IMETHOD_(nsresult)
struct nsID {
/**
* @name Identifier values
*/
//@{
uint32_t m0;
uint16_t m1;
uint16_t m2;
uint8_t m3[8];
//@}
/**
* @name Methods
*/
//@{
/**
* Equivalency method. Compares this nsID with another.
* @return <b>true</b> if they are the same, <b>false</b> if not.
*/
inline bool Equals(const nsID& other) const {
// Unfortunately memcmp isn't faster than this.
return
((((uint32_t*) &m0)[0] == ((uint32_t*) &other.m0)[0]) &&
(((uint32_t*) &m0)[1] == ((uint32_t*) &other.m0)[1]) &&
(((uint32_t*) &m0)[2] == ((uint32_t*) &other.m0)[2]) &&
(((uint32_t*) &m0)[3] == ((uint32_t*) &other.m0)[3]));
}
//@}
};
typedef nsID nsIID;
typedef nsID nsCID;
#define REFNSIID const nsIID&
#if 0
#define NS_DECLARE_STATIC_IID_ACCESSOR(the_iid) \
template <class Dummy> \
struct COMTypeInfo \
{ \
static const nsIID kIID; \
}; \
static const nsIID& GetIID() {return COMTypeInfo<int>::kIID;}
#endif
typedef uint32_t nsrefcnt;
class nsISupports {
public:
#if 0
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISUPPORTS_IID)
#endif
/**
* @name Methods
*/
//@{
/**
* A run time mechanism for interface discovery.
* @param aIID [in] A requested interface IID
* @param aInstancePtr [out] A pointer to an interface pointer to
* receive the result.
* @return <b>NS_OK</b> if the interface is supported by the associated
* instance, <b>NS_NOINTERFACE</b> if it is not.
*
* aInstancePtr must not be null.
*/
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0;
/**
* Increases the reference count for this interface.
* The associated instance will not be deleted unless
* the reference count is returned to zero.
*
* @return The resulting reference count.
*/
NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
/**
* Decreases the reference count for this interface.
* Generally, if the reference count returns to zero,
* the associated instance is deleted.
*
* @return The resulting reference count.
*/
NS_IMETHOD_(nsrefcnt) Release(void) = 0;
//@}
};
#define NS_MAY_ALIAS_PTR(t) t*
#define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
#define NSCAP_RELEASE(this, ptr) (ptr)->Release()
class nsCOMPtr_helper
/*
An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms
that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
Here are the rules for a helper:
- it implements |operator()| to produce an interface pointer
- (except for its name) |operator()| is a valid [XP]COM `getter'
- the interface pointer that it returns is already |AddRef()|ed (as from any good getter)
- it matches the type requested with the supplied |nsIID| argument
- its constructor provides an optional |nsresult*| that |operator()| can fill
in with an error when it is executed
See |class nsGetInterface| for an example.
*/
{
public:
virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const = 0;
};
class
nsCOMPtr_base
/*
...factors implementation for all template versions of |nsCOMPtr|.
This should really be an |nsCOMPtr<nsISupports>|, but this wouldn't work
because unlike the
Here's the way people normally do things like this
template <class T> class Foo { ... };
template <> class Foo<void*> { ... };
template <class T> class Foo<T*> : private Foo<void*> { ... };
*/
{
public:
nsCOMPtr_base( nsISupports* rawPtr = 0 )
: mRawPtr(rawPtr)
{
// nothing else to do here
}
NS_COM_GLUE NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base()
{
if ( mRawPtr )
NSCAP_RELEASE(this, mRawPtr);
}
NS_COM_GLUE void NS_FASTCALL assign_with_AddRef( nsISupports* );
#if 1
NS_COM_GLUE void NS_FASTCALL assign_from_helper( const nsCOMPtr_helper&, const nsIID& );
#endif
NS_COM_GLUE void** NS_FASTCALL begin_assignment();
protected:
NS_MAY_ALIAS_PTR(nsISupports) mRawPtr;
void
assign_assuming_AddRef( nsISupports* newPtr )
{
/*
|AddRef()|ing the new value (before entering this function) before
|Release()|ing the old lets us safely ignore the self-assignment case.
We must, however, be careful only to |Release()| _after_ doing the
assignment, in case the |Release()| leads to our _own_ destruction,
which would, in turn, cause an incorrect second |Release()| of our old
pointer. Thank <waterson at netscape.com> for discovering this.
*/
nsISupports* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(this, oldPtr);
}
};
// template <class T> class nsGetterAddRefs;
#define MOZ_FINAL final
template <class T>
class nsCOMPtr MOZ_FINAL
#ifdef NSCAP_FEATURE_USE_BASE
: private nsCOMPtr_base
#endif
{
#ifdef NSCAP_FEATURE_USE_BASE
#define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x)
#else
#define NSCAP_CTOR_BASE(x) mRawPtr(x)
private:
void assign_with_AddRef( nsISupports* );
void assign_from_helper( const nsCOMPtr_helper&, const nsIID& );
void** begin_assignment();
void
assign_assuming_AddRef( T* newPtr )
{
T* oldPtr = mRawPtr;
mRawPtr = newPtr;
if ( oldPtr )
NSCAP_RELEASE(this, oldPtr);
}
private:
T* mRawPtr;
#endif
public:
typedef T element_type;
#ifndef NSCAP_FEATURE_USE_BASE
~nsCOMPtr()
{
if ( mRawPtr )
NSCAP_RELEASE(this, mRawPtr);
}
#endif
// Constructors
nsCOMPtr()
: NSCAP_CTOR_BASE(0)
// default constructor
{
}
public:
T**
StartAssignment()
{
return reinterpret_cast<T**>(begin_assignment());
}
};
#ifndef NSCAP_FEATURE_USE_BASE
template <class T>
void
nsCOMPtr<T>::assign_with_AddRef( nsISupports* rawPtr )
{
if ( rawPtr )
NSCAP_ADDREF(this, rawPtr);
assign_assuming_AddRef(reinterpret_cast<T*>(rawPtr));
}
template <class T>
void
nsCOMPtr<T>::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID )
{
void* newRawPtr;
if ( NS_FAILED( helper(aIID, &newRawPtr) ) )
newRawPtr = 0;
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void**
nsCOMPtr<T>::begin_assignment()
{
assign_assuming_AddRef(0);
union { T** mT; void** mVoid; } result;
result.mT = &mRawPtr;
return result.mVoid;
}
#endif
template <class T>
class nsGetterAddRefs
/*
...
This class is designed to be used for anonymous temporary objects in the
argument list of calls that return COM interface pointers, e.g.,
nsCOMPtr<IFoo> fooP;
...->QueryInterface(iid, getter_AddRefs(fooP))
DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
When initialized with a |nsCOMPtr|, as in the example above, it returns
a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this
case) can fill in.
This type should be a nested class inside |nsCOMPtr<T>|.
*/
{
public:
explicit
nsGetterAddRefs( nsCOMPtr<T>& aSmartPtr )
: mTargetSmartPtr(aSmartPtr)
{
// nothing else to do
}
operator void**()
{
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
}
operator nsISupports**()
{
return reinterpret_cast<nsISupports**>(mTargetSmartPtr.StartAssignment());
}
#if 1
operator T**()
{
return mTargetSmartPtr.StartAssignment();
}
T*&
operator*()
{
return *(mTargetSmartPtr.StartAssignment());
}
#endif
private:
nsCOMPtr<T>& mTargetSmartPtr;
};
template <>
class nsGetterAddRefs<nsISupports>
{
public:
explicit
nsGetterAddRefs( nsCOMPtr<nsISupports>& aSmartPtr )
: mTargetSmartPtr(aSmartPtr)
{
// nothing else to do
}
#if 1
operator void**()
{
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
}
operator nsISupports**()
{
return mTargetSmartPtr.StartAssignment();
}
nsISupports*&
operator*()
{
return *(mTargetSmartPtr.StartAssignment());
}
#endif
private:
nsCOMPtr<nsISupports>& mTargetSmartPtr;
};
template <class T>
inline
nsGetterAddRefs<T>
getter_AddRefs( nsCOMPtr<T>& aSmartPtr )
/*
Used around a |nsCOMPtr| when
...makes the class |nsGetterAddRefs<T>| invisible.
*/
{
return nsGetterAddRefs<T>(aSmartPtr);
}
//--
#if 1
class nsIFile : public nsISupports {
public:
#if 0
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFILE_IID)
#endif
enum {
NORMAL_FILE_TYPE = 0U,
DIRECTORY_TYPE = 1U
};
/* void normalize (); */
NS_IMETHOD Normalize(void) = 0;
};
#endif
inline nsresult
NS_GetSpecialDirectory(const char* specialDirName, nsIFile* *result)
{
#if 0
nsresult rv;
nsCOMPtr<nsIProperties> serv(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
return serv->Get(specialDirName, NS_GET_IID(nsIFile),
reinterpret_cast<void**>(result));
#else
return NS_OK;
#endif
}
int gensigill (void)
{
nsCOMPtr<nsIFile> file;
nsresult rv = NS_GetSpecialDirectory("ProfDS", getter_AddRefs(file));
return NS_FAILED(rv);
}
More information about the freebsd-bugs
mailing list