[apple.general] Failed allocation in constructors?

escher@Apple.COM (Michael Crawford) (07/11/90)

Can anyone suggest strategies for handling failed memory allocation
in constructors?

Constructors may not have return values, and aren't even void.
I have seen some references to how there is not unified method, and
one just needs to hack it.

Example source code I have seen does not even address the issue, and
just assumes the construction succeeds.

The problem, as I see it, is that what one does upon memory failure
depends greatly on the situation: do you crash and burn, wait, advise
the user to close documents, or free a sentinel block (a large block
allocated at the start of a program to provide a reserve) and retry
the allocation?

Here is a the problem:

class foo {
	char *thePtr;
public:
	CauseACrash();
	foo();
	~foo();
}

void theFun()
{
	foo theFoo;	// foo(), the constructor, gets called

	foo.CauseACrash();

	// ~foo() gets called here, if we're still running!
}

foo::foo()
{
	thePtr = NewPtr( 123456789 );

	if ( thePtr == (char*)NULL ){
		// Whadda I do?
	}
}

foo::CauseACrash()
{
	int i;
	
	for ( i = 0; i < 123456789; i++ ){
		*i = 'Q';
	}
}

On a Mac, CauseACrash will scrawl all over the interrupt vector table; on
Unix, it should core dump (if page 0 is mapped out, as good Unices do).

Seems to me a member function ought to be able to assume that its instance
is valid, and one should not have to validate every instance one creates;
the fact that the object is dynamically allocated should be hidden to the
user.  This would mean that the failure should be handled within the
constructor.

I can conceive of some ways to do it, but I am a beginner here, and having
enough trouble figuring out the language.  Others must have invented this
wheel before, care to roll one by me?

I will summarize and post if you mail me suggestions, though this looks
like a general enough problem to have an open discussion.

Thank you very much,
-- 
Michael D. Crawford
Oddball Enterprises		Consulting for Apple Computer Inc.
606 Modesto Avenue		escher@apple.com
Santa Cruz, CA 95060		Applelink: escher@apple.com@INTERNET#
oddball!mike@ucscc.ucsc.edu	The opinions expressed here are solely my own.

		alias make '/bin/make & rn'

fair@Apple.COM (Erik E. Fair) (07/11/90)

In the referenced article, escher@Apple.COM (Michael Crawford) writes:

on Unix, it should core dump (if page 0 is mapped out, as good Unices do).


Mike,
	Deferencing address zero isn't a crime, unless it isn't in
your address space. There are lots of versions of UNIX where it is, and
that program won't crash and burn until you reach the bottom of your
allocated address space.

The reason that some UNIX systems don't map page zero, as you put it,
varies. Some do it because their hardware (or compiler) has things set
up so that a user program's address space doesn't begin in zero.

Some do it, because attempting to deference address zero is a very
common portability error (and more than occasionally, a logic error)
for the systems that don't have it mapped, particularly for those
programs which assume that location zero *contains* a zero of some
size. So some UNIX systems that might otherwise have address zero
mapped, don't do so, as an encouragement to write portable code.

So, dereferencing zero isn't a bad thing; it's just bad to assume that
you always can across all possible hardware architectures that your
program might be run on.

	Erik E. Fair	apple!fair	fair@apple.com

imp@dancer.Solbourne.COM (Warner Losh) (07/12/90)

In article <42825@apple.Apple.COM> fair@Apple.COM (Erik E. Fair) writes:
>So, dereferencing zero isn't a bad thing; it's just bad to assume that
>you always can across all possible hardware architectures that your
>program might be run on.

Dereferencing "zero" is a bad thing.  "0" is the Nil pointer in C and
C++.  It is defined to point to an address that doesn't exist (or is
at least unique).  So if you dereference it, you are asking for
trouble.

In most implementations of C and C++ a Nil pointer has all its bits
turned off, but not all implementations do this.  Regardless of the
implementation, saying "p=0" will get you a Nil pointer.  So if you
then say *p, that is an error.  However, according to the standard,
compilers are free to not notify the user this error has occurred.

-- 
Warner Losh		imp@Solbourne.COM
All the world is not a VAX. :-)

lsr@Apple.COM (Larry Rosenstein) (07/12/90)

In article <9075@goofy.Apple.COM> escher@Apple.COM (Michael Crawford) writes:
>
>Example source code I have seen does not even address the issue, and
>just assumes the construction succeeds.
>
>The problem, as I see it, is that what one does upon memory failure
>depends greatly on the situation: do you crash and burn, wait, advise
>the user to close documents, or free a sentinel block (a large block

The purpose of the constructor is to put the object in a known, consistent
state.  This doesn't necessarily mean it is in a valid or normal state.
Probably the best approach is to have the contructor flag the invalid
object, and have the other methods check the validity before proceeding.

After the client creates the object, it can check to see if the creation
succeeded.  If it doesn't check, then error can be reported later, but at
least everything is consistent, and the client can handle the error as it
chooses. 

I don't think a constructor should try to decide what to do about the error
(e.g., crash, advise the user, etc.); that's the function of higher levels
of software.  Freeing a sentinel block is a common approach on the
Macintosh, but this is normally done at a lower level (within a Memory
Manager GrowZoneProc).

Another approach would be similar to what is done in Object Pascal.  The
constructor is set up to do initialization that can't fail, and there is a
separate initialization step that the client has to explicitly call, which
can return an error.  (This makes things more complicated for the client, of
course.) 

The issue isn't just that constructors don't return a value.  One can always
use setjmp/longjmp to break out of the constructor.  The problem is
recovering, which requires that destructors be invoked for automatic
objects, for example.  (The proposed C++ exception handling mechanism does
this, for example.)

>On a Mac, CauseACrash will scrawl all over the interrupt vector table; on

True, but not very useful.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

escher@Apple.COM (Michael Crawford) (07/13/90)

In article <1990Jul11.180345.21464@Solbourne.COM> imp@dancer.solbourne.com 
writes:
>In article <42825@apple.Apple.COM> fair@Apple.COM (Erik E. Fair) writes:
>>So, dereferencing zero isn't a bad thing; it's just bad to assume that
>>you always can across all possible hardware architectures that your
>>program might be run on.
>
>In most implementations of C and C++ a Nil pointer has all its bits
>turned off, but not all implementations do this.  Regardless of the
>implementation, saying "p=0" will get you a Nil pointer.  So if you
>then say *p, that is an error.  However, according to the standard,
>compilers are free to not notify the user this error has occurred.

According to me, no system that pretends to have protected memory
has any excuse to not map out page 0.

This, to me, is like buying a fancy car, and having them leave out
the brakes.

I understand it is perfectly legal to have it mapped in, as long
as address 0 is either never used _or_ (void*)NULL does not have
all 0 bits (this is not always the case in practice, as recently
discussed in comp.unix.wizards), but I consider segmentation 
violations and core dumps to be extremely important debugging tools,
and would not buy a protected-mode OS that did not do this.

Of course the Macintosh doesn't, but it does not claim to have
protected memory, and one is not paying for it.  I program the mac
because I find it aesthetically pleasing, but I also program on Unix
(Sun particularly) because I find it easier to get things to work.

-- 
Michael D. Crawford
Oddball Enterprises		Consulting for Apple Computer Inc.
606 Modesto Avenue		escher@apple.com
Santa Cruz, CA 95060		Applelink: escher@apple.com@INTERNET#
oddball!mike@ucscc.ucsc.edu	The opinions expressed here are solely my own.

		alias make '/bin/make & rn'