arm-pe: Multiple inheritance problem w/C++

Craig A. Vanderborgh craigv@voxware.com
Sat May 24 16:28:00 GMT 2003


Hello all:

We have discovered a bad problem with binutils configured for
arm-wince-pe on an x86linux host.  We have been able to partially
diagnose this problem, but we really need the help of the experts this
time.

The problem is this: in the case where a class has multiple inheritance,
the vtables seem to be messed up.  The test case below shows that the
vtable offset of the pure virtual method in DOMImplementationSource is
used instead of the offset in DOMImplementationImpl, and then applied to
the Impl vtable.  This breaks C++ programs of any complexity, and seems
to permeate GNU ld versions 2.11.2, 2.13.9, and even the latest
snapshot, at least for the arm-pe configuration.

I have attached a test case that demonstrates the problem.  It stands
alone, but it is kind of long - I hope that everyone understands that it
is not easy to achieve much more brevity in a test case such as this.

We have determined that this is not a compiler issue; objects compiled
with our arm-wince-pe-gcc and linked elsewhere seem to work without
exhibiting this problem.  We have set our testing up so that both links
(on the 2 different platforms) receive identical input for all objects
and libraries. Thus, this is apparently a linker issue.

The test case follows.  Please try to help us if possible - this is a
bad problem for us and we are currently quite stuck.  Naturally we would
be delighted to provide *any* additional info or materiel.

Thanks in advance,
craig vanderborgh
voxware incorporated

#include <stdio.h>
#include <stdlib.h>

FILE * stdOut;

class DOMBuilder
{
  public :
    DOMBuilder() {};
    ~DOMBuilder() {};
};

class DOMImplementationLS
{
  protected :
    // -----------------------------------------------------------------------
    //  Hidden constructors
    // -----------------------------------------------------------------------
    DOMImplementationLS() {};
    DOMImplementationLS(const DOMImplementationLS &) {};
    DOMImplementationLS & operator = (const DOMImplementationLS &) { return * this; };

  public:
    // -----------------------------------------------------------------------
    //  All constructors are hidden, just the destructor is available
    // -----------------------------------------------------------------------
    virtual ~DOMImplementationLS() {};

    // -----------------------------------------------------------------------
    // Virtual DOMImplementation LS interface
    // -----------------------------------------------------------------------
    virtual DOMBuilder * createDOMBuilder() = 0;
};

class DOMImplementation : public DOMImplementationLS
{
  protected :
    // -----------------------------------------------------------------------
    //  Hidden constructors
    // -----------------------------------------------------------------------
    DOMImplementation() {};                                                        // no plain constructor
    DOMImplementation(const DOMImplementation &) {};                               // no copy construtor.
    DOMImplementation & operator = (const DOMImplementation &) { return * this; }; // No Assignment
  public:
    // -----------------------------------------------------------------------
    //  All constructors are hidden, just the destructor is available
    // -----------------------------------------------------------------------
    virtual ~DOMImplementation() {};

    // -----------------------------------------------------------------------
    // Non-standard extension
    // -----------------------------------------------------------------------
    static DOMImplementation * getImplementation();
};


class DOMImplementationSource
{
  protected :
    // -----------------------------------------------------------------------
    //  Hidden constructors
    // -----------------------------------------------------------------------
    DOMImplementationSource() {};
    DOMImplementationSource(const DOMImplementationSource &) {};
    DOMImplementationSource & operator = (const DOMImplementationSource &) { return * this; };

  public:
    // -----------------------------------------------------------------------
    //  All constructors are hidden, just the destructor is available
    // -----------------------------------------------------------------------
    virtual ~DOMImplementationSource() {};

    // -----------------------------------------------------------------------
    //  Virtual DOMImplementationSource interface
    // -----------------------------------------------------------------------
    virtual DOMImplementation * getDOMImplementation() const = 0;
};


class DOMImplementationImpl: public DOMImplementation, public DOMImplementationSource
{
  private:
    DOMImplementationImpl() {};
    DOMImplementationImpl(const DOMImplementationImpl & other) {};
    DOMImplementationImpl & operator = (const DOMImplementationImpl & other) { return * this; };

  public:
    virtual ~DOMImplementationImpl() {};
    static DOMImplementationImpl * getDOMImplementationImpl();

    // ------------------------------------------------------------
    // DOMImplementationLS Virtual interface
    // ------------------------------------------------------------
    virtual DOMBuilder * createDOMBuilder();

    // ------------------------------------------------------------
    // DOMImplementationSource Virtual interface
    // ------------------------------------------------------------
    virtual DOMImplementation * getDOMImplementation() const;

};

static DOMImplementationImpl * gDomimp; // Points to the singleton instance of DOMImplementation that is returned by any call to getImplementation().

DOMImplementationImpl * DOMImplementationImpl::getDOMImplementationImpl() {
  fprintf(stdOut, "DOMImplementationImpl::getDOMImplementationImpl: invoked\r\n");
  if (gDomimp == NULL) gDomimp = new DOMImplementationImpl;
  return gDomimp;
};

//  DOMImplementation::getImplementation
//  DOMImplementation is supposed to be a pure interface class. 
//  This lone static function is the hook that gets things started.
DOMImplementation * DOMImplementation::getImplementation()
{
  fprintf(stdOut, "DOMImplementation::getImplementation: invoked\r\n");
  return (DOMImplementation *) DOMImplementationImpl::getDOMImplementationImpl();
}

// ------------------------------------------------------------
// DOMImplementationLS Virtual interface
// ------------------------------------------------------------
DOMBuilder * DOMImplementationImpl::createDOMBuilder()
{
  return new DOMBuilder();
}

// ------------------------------------------------------------
// DOMImplementationSource Virtual interface
// ------------------------------------------------------------
DOMImplementation * DOMImplementationImpl::getDOMImplementation() const
{
  fprintf(stdOut, "DOMImplementationImpl::getDOMImplementation: invoked\r\n");
  DOMImplementation * impl = DOMImplementation::getImplementation();
  fprintf(stdOut, "DOMImplementationImpl::getDOMImplementation: got DOMImplementation@%p\r\n", impl);
  fflush(stdOut);
  return impl;
}

class DOMImplementationRegistry
{
  public:
    static DOMImplementation * getDOMImplementation();
};

// -----------------------------------------------------------------------
//  DOMImplementationRegistry Functions
// -----------------------------------------------------------------------
DOMImplementation * DOMImplementationRegistry::getDOMImplementation() {

  DOMImplementation * impl = NULL;

  DOMImplementationImpl * implImpl = DOMImplementationImpl::getDOMImplementationImpl();
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: got DOMImplementationImpl@%p\r\n", implImpl);
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: got DOMImplementation@%p\r\n", implImpl->getDOMImplementation());
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: cast to DOMImplementation@%p\r\n", (DOMImplementation *)implImpl);
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: cast to DOMImplementationLS@%p\r\n", (DOMImplementationLS *)implImpl);
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: cast to DOMImplementationSource@%p\r\n", (DOMImplementationSource *)implImpl);
  fflush(stdOut);

  DOMImplementationSource * source = (DOMImplementationSource *)DOMImplementationImpl::getDOMImplementationImpl();
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: got DOMImplementationSource@%p\r\n", source);
  fflush(stdOut);

  /*!! BINUTILS: this is the method invocation that fails when compiled w/arm-wince-pe !!*/
  impl = source->getDOMImplementation();
  fprintf(stdOut, "DOMImplementationRegistry::getDOMImplementation: got DOMImplementation@%p\r\n", impl);
  fflush(stdOut);

  return impl;
}

int
main(int argC, char* argV[])
{
   // Open the log file
  stdOut = fopen("/temp/CastTest.log", "wb");
  if (stdOut == NULL) return -1;
  fprintf(stdOut, "CastTest: invoked\r\n");
  fflush(stdOut);

   // Instantiate the DOM parser
  DOMImplementation * impl = DOMImplementationRegistry::getDOMImplementation();
  fprintf(stdOut, "CastTest: got DOMImplementation@%p\r\n", impl);
  fflush(stdOut);
  DOMImplementationLS * implls = (DOMImplementationLS *)impl;
  fprintf(stdOut, "CastTest: cast to DOMImplementationLS@%p\r\n", implls);
  fflush(stdOut);
  DOMBuilder * parser = NULL;
  if (impl) parser = implls->createDOMBuilder();

  fprintf(stdOut, "CastTest: created DOMBuilder@%p\r\n", parser);
  fflush(stdOut);

  delete parser;
  fprintf(stdOut, "CastTest: deleted DOMBuilder@%p\r\n", parser);
  fflush(stdOut);

  fclose(stdOut);
  return 0;
}






More information about the Binutils mailing list