By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,046 Members | 2,105 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,046 IT Pros & Developers. It's quick & easy.

Class throwing exceptions in aggregate static initializer causes abort() ...

P: n/a
I have a class that throws exceptions in new initializer, and a static
array of objects of this type.

When something is wrong in initialization, CGI program crashes
miserably. Debugging shows uncaught exception.

How to catch an exception that happened before main() try { ... }
catch (...) { ... } block?

Is there a way?

Thank you very much in forward,
Marvin

class formtblitem {
protected:
void clear() {
memset (form_field, 0, sizeof (form_field ));
memset (field_type, 0, sizeof (field_type ));
memset (dflt, 0, sizeof (dflt ));
memset (minval, 0, sizeof (minval ));
memset (maxval, 0, sizeof (maxval ));
memset (POVRAYsubst, 0, sizeof (POVRAYsubst));
varaddr = NULL;
}

#define STRCPY(DEST, SRC) \
if (strlen (SRC) sizeof (DEST) - 1) \
throw PARM_ESTRBUFOVERFLOW; \
else \
strcpy (DEST, SRC);

void initialize (const char *ff, const char *ft, const char
*df,
const char *mn, const char *mx, const char
*ps) {
STRCPY (form_field, ff);
STRCPY (field_type, ft);
if (NotNull()) {
switch (FieldType()) {
case 'b':
if (!isbinary (df) || !isbinary (mn) || !
isbinary (mx))
throw PARM_EBINARY;
break;
case 'i':
if (!isinteger (df) || !isinteger (mn) || !
isinteger (mx))
throw PARM_EINTEGER;
break;
case 'f':
if (!isfloat (df) || !isfloat (mn) || !
isfloat (mx)
..
..
..
};
typedef class formtblitem FTI;

class formtblitem formtbl[] = {
// FORM field, type, dflt, min, max, POV-Ray subst
//
FTI ("debug", "b", "0", "0", "1", "DEBUG",
&debug ),
FTI ("rwidth", "i", "800", "16", "13000", "RWIDTH",
&rwidth ),
FTI ("rheight", "i", "600", "16", "13000", "RHEIGHT",
&rheight ),
FTI ("quality", "i", "9", "0", "13", "Q",
&quality ),
FTI ("antialiasing", "b", "0", "0", "1", "AA",
&antialiasing ),
..
..
..
};

Feb 16 '07 #1
Share this Question
Share on Google+
6 Replies


P: n/a
* Marvin Barley:
I have a class that throws exceptions in new initializer, and a static
array of objects of this type.

When something is wrong in initialization, CGI program crashes
miserably. Debugging shows uncaught exception.

How to catch an exception that happened before main() try { ... }
catch (...) { ... } block?

Is there a way?
Locally yes, just use try-catch; globally, in a portable way, no.

That said, what you have doesn't seem to be exceptions resulting from
exceptional circumstances (such as resource shortage), but resulting
from programming bugs.

Fix your code and you won't have that problem.

Thank you very much in forward,
Marvin

class formtblitem {
protected:
void clear() {
memset (form_field, 0, sizeof (form_field ));
memset (field_type, 0, sizeof (field_type ));
memset (dflt, 0, sizeof (dflt ));
memset (minval, 0, sizeof (minval ));
memset (maxval, 0, sizeof (maxval ));
memset (POVRAYsubst, 0, sizeof (POVRAYsubst));
varaddr = NULL;
}
memset is not guaranteed to yield C++ nullvalues, and is dangerous and
generally inefficient (when wielded by novices) -- not that you should
focus on effiency at all before having reasonably /correct/ code.

Here's a reasonable and correct implementation of clear(), assuming a
default constructor that clears:

void clear() { *this = formtblitem(); }

Don't use raw arrays (even though this code also works with raw arrays).

#define STRCPY(DEST, SRC) \
if (strlen (SRC) sizeof (DEST) - 1) \
throw PARM_ESTRBUFOVERFLOW; \
else \
strcpy (DEST, SRC);
Don't use macros.
>
void initialize (const char *ff, const char *ft, const char
*df,
const char *mn, const char *mx, const char
*ps) {
Don't use raw pointers.

STRCPY (form_field, ff);
STRCPY (field_type, ft);
Don't use macros.

if (NotNull()) {
switch (FieldType()) {
case 'b':
if (!isbinary (df) || !isbinary (mn) || !
isbinary (mx))
throw PARM_EBINARY;
Reserve all uppercase names for macros (which you shouldn't use) --
see this group's FAQ and Bjarne Stroustrup's FAQ.

break;
case 'i':
if (!isinteger (df) || !isinteger (mn) || !
isinteger (mx))
throw PARM_EINTEGER;
break;
case 'f':
if (!isfloat (df) || !isfloat (mn) || !
isfloat (mx)
.
.
.
Additional errors probably in the declarations you left out.
};
typedef class formtblitem FTI;
No need to use keyword 'class' -- C'ism.

class formtblitem formtbl[] = {
No need to use keyword 'class' -- not even a C'ism.

// FORM field, type, dflt, min, max, POV-Ray subst
//
FTI ("debug", "b", "0", "0", "1", "DEBUG",
&debug ),
FTI ("rwidth", "i", "800", "16", "13000", "RWIDTH",
&rwidth ),
FTI ("rheight", "i", "600", "16", "13000", "RHEIGHT",
&rheight ),
FTI ("quality", "i", "9", "0", "13", "Q",
&quality ),
FTI ("antialiasing", "b", "0", "0", "1", "AA",
&antialiasing ),
.
.
.
};
It might be a good idea to reproduce in a small program that compiles,
and post that code.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 16 '07 #2

P: n/a
Thank you very much, Mr. Steinbach,

Alf P. Steinbach je napisao/la:
* Marvin Barley:
I have a class that throws exceptions in new initializer, and a static
array of objects of this type.

When something is wrong in initialization, CGI program crashes
miserably. Debugging shows uncaught exception.

How to catch an exception that happened before main() try { ... }
catch (...) { ... } block?

Is there a way?

Locally yes, just use try-catch; globally, in a portable way, no.
I thought there should be a way through set_terminate() to just exit
gracefully, if not to actually catch exception?
That said, what you have doesn't seem to be exceptions resulting from
exceptional circumstances (such as resource shortage), but resulting
from programming bugs.
No, Sir, stack unwinding proved that the abort() was called in a stack
child of __cxa_throw() called from
__static_initialization_and_destruction_0() internals.

Should've printed it out:

=========================================
#0 0x00003aa431af7545 in raise () from /lib/libc.so.6
#1 0x00003aa431af8cce in abort () from /lib/libc.so.6
#2 0x00003aa4316f85c6 in __cxa_call_unexpected () from /usr/lib/
libstdc++.so.5
#3 0x00003aa4316f85f3 in std::terminate () from /usr/lib/libstdc++.so.
5
#4 0x00003aa4316f8713 in __cxa_throw () from /usr/lib/libstdc++.so.5
#5 0x0000000000406124 in formtblitem::initialize (this=0x50b6e0,
ff=0x62 <Address 0x62 out of bounds>, ft=0x407ffb "b", df=0x408043
"5",
mn=0x408007 "0", mx=0x407e5e "1", ps=0x408052 "AA")
at povdriver-0.1.64-cgi.cc:197
#6 0x0000000000405d29 in __static_initialization_and_destruction_0 (
__initialize_p=3, __priority=16071) at povdriver-0.1.64-cgi.cc:252
#7 0x0000000000407996 in __do_global_ctors_aux ()
#8 0x0000000000402483 in _init ()
#9 0x0000000000407910 in __libc_csu_init ()
#10 0x00000000004078cb in __libc_csu_init ()
#11 0x00003aa431ae53eb in __libc_start_main () from /lib/libc.so.6
#12 0x0000000000402aea in _start () at ../sysdeps/x86_64/elf/start.S:
96
#13 0x000079001d77e7e8 in ?? ()
#14 0x0000000000000000 in ?? ()
#15 0x0000000000000001 in ?? ()
#16 0x000079001d77e9ce in ?? ()
#17 0x0000000000000000 in ?? ()
#18 0x000079001d77e9e7 in ?? ()
#19 0x000079001d77e9f7 in ?? ()
#20 0x000079001d77ea03 in ?? ()
#21 0x000079001d77ea2c in ?? ()
#22 0x000079001d77ea4b in ?? ()
#23 0x000079001d77ea5e in ?? ()
#24 0x000079001d77ea6c in ?? ()
#25 0x000079001d77eca1 in ?? ()
#26 0x000079001d77f16c in ?? ()
#27 0x000079001d77f1be in ?? ()
#28 0x000079001d77f1d6 in ?? ()
#29 0x000079001d77f1ec in ?? ()
#30 0x000079001d77f214 in ?? ()
#31 0x000079001d77f21f in ?? ()
#32 0x000079001d77f238 in ?? ()
#33 0x000079001d77f240 in ?? ()
#34 0x000079001d77f258 in ?? ()
#35 0x000079001d77f269 in ?? ()
#36 0x000079001d77f288 in ?? ()
#37 0x000079001d77f291 in ?? ()
..
..
..
===========================================
Fix your code and you won't have that problem.
I'll try - if only I could know for sure from inside constructor is
the object statically or dynamically initialized, so I should throw
exception in dynamic allocation and only set <error_codein static
case?
Thank you very much in forward,
Marvin

class formtblitem {
protected:
void clear() {
memset (form_field, 0, sizeof (form_field ));
memset (field_type, 0, sizeof (field_type ));
memset (dflt, 0, sizeof (dflt ));
memset (minval, 0, sizeof (minval ));
memset (maxval, 0, sizeof (maxval ));
memset (POVRAYsubst, 0, sizeof (POVRAYsubst));
varaddr = NULL;
}

memset is not guaranteed to yield C++ nullvalues, and is dangerous and
generally inefficient (when wielded by novices) -- not that you should
focus on effiency at all before having reasonably /correct/ code.

Here's a reasonable and correct implementation of clear(), assuming a
default constructor that clears:

void clear() { *this = formtblitem(); }

Don't use raw arrays (even though this code also works with raw arrays).

#define STRCPY(DEST, SRC) \
if (strlen (SRC) sizeof (DEST) - 1) \
throw PARM_ESTRBUFOVERFLOW; \
else \
strcpy (DEST, SRC);

Don't use macros.
Couldn't find a way to check sizeof () elegant in function, sorry I
know some very competent programmers who use macros. I think it is a
matter of opinion.
Don't use raw pointers.
Don't use macros.
Reserve all uppercase names for macros (which you shouldn't use) --
see this group's FAQ and Bjarne Stroustrup's FAQ.
Additional errors probably in the declarations you left out.
No need to use keyword 'class' -- C'ism.
No need to use keyword 'class' -- not even a C'ism.
I think these are just style guides not connected to the main problem
of exception in global initializer, wouldn't you agree? I like to
emphasize it is a class in declaration, since I have a short term
memory problem ;-)
It might be a good idea to reproduce in a small program that compiles,
and post that code.
Should've thought of it myself:

#include <iostream>

using namespace std;

class formtblitem {
void initialize (const char *val) {
throw -1;
form_field = new char [strlen(val)+1];
strcpy (form_field, val);
}
protected:
char *form_field;
public:
formtblitem() { form_field = NULL; }
formtblitem(char *line) { initialize (line); }
~formtblitem() {
if (form_field) delete [] form_field;
}

const char * FormField (void)
{ return form_field; }
};

typedef formtblitem FTI;

FTI formtbl[] = {
FTI ("global initializer throwing exceptions")
};

int main (int argc, char *argv[]) {
FTI *dynamic = NULL;

try {
FTI automatic("automatic_initializer");

dynamic = new FTI("dynamic_initializer");
} catch (int i) {
cout << "caught exception << i << endl;
// cleanup
if (dynamic) delete [] dynamic;
exit(1);
}
}

-------------------------------------
Thanks!

Feb 17 '07 #3

P: n/a
* Marvin Barley:
Thank you very much, Mr. Steinbach,

Alf P. Steinbach je napisao/la:
>* Marvin Barley:
>>I have a class that throws exceptions in new initializer, and a static
array of objects of this type.

When something is wrong in initialization, CGI program crashes
miserably. Debugging shows uncaught exception.

How to catch an exception that happened before main() try { ... }
catch (...) { ... } block?

Is there a way?
Locally yes, just use try-catch; globally, in a portable way, no.

I thought there should be a way through set_terminate() to just exit
gracefully, if not to actually catch exception?
You can exit but not gracefully (in a portable way)... ;-) Calling
'exit' attempts to or may attempt to destroy static objects, which is
not a good idea with the process in an unstable state. And 'abort'
typically prints a message.

>That said, what you have doesn't seem to be exceptions resulting from
exceptional circumstances (such as resource shortage), but resulting
from programming bugs.

No, Sir, stack unwinding proved that the abort() was called in a stack
child of __cxa_throw() called from
__static_initialization_and_destruction_0() internals.
Yep, programming bug.

Should've printed it out:
[stack trace elided]
.
===========================================
>Fix your code and you won't have that problem.

I'll try - if only I could know for sure from inside constructor is
the object statically or dynamically initialized, so I should throw
exception in dynamic allocation and only set <error_codein static
case?
You can't /detect/ that in a portable way, but you can ensure that a
class is only instantiated dynamically (via new) by making the
destructor private or protected, e.g.

class DynamicObject
{
private:
~DynamicObject() {}
public:
void selfDestroy() { delete this; }
};

Instead of a non-static member function 'selfDestroy' you might prefer
to grant friendship to a global template function 'destroy' as well as
e.g. 'std::auto_ptr' and any other smart-pointer class used in the code.

But I hasten to add, this is not a technique that is likely to help with
your problem, which is not to differentiate between different kinds of
allocation, but simply to get the code working.
[snip]
>Don't use raw arrays (even though this code also works with raw arrays).

>>#define STRCPY(DEST, SRC) \
if (strlen (SRC) sizeof (DEST) - 1) \
throw PARM_ESTRBUFOVERFLOW; \
else \
strcpy (DEST, SRC);
Don't use macros.

Couldn't find a way to check sizeof () elegant in function, sorry I
know some very competent programmers who use macros. I think it is a
matter of opinion.
Instead of raw arrays, use std::string for strings, and std::vector for
other kinds of "arrays". Then you don't have to use the macro. And you
avoid all the other bug-causing stuff.

>Don't use raw pointers.
Don't use macros.
Reserve all uppercase names for macros (which you shouldn't use) --
see this group's FAQ and Bjarne Stroustrup's FAQ.
Additional errors probably in the declarations you left out.
No need to use keyword 'class' -- C'ism.
No need to use keyword 'class' -- not even a C'ism.

I think these are just style guides not connected to the main problem
of exception in global initializer, wouldn't you agree? I like to
emphasize it is a class in declaration, since I have a short term
memory problem ;-)
Mostly they're style guides, yes, except the first one: that one is your
ticket out of the crash-crash-crash situation.

>It might be a good idea to reproduce in a small program that compiles,
and post that code.

Should've thought of it myself:

#include <iostream>

using namespace std;

class formtblitem {
void initialize (const char *val) {
throw -1;
form_field = new char [strlen(val)+1];
strcpy (form_field, val);
}
protected:
char *form_field;
public:
formtblitem() { form_field = NULL; }
formtblitem(char *line) { initialize (line); }
~formtblitem() {
if (form_field) delete [] form_field;
}

const char * FormField (void)
{ return form_field; }
};
If you remove the 'throw' there are still a number of problems here.

Academically (but it goes to portability), you need <cstddeffor NULL.

Practically, if an object of class 'formtblitem' is ever copied then you
will have two or more objects trying to 'delete' the same dynamically
allocated array. Just by using 'std::string' instead you remove that
problem. To be fair, it isn't the problem you're experiencing, which
occurs at initialization instead of destruction, but chances are that
just using std::string instead of raw arrays will fix that too.

typedef formtblitem FTI;

FTI formtbl[] = {
FTI ("global initializer throwing exceptions")
};

int main (int argc, char *argv[]) {
FTI *dynamic = NULL;

try {
FTI automatic("automatic_initializer");

dynamic = new FTI("dynamic_initializer");
} catch (int i) {
cout << "caught exception << i << endl;
// cleanup
if (dynamic) delete [] dynamic;
exit(1);
}
}
Off the cuff (code not touched by compiler's hands):

#include <cstddef // EXIT_SUCCESS, EXIT_FAILURE
#include <iostream // std::cout
#include <ostream // operator<<, std::endl
#include <string // std::string
#include <memory // std::auto_ptr
#include <stdexcept // std::exception

class FormTblItem
{
private:
std::string myValue;
public:
FormTblItem() {}
FormTblItem( char const line[] ): myValue( line ) {}

char const* value() { return myValue.c_str(); }
};

typedef FormTblItem Fti;
typedef std::auto_ptr<FtiFtiPtr;

Fti const formTbl[] = { "global_initializer" };

int main()
{
try
{
Fti automatic( "automatic_initializer" );
FtiPtr dynamic( new Fti( "dynamic_initializer" ) );
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}
}

That's all there is to it, in C++. :-)

But of course, if the rest of the code is C++'ified too, then 'value'
should probably return a 'std::string' instead of a 'char const*'.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 17 '07 #4

P: n/a

OK, Mr. Steinbach, hate to oppose your valid argument here, but we
again have a static initialization. This static initialization uses
class _string_, which uses _new_, which _can and will_ throw exception
if system memory is too short, and there's nothing left in core memory
or swap ... (speaking in UN*X terms).

This leads back to point 1. -- core dump because of abort(): "uncaught
exception in global initializer", which is called before main.

The bottom line is: if I don't throw in static initializer, somebody
else might, and my app crashes badly with core, which is a programming
bug.

I if thought of the following (you'd hate it because of macro):
--------------------------------------------------------------------------
[code snippet]
int exception_occured = 0;

#define THROW_INT_EXCEPT(X) { exception_occured = X; throw X; }

void terminator() {
cout << "exception occurred in static initializer " <<
exception_occured << endl;
cout << "Congratulations, you have found a bug! Ending program." <<
endl;
proper_cleanup();
exit(1);
}

void (*old_terminate)()
= set_terminate(terminator);

....

[static initialization with integer exception]

Since there are no dynamically allocated objects yet, cleanup is easy.
It can be called and see all the slots of global variables which were
allocated and call destructors, brave but questionably smart after an
uncaught exception - but since I _know_ what happened in initializer
from _exeception_occured_ variable, I can decide whether it is safe to
cleanup or not.

THROW_INT_EXCEPT(X) macro should be used only in initializers that can
be called from constructor, and only for classes that are possible to
be used in global or static initialization.

Does this make any sense?

This still does not solve the problem of uncaught bad_alloc& in static
initializer, in case system memory is frail, so the program will work
only in good times :-(

I think compiler should have at least warned me that I throw
exceptions in static initializations, don't you?

Regards,
Marvin

Feb 17 '07 #5

P: n/a
* Marvin Barley:
OK, Mr. Steinbach, hate to oppose your valid argument here, but we
again have a static initialization. This static initialization uses
class _string_, which uses _new_, which _can and will_ throw exception
if system memory is too short, and there's nothing left in core memory
or swap ... (speaking in UN*X terms).

This leads back to point 1. -- core dump because of abort(): "uncaught
exception in global initializer", which is called before main.
Yes, that /possible/ (see below) allocation failure is an issue.

The most important thing to realize about memory allocation failures is
that in current desktop systems and larger they (unfortunately) almost
never occur: before any ordinary allocation fails the system typically
slows to slower than a snail's pace (because of virtual memory) and so,
unless the program tries to allocate a very large chunk of memory that
the OS can see outright must fail, the program won't get to that final
"drop" allocation that might fail (it would IMO be much better with a
strict limit on per process memory usage by default, easily configurable
on-the-fly, instead of a rubber band that's streched to infinity, and
with Java/C# the rubber band stretched via a rubber band, but no).

The second most important thing to realize is that /if/ an allocation
fails, there's almost never any cure, any reasonable way to continue
program execution. In particular, C++ standard exceptions use dynamic
allocation, and so aren't safe in this situation (this is a library
active issue, not yet resolved, and yes it's ugly, almost as ugly as
those rubber bands). The only thing you can reasonably do is log the
failure, if necessary (this might be difficult to do in a low-memory
situation), and terminate right away /instead/ of throwing an exception.

And to do that you need to install a new_handler.

Via std::set_new_handler.

In your situation you need to have your new_handler installed before
those pesky globals are initialized.

One way to do that is to have the new_handler installed by a static
object declared before the pesky ones, in the same translation unit.
Another way is to have each static object that depends on dynamic memory
allocation, call a function in the translation unit where the
new_handler is installed via a static object. And there are more ways.

Did I mention that globals are considered Evil(TM)?

With that in mind, another solution is to simply don't have them, to
instead pass around all that's needed (wherever) as arguments or object
members.
[snip]
I think compiler should have at least warned me that I throw
exceptions in static initializations, don't you?
C++ allows you to level the nearest city block just by typing the wrong
character in a line of source code; much more powerful that way than C. ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 17 '07 #6

P: n/a
On Feb 17, 8:31 am, "Alf P. Steinbach" <a...@start.nowrote:
* Marvin Barley:
OK, Mr. Steinbach, hate to oppose your valid argument here, but we
again have a static initialization. This static initialization uses
class _string_, which uses _new_, which _can and will_ throw exception
if system memory is too short, and there's nothing left in core memory
or swap ... (speaking in UN*X terms).
This leads back to point 1. -- core dump because of abort(): "uncaught
exception in global initializer", which is called before main.

Yes, that /possible/ (see below) allocation failure is an issue.

The most important thing to realize about memory allocation failures is
that in current desktop systems and larger they (unfortunately) almost
never occur: before any ordinary allocation fails the system typically
slows to slower than a snail's pace (because of virtual memory) and so,
unless the program tries to allocate a very large chunk of memory that
the OS can see outright must fail, the program won't get to that final
"drop" allocation that might fail (it would IMO be much better with a
strict limit on per process memory usage by default, easily configurable
on-the-fly, instead of a rubber band that's streched to infinity, and
with Java/C# the rubber band stretched via a rubber band, but no).

The second most important thing to realize is that /if/ an allocation
fails, there's almost never any cure, any reasonable way to continue
program execution. In particular, C++ standard exceptions use dynamic
allocation, and so aren't safe in this situation (this is a library
active issue, not yet resolved, and yes it's ugly, almost as ugly as
those rubber bands). The only thing you can reasonably do is log the
failure, if necessary (this might be difficult to do in a low-memory
situation), and terminate right away /instead/ of throwing an exception.

And to do that you need to install a new_handler.

Via std::set_new_handler.

In your situation you need to have your new_handler installed before
those pesky globals are initialized.
One way to do that is to have the new_handler installed by a static
object declared before the pesky ones, in the same translation unit.
Another way is to have each static object that depends on dynamic memory
allocation, call a function in the translation unit where the
new_handler is installed via a static object. And there are more ways.
In a manner of speaking and IMVHO, language ought to provide a means
to catch exceptions it allows to be raised. I have thought of various
ways to do this, but I will propose none of them, as I am a rookie in C
++.
Did I mention that globals are considered Evil(TM)?

With that in mind, another solution is to simply don't have them, to
instead pass around all that's needed (wherever) as arguments or object
members.
Will comply. I always felt bad blood in those globals :-)
[snip]
I think compiler should have at least warned me that I throw
exceptions in static initializations, don't you?

C++ allows you to level the nearest city block just by typing the wrong
character in a line of source code; much more powerful that way than C. ;-)
;-)

Thank for a tone of useful advice.

Marv

Feb 19 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.