This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: egcs 2.95.1 exceptions don't work in .so (Solaris) and possible solution


With Martin's changes, I can get exceptions to work across shared
libraries on both Solaris 2.5.1 and Solaris 2.6 (using Sun's ld, not
binutils).  Code generated on Solaris 2.6 works on Solaris 7.

However, compling on Solaris 7 doesn't work (yes, I have removed patch
107058-01).

I've added a new test to my code and I now also get the following
error on Solaris 7 if I don't test the throw/catch mechanism (you can
reproduce this by setting testThrowAcrossBoundary to false in test.cpp):

Program received signal SIGSEGV, Segmentation fault.
0xff36617c in __do_global_dtors_aux () from /home/ludemann/src/test-so/libtestlib.so
(gdb) where
#0  0xff36617c in __do_global_dtors_aux () from /home/ludemann/src/test-so/libtestlib.so
#1  0xff366134 in _fini () from /home/ludemann/src/test-so/libtestlib.so
#2  0xff3b9f5c in ?? ()
#3  0xff2200d0 in _exithandle () from /usr/lib/libc.so.1
#4  0xff296814 in exit () from /usr/lib/libc.so.1

- peter

---------------- test sample (shar) --------------

mkdir -p test-so
cat >test-so/README <<'---end---'
The code here is for testing the building of shared objects on
Solaris, using GNU g++ 2.95.1.

The problem appears to be only on Solaris 7 (without patch 107058-01).
Both Solaris 2.6 and Solaris 2.5.1 work OK; and code generated on
Solaris 2.6 works fine on Solaris 7.

To demonstrate the problem, do this:

    make clean default

The problem being demonstrated is this: if an exception is thrown in a
shared object, any surrounding try/catch aren't be honoured; instead
terminate() is called.  A suggested solution was to compile with
-fsjlj-exceptions (not documented, except in the GNU C++ code [use the
source, Luke]); but that didn't work after all.

In addition, this code tests that exceptions work across .so
boundaries with the same technique.

----

$Id: README,v 1.5 1999/10/11 18:24:58 ludemann Exp $
---end---
cat >test-so/Makefile <<'---end---'
# $Id: Makefile,v 1.10 1999/10/11 18:24:58 ludemann Exp $

CXX=g++
CC=gcc
LINK=gcc			# NOT g++ which drags in unneeded stuff!
LINKFLAGS=			# -Xlinker -Dargs,basic,map,entry,support,files,segments	# ,sections,detail,reloc,segments

# CXX=/shared/local/bin/g++
# CXX=/shared/solaris2.6/bin/g++

# It's not clear whether or not we need -mno-app-regs or -ffreestanding,
# but they don't seem to cause harm.
# The following aren't needed:  # -fno-gnu-linker -fexceptions -fnew-exceptions -fguiding-decls # -fcheck-memory-usageb # -v
#    -nostartfiles -nodefaultlibs # -mimpure-text -Xlinker -ztextoff  # -Wl,soname,$@

# CXXFLAGS2=-fsjlj-exceptions -ffreestanding # -mno-app-regs
# CXXFLAGS2=-fnew-exceptions

CXXFLAGS+=-g -O -Wall -fPIC -mno-app-regs $(CXXFLAGS2)

PURIFY=
# PURIFY=purify

# The default rule

default: test-static test-dynamic run

.PHONY: run clean tar cpio shar ci

RUNARGS="a bb" ccc

run::
	./test-static $(RUNARGS)

run::
	./test-dynamic $(RUNARGS)

run::
	@echo
	@echo "Tests succeeded"

clean::
	$(RM) *.o *.a *.so *~ test-dynamic test-static core

test-static: test.o libtestlib.a Makefile
	$(PURIFY) $(CXX) $(LINKFLAGS) $(CPPFLAGS) $(CXXFLAGS) -o $@ test.o libtestlib.a
	-ldd $@

test-dynamic: test.o libtestlib.so Makefile
	@# pwd
	@# echo sh=$(SHELL) R`pwd`
	@# $(PURIFY) $(CXX) $(CXXFLAGS) -dynamic -o $@ test.o -L. -ltestlib -R`pwd`
	$(PURIFY) $(CXX) $(LINKFLAGS) $(CPPFLAGS) $(CXXFLAGS) -o $@ test.o -L. -ltestlib -R`pwd`
	-ldd $@

%.o: %.cpp testlib.hpp Makefile
	@$(CXX) -v
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $*.cpp

libtestlib.a: testlib.o
	$(AR) -rcv $@ $+

libtestlib.so: testlib.o
	@# $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -shared -nostdlib $+
	@# note use of gcc instead of g++ and the addition of -lgcc
	@# (actually, "-lgcc" is implicit)
	$(LINK) $(LINKFLAGS) -o $@ -shared $+ # -lgcc
	-ldd $@

TARSRC=README Makefile test.cpp testlib.cpp testlib.hpp

tar: $(TMPDIR)/test-so.tgz-uuencode

$(TMPDIR)/test-so.tgz: $(TARSRC) Makefile
	cd ..; tar cvvzf $@ $(TARSRC:%=test-so/%)

$(TMPDIR)/test-so.tgz-uuencode: $(TMPDIR)/test-so.tgz Makefile
	cd $(TMPDIR); uuencode test-so.tgz test-so.tgz > $@

cpio: $(TMPDIR)/test-so.cpio

$(TMPDIR)/test-so.cpio: $(TARSRC) Makefile
	cd ..; ls -1 $(TARSRC:%=test-so/%) | cpio -ocv > $@

shar: $(TMPDIR)/test-so.shar

$(TMPDIR)/test-so.shar: $(TARSRC) Makefile
	$(RM) $@
	echo "mkdir -p test-so" >> $@
	for i in $(TARSRC); do					\
	    echo "cat >test-so/$$i <<'---end---'" >> $@;	\
	    cat $$i >> $@;					\
	    echo "---end---" >> $@;				\
	done

ci:
	ci -u $(TARSRC)
---end---
cat >test-so/test.cpp <<'---end---'
// $Id: test.cpp,v 1.5 1999/10/11 18:24:58 ludemann Exp $

#include <iostream>
#include <string>
#include <cstdlib>

#include "testlib.hpp"

using namespace std;

extern const char test_id[] = "@(#) $Id: test.cpp,v 1.5 1999/10/11 18:24:58 ludemann Exp $";

Global* globalPtr = new GlobalPlusOne(3);
Global& global = *globalPtr;
GlobalPlusOne global2 ( 4 );

void testV(const string& name, int v, int shouldBe)
{
  cout << name << " = " << v << endl;
  if (v != shouldBe) {
    cout << "*** Global value not " << shouldBe << ": " << v << endl;
    exit(1);
  }
}

int main(int argc, const char * const argv[])
{
  bool testThrowAcrossBoundary = false;

  Args args(argc, argv);
  args.display(cout);

  testV("global", global.getValue(), 4);
  testV("global2", global2.getValue(), 5);

  if (testThrowAcrossBoundary) { // testing an exception across .so boundary
    try {
      global2.throwUp();
    } catch (const AnError& err) {
      cout << "Caught exception in main: " << err.msg << endl;
    }
  }

  delete globalPtr;
  globalPtr = 0;

  // -- repeat above code, but with the x_global stuff from the .so

#ifdef TEST_GLOBAL_IN_SO

  testV("x_global", x_global.getValue(), 31);
  testV("x_global2", x_global2.getValue(), 41);

  if (testThrowAcrossBoundary) { // testing an exception across .so boundary
    try {
      x_global2.throwUp();
    } catch (const AnError& err) {
      cout << "Caught exception in main: " << err.msg << endl;
    }
  }

  delete x_globalPtr;
  x_globalPtr = 0;

#endif

  return 0;
}
---end---
cat >test-so/testlib.cpp <<'---end---'
// $Id: testlib.cpp,v 1.5 1999/10/11 18:24:58 ludemann Exp $

#include <iostream>

#include "testlib.hpp"

using namespace std;

extern const char testlib_id[] = "@(#) $Id: testlib.cpp,v 1.5 1999/10/11 18:24:58 ludemann Exp $";

#ifdef TEST_GLOBAL_IN_SO

Global* x_globalPtr = new GlobalPlusOne(30);
Global& x_global = *x_globalPtr;
GlobalPlusOne x_global2 ( 40 );

#endif


Args::Args(int argc, const char * const * argv)
  :
  argc_(argc),
  argv_(argv)
{
  // cout << "--- Args::Args(" << argc << ")" << endl;
}

Args::~Args()
{
  // cout << "--- Args::~Args()" << endl;
}

void Args::display(ostream& ostr)
{
  ostr << argv_[0] << ": " << argc_-1 << " arguments ...";
  string sep = " ";
  for (int i = 1; i < argc_; ++i) {
    ostr << sep << "#" << i << ": `" << argv_[i] << "'";
    sep = ", ";
  }
  ostr << endl;
}

Global::Global(int value)
  :
  value_(value)
{
  // cout << "--- Global::Global(" << value << ")" << endl;
}

Global::~Global()
{
  // cout << "--- Global::~Global(value[actual]=" << value_ << ")" << endl;
}

int Global::getValue()
{
  return value_;
}

void Global::throwUp()
{
  throw AnError("Global::throwUp exception");
}

GlobalPlusOne::GlobalPlusOne(int value)
  :
  Global(value)
{
  // cout << "-- GlobalPlusOne::GlobalPlusOne(" << value << ")" << endl;
}

GlobalPlusOne::~GlobalPlusOne()
{
  // cout << "--- GlobalPlusOne::~GlobalPlusOne(value[actual]=" << super::getValue() << ")" << endl;
}

int GlobalPlusOne::getValue()
{
  if (1) {
    try {
      // throwUp(); // xThrowUp();
    } catch (const AnError& err) {
      cout << "Caught exception in GlobalPlusOne::getValue(): `" << err.msg << "'" << endl;
      // throw;
    }
  }

  return super::getValue() + 1;
}


void xThrowUp()
{
   throw AnError("xThrowUp exception");
}


AnError::AnError(const string& the_msg)
  :
  msg(the_msg)
{
  // cout << "--- AnError(" << msg << ")" << endl;
}
---end---
cat >test-so/testlib.hpp <<'---end---'
// $Id: testlib.hpp,v 1.4 1999/10/11 18:24:58 ludemann Exp $

#ifndef testlib_INCLUDED

#define testlib_INCLUDED

#include <iostream>
#include <string>

class Args
{
public:
  Args(int argc, const char * const * argv);
  virtual ~Args();
  virtual void display(ostream& ostr);
private:
  Args();
  Args(const Args&);
  Args& operator = (const Args&);
protected:
  int argc_;
  const char * const * argv_;
};

class AnError
{
public:
  AnError(const string& the_msg);
  string msg;
};

class Global
{
public:
  Global(int value);
  virtual ~Global();
  virtual int getValue();
  virtual void throwUp();
private:
  Global();
  Global(const Global&);
  Global& operator = (const Global&);
protected:
  typedef Global super;
private:
  int value_;
};

class GlobalPlusOne : public Global
{
public:
  GlobalPlusOne(int value);
  virtual ~GlobalPlusOne();
  virtual int getValue();
};

void xThrowUp();

#define TEST_GLOBAL_IN_SO

#ifdef TEST_GLOBAL_IN_SO

extern Global* x_globalPtr;
extern Global& x_global;
extern GlobalPlusOne x_global2;

#endif

#endif
---end---


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]