Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Feb 2014 23:05:02 -0800 (PST)
From:      Don Lewis <truckman@FreeBSD.org>
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
Message-ID:  <201402280705.s1S752qJ095938@gw.catspoiler.org>
In-Reply-To: <201402270020.s1R0K0Fd059781@freefall.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
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 <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@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);
}




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402280705.s1S752qJ095938>