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:10:01 UTC 2014


The following reply was made to PR bin/187103; it has been noted by GNATS.

From: Don Lewis <truckman at FreeBSD.org>
To: FreeBSD-gnats-submit at FreeBSD.org
Cc: freebsd-bugs at FreeBSD.org
Subject: Re: bin/187103: clang 3.4 miscompiles nsAppRunner.cpp from firefox
 firefox-27.0.1,1 in i386
Date: Thu, 27 Feb 2014 23:05:02 -0800 (PST)

 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