473,385 Members | 1,707 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Recovering gracefully from a realloc() failure

Hi,
I'm currently playing around with a little spam filter for my Linksys NSLU2
(I would have used Spamassassin but that's slow even on my 2GHz Athlon64 - on
a 266MHz XScale it's likely to be intolerably slow). As part of that, I'm
keeping track of the DNSBL blocklists that are being queried using a
dynamically-allocated array.

When a new DNSBL zone is added to the zone array, I use realloc() to
increase the amount of memory available for the array. The newly-allocated
block then gets filled in with the zone's details, and a null block (one where
the "zone" pointer is set to NULL) is stored to act as a terminator.

At the moment, I'm using code like this:
if ((zones = realloc(zones, (zonecount + 2) * sizeof(ZONE))) == NULL) {
// something broke, bail out
exit(1);
}

But this has the side effect of clobbering the "zones" pointer if realloc
fails, making anything other than a bail-out impossible (because the zone
table has been mangled). What I was thinking of doing was something like this:
if ((ztemp = realloc(zones, (zonecount + 2) * sizeof(ZONE))) == NULL) {
// something broke, tell the caller and let them deal with it
return ERROR_MEMALLOC;
} else {
// it worked, update the pointer
zones = ztemp;
}

What I was wondering was how realloc() actually behaved. Can the old value
of "zones" be considered to be valid if realloc() fails (i.e. returns NULL)?
In other words, can I continue on using the old value of "zones" (i.e. before
the reassignment) if realloc() fails, and just post an error to syslog along
the lines of "couldn't add zone table entry, out of memory"?

That said, "out of memory" is a pretty rare condition these days, what with
virtual memory and such, but I'd like to handle this situation as gracefully
as possible. If that means bailing out then fine, but if I can make my code
recover from the error, then I'd like to add the code to make that happen.

I've checked the Linux manpages on this, and K&R, but haven't found a
conclusive answer.

Thanks.
--
Phil. | Kitsune: Acorn RiscPC SA202 64M+6G ViewFinder
ph*****@despammed.com (valid!)| Cheetah: Athlon64 3200+ A8VDeluxeV2 512M+100G
http://www.philpem.me.uk/ | Tiger: Toshiba SatPro4600 Celeron700 256M+40G
No software patents! <http://www.eff.org/> / <http://www.ffii.org/>
Apr 20 '06 #1
10 3632
On Thu, 20 Apr 2006 19:13:41 +0100, Philip Pemberton
<ph*****@despammed.com> wrote:
Hi,
I'm currently playing around with a little spam filter for my Linksys NSLU2
(I would have used Spamassassin but that's slow even on my 2GHz Athlon64 - on
a 266MHz XScale it's likely to be intolerably slow). As part of that, I'm
keeping track of the DNSBL blocklists that are being queried using a
dynamically-allocated array.

When a new DNSBL zone is added to the zone array, I use realloc() to
increase the amount of memory available for the array. The newly-allocated
block then gets filled in with the zone's details, and a null block (one where
the "zone" pointer is set to NULL) is stored to act as a terminator.

At the moment, I'm using code like this:
if ((zones = realloc(zones, (zonecount + 2) * sizeof(ZONE))) == NULL) {
// something broke, bail out
exit(1);
}

But this has the side effect of clobbering the "zones" pointer if realloc
fails, making anything other than a bail-out impossible (because the zone
table has been mangled). What I was thinking of doing was something like this:
if ((ztemp = realloc(zones, (zonecount + 2) * sizeof(ZONE))) == NULL) {
// something broke, tell the caller and let them deal with it
return ERROR_MEMALLOC;
} else {
// it worked, update the pointer
zones = ztemp;
}

What I was wondering was how realloc() actually behaved. Can the old value
of "zones" be considered to be valid if realloc() fails (i.e. returns NULL)?
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."
In other words, can I continue on using the old value of "zones" (i.e. before
the reassignment) if realloc() fails, and just post an error to syslog along
the lines of "couldn't add zone table entry, out of memory"?

That said, "out of memory" is a pretty rare condition these days, what with
virtual memory and such, but I'd like to handle this situation as gracefully
as possible. If that means bailing out then fine, but if I can make my code
recover from the error, then I'd like to add the code to make that happen.

I've checked the Linux manpages on this, and K&R, but haven't found a
conclusive answer.
Thanks.


--
Al Balmer
Sun City, AZ
Apr 20 '06 #2
According to the malloc functions manual, one can find (on the
RETURN VALUE section) the final phrase on the last paragraph: If
realloc() fails the original block is left untouched - it is not freed
or moved. So, if (zonecount + 2) > 0 is _always_ TRUE, your memory
block still there.

You can try to use a custom realloc() implementation, that wraps
errors and prints out some debugging info, and even use it as a macro
(i.e. for less function call overhead):

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

/* __FILE__ and __LINE__ are usefull prepocessor macros */
#define XREALLOC(ptr, size) xrealloc(ptr, size, __FILE__, __LINE__)

void *
xrealloc (void *ptr, size_t size, char *fname, int lnum)
{
register void *value = realloc (ptr, size);

if (value == NULL)
{
fprintf (stderr, "%s:%d - realloc error\n", fname, lnum);
return NULL; //here the caller can deal with the error, but it's
recommended to exit ()
/* exit (EXIT_FAILURE); */
}
return value;
}

You can use the macro this way:

ztemp = (ZONE *) XREALLOC (zones, (zonecount + 2) * sizeof (ZONE));

and wrap (ztemp == NULL) to free memory and try again, et cetera.
If your application is linear (i.e. make the job in a serial way),
thre's no sense to wait some memory to apear, and exit() is the better
choice, but if we are expecting some memory to be realeased on the next
instants (wonder a multi-threaded application allocating/freeing memory
asychronously), make a try counter, sleep for a while, and try until
the counter reaches a limit (i.e. wait 100 us, and try 5 counts before
exit ()).

----mauricio

Apr 20 '06 #3
Al Balmer wrote:
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."


Thanks for that - guess I'll have to try and get a copy of the C standard at
some point. K&R is great for most things, but I'm surprised it doesn't cover
realloc (or if it does it's certainly not listed in the index).

I gather that by "the standard" you mean "ISO/IEC 9899:1999: Programming
Language C"?

Thanks.
--
Phil. | Kitsune: Acorn RiscPC SA202 64M+6G ViewFinder
ph*****@despammed.com (valid!)| Cheetah: Athlon64 3200+ A8VDeluxeV2 512M+100G
http://www.philpem.me.uk/ | Tiger: Toshiba SatPro4600 Celeron700 256M+40G
No software patents! <http://www.eff.org/> / <http://www.ffii.org/>
Apr 20 '06 #4
Philip Pemberton wrote:
.... snip ...
But this has the side effect of clobbering the "zones" pointer if
realloc fails, making anything other than a bail-out impossible
(because the zone table has been mangled). What I was thinking of
doing was something like this:

if ((ztemp = realloc(zones, (zonecount + 2) * sizeof(ZONE))) == NULL) {
// something broke, tell the caller and let them deal with it
return ERROR_MEMALLOC;
} else {
// it worked, update the pointer
zones = ztemp;
}

What I was wondering was how realloc() actually behaved. Can the
old value of "zones" be considered to be valid if realloc() fails
(i.e. returns NULL)? In other words, can I continue on using the
old value of "zones" (i.e. before the reassignment) if realloc()
fails, and just post an error to syslog along the lines of
"couldn't add zone table entry, out of memory"?


That is the correct way to handle it. On failure realloc will not
disturb the old pointer or the material to which it points.

--
I hear the voices. G W Bush, 2006-04-18
Apr 20 '06 #5
Philip Pemberton <ph*****@despammed.com> writes:
Al Balmer wrote:
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."


Thanks for that - guess I'll have to try and get a copy of the C
standard at some point. K&R is great for most things, but I'm
surprised it doesn't cover realloc (or if it does it's certainly not
listed in the index).

I gather that by "the standard" you mean "ISO/IEC 9899:1999:
Programming Language C"?


That's the current official standard, yes. Most implementations don't
yet fully support it; the older 1990 standard is almost universally
supported (often with extensions).

A draft of the standard, including the C99 standard with later
modifications ("Technical Corrigenda") merged in and marked with
change bars, is freely available as n1124.pdf. I have a copy of the
actual standard (for which I paid $18 to ANSI), but these days I
almost always use n1124 instead.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Apr 20 '06 #6
Philip Pemberton wrote:
Al Balmer wrote:
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."
Thanks for that - guess I'll have to try and get a copy of the C
standard at some point. K&R is great for most things, but I'm surprised
it doesn't cover realloc (or if it does it's certainly not listed in the
index).


<fx: wanders off to grab copy of K&R2>

It's in the index of the second edition. If you have the first edition
then I suggest you go out and buy the "modern" version that was
published in 1989 since it tells you about all sorts of cool "new"
things, such as function prototypes and void.
I gather that by "the standard" you mean "ISO/IEC 9899:1999: Programming
Language C"?


I'm sure he does. I suggest you look here
http://clc-wiki.net/wiki/c_standard
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
Apr 20 '06 #7
On Thu, 20 Apr 2006 20:30:46 +0100, Philip Pemberton
<ph*****@despammed.com> wrote:
Al Balmer wrote:
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."
Thanks for that - guess I'll have to try and get a copy of the C standard at
some point. K&R is great for most things, but I'm surprised it doesn't cover
realloc (or if it does it's certainly not listed in the index).


It's listed in the second edition - page 252. A short paragraph, in
the usual K&R style of no unnecessary words :-)
I gather that by "the standard" you mean "ISO/IEC 9899:1999: Programming
Language C"?

Yes. It's available as a PDF from ANSI for $18.00. That's what I use.

--
Al Balmer
Sun City, AZ
Apr 20 '06 #8
"pragma" <mp****@if.ufrgs.br> wrote in message
news:11*********************@v46g2000cwv.googlegro ups.com...
According to the malloc functions manual, one can find (on the
RETURN VALUE section) the final phrase on the last paragraph: If
realloc() fails the original block is left untouched - it is not freed
or moved. So, if (zonecount + 2) > 0 is _always_ TRUE, your memory
block still there.

You can try to use a custom realloc() implementation, that wraps
errors and prints out some debugging info, and even use it as a macro
(i.e. for less function call overhead):

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

/* __FILE__ and __LINE__ are usefull prepocessor macros */
#define XREALLOC(ptr, size) xrealloc(ptr, size, __FILE__, __LINE__)

void *
xrealloc (void *ptr, size_t size, char *fname, int lnum)
{
register void *value = realloc (ptr, size);

if (value == NULL)
{
fprintf (stderr, "%s:%d - realloc error\n", fname, lnum);
return NULL; //here the caller can deal with the error, but it's
recommended to exit ()
/* exit (EXIT_FAILURE); */
}
return value;
}

You can use the macro this way:

ztemp = (ZONE *) XREALLOC (zones, (zonecount + 2) * sizeof (ZONE));
And why would you need to cast XREALLOC() here?
and wrap (ztemp == NULL) to free memory and try again, et cetera.

Apr 20 '06 #9
On Thu, 20 Apr 2006 20:30:46 +0100, Philip Pemberton
<ph*****@despammed.com> wrote:
Al Balmer wrote:
From the standard:
"If memory for the new
object cannot be allocated, the old object is not deallocated and its
value is unchanged."


Thanks for that - guess I'll have to try and get a copy of the C standard at
some point. K&R is great for most things, but I'm surprised it doesn't cover
realloc (or if it does it's certainly not listed in the index).


It's in the index on page 269 in my copy. The index refers to page
252. The wording is a tad different but it matches the intent that Al
quoted.
Remove del for email
Apr 21 '06 #10
Philip Pemberton wrote:
<snip>
That said, "out of memory" is a pretty rare condition these days, what
with virtual memory and such,
This is OT, but virtual memory is neither inexhaustible nor necessarily
unbounded. My machine in particular has a fixed amount of virtual memory,
and it does get exhausted (mostly by rude applications who *could* do with
less memory if they hadn't been written with the assumption that large
amounts of memory will magically appear and disappear). I still prefer
applications crashing left and right to losing my system through thrashing.
but I'd like to handle this situation as gracefully as possible.


Good for you. Usually a best effort suffices. Whatever you do is better than
assuming it never fails, even if it's just displaying "out of memory" rather
than "segmentation fault".

S.
Apr 21 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

36
by: Roy | last post by:
Hi all : My code below : #include <stdio.h> #include <string.h> #include <stdlib.h> char *cat(char *s, const char *t) { char *tmp;
86
by: Walter Roberson | last post by:
If realloc() finds it necessary to move the memory block, then does it free() the previously allocated block? The C89 standard has some reference to undefined behaviour if one realloc()'s memory...
16
by: Martin Joergensen | last post by:
Hi, I wanted to try something which I think is a very good exercise... I read in data from the keyboard and store them in a structure. There's a pointer called "data_pointer" which I use to...
19
by: ivan.leben | last post by:
Let's say I have a piece of allocated memory which I want to expand and reuse if possible or allocate in a different part of RAM if resizing is not possible, however, in the latter case I don't...
64
by: Robert Seacord | last post by:
The C standard doesn't say anything about what happens when you call realloc with a size argument of 0. Both glibc and openbsd appear to return a valid pointer to a zero-sized object.. e.g. the...
31
by: banansol | last post by:
Hi, I just want to get this right. A call to realloc() will return NULL on error and the original memory is left untouched, both when requesting a larger or a smaller size that the original,...
4
by: Kenneth Brody | last post by:
I looked at my copy of n1124, and I didn't see anything about this particular situation... What happens if you realloc() to a size of zero? Implementations are allowed to return NULL on...
10
by: Igal | last post by:
hay, i'm doing this program. having problem wiht realloc in the function that reads data structures into array (pointer - bp2), this happens after reading the second record. when call to realloc....
35
by: Bill Cunningham | last post by:
My string.h headers declares two functions I have been using called memfrob and strfry. They are encryption types functions. My man pages say they are standard to linux c and gnu c. They sure...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.