From owner-freebsd-bugs@FreeBSD.ORG Fri Feb 28 07:10:01 2014 Return-Path: Delivered-To: freebsd-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 69E53710 for ; Fri, 28 Feb 2014 07:10:01 +0000 (UTC) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 398711821 for ; Fri, 28 Feb 2014 07:10:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.7/8.14.7) with ESMTP id s1S7A1uS020052 for ; Fri, 28 Feb 2014 07:10:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.8/8.14.8/Submit) id s1S7A1VH020051; Fri, 28 Feb 2014 07:10:01 GMT (envelope-from gnats) Date: Fri, 28 Feb 2014 07:10:01 GMT Message-Id: <201402280710.s1S7A1VH020051@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Don Lewis Subject: Re: bin/187103: clang 3.4 miscompiles nsAppRunner.cpp from firefox firefox-27.0.1,1 in i386 X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list Reply-To: Don Lewis List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Feb 2014 07:10:01 -0000 The following reply was made to PR bin/187103; it has been noted by GNATS. From: Don Lewis To: FreeBSD-gnats-submit@FreeBSD.org Cc: freebsd-bugs@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",@progbits .hidden _Z9gensigillv .globl _Z9gensigillv .align 16, 0x90 .type _Z9gensigillv,@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@PLT ud2 .Ltmp1: .size _Z9gensigillv, .Ltmp1-_Z9gensigillv .ident "FreeBSD clang version 3.4 (tags/RELEASE_34/final 197956) 20140216" .section ".note.GNU-stack","",@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 #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(_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 true if they are the same, false 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 \ struct COMTypeInfo \ { \ static const nsIID kIID; \ }; \ static const nsIID& GetIID() {return COMTypeInfo::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 NS_OK if the interface is supported by the associated * instance, NS_NOINTERFACE 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|, but this wouldn't work because unlike the Here's the way people normally do things like this template class Foo { ... }; template <> class Foo { ... }; template class Foo : private Foo { ... }; */ { 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 for discovering this. */ nsISupports* oldPtr = mRawPtr; mRawPtr = newPtr; if ( oldPtr ) NSCAP_RELEASE(this, oldPtr); } }; // template class nsGetterAddRefs; #define MOZ_FINAL final template 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(begin_assignment()); } }; #ifndef NSCAP_FEATURE_USE_BASE template void nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) { if ( rawPtr ) NSCAP_ADDREF(this, rawPtr); assign_assuming_AddRef(reinterpret_cast(rawPtr)); } template void nsCOMPtr::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(newRawPtr)); } template void** nsCOMPtr::begin_assignment() { assign_assuming_AddRef(0); union { T** mT; void** mVoid; } result; result.mT = &mRawPtr; return result.mVoid; } #endif template 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 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|. */ { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } operator nsISupports**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } #if 1 operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } #endif private: nsCOMPtr& mTargetSmartPtr; }; template <> class nsGetterAddRefs { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } #if 1 operator void**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); } nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } #endif private: nsCOMPtr& mTargetSmartPtr; }; template inline nsGetterAddRefs getter_AddRefs( nsCOMPtr& aSmartPtr ) /* Used around a |nsCOMPtr| when ...makes the class |nsGetterAddRefs| invisible. */ { return nsGetterAddRefs(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 serv(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; return serv->Get(specialDirName, NS_GET_IID(nsIFile), reinterpret_cast(result)); #else return NS_OK; #endif } int gensigill (void) { nsCOMPtr file; nsresult rv = NS_GetSpecialDirectory("ProfDS", getter_AddRefs(file)); return NS_FAILED(rv); }