Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Checking validity of a file pointer

4 views
Skip to first unread message

Richard Harter

unread,
Jan 13, 2010, 12:04:24 PM1/13/10
to

Is there any way to reliably check the legitimacy of something
that purports to be a file pointer? The best answer would be a
technique that is guaranteed to work. If there be not such, a
technique that would almost certainly work in practice.

In addition, is there a "sanitary" version of the printf
formatting that is publicly available. The issue here is that
printf and friends can do all sorts of ugly things.

The context is an error exit routine. The prototype looks
something like this:

void errexit(FILE * fptr,char * fmt,...);

The idea is that errexit will write an error message to the
specified file and then call exit. It would be couth if the
errexit routine would not crash the program. Some potential
failure points:

(a) The code explicitly or implicitly calls malloc or free.
(b) The fptr argument is not a valid file point and is not 0.
(c) The error message becomes unboundedly large. In particular
the code doesn't gracefully hand unterminated strings.
(d) The code doesn't gracefully handle argument/format
mismatches.

Obviously one can write a mini printf, but this may be a wheel
best not reinvented.

Any thoughts will be appreciated.


Richard Harter, c...@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Infinity is one of those things that keep philosophers busy when they
could be more profitably spending their time weeding their garden.

jacob navia

unread,
Jan 13, 2010, 1:06:42 PM1/13/10
to
Richard Harter a �crit :

> Is there any way to reliably check the legitimacy of something
> that purports to be a file pointer?

No.

This is equivalent to checking a pointer. Under windows is an API that
does that, maybe in an other systems there is something similar,
but there isn't anything 100% reliable.

Solution:

When you start the program open the log file and ensure that
it is OK to write to it. Then store it in some place.
Eliminate the FILE * argument from the log function specs.

Why should be there anyway? Do you have several log files open
at the same time?

Simplify!

> The best answer would be a
> technique that is guaranteed to work. If there be not such, a
> technique that would almost certainly work in practice.
>

IsVAlidReadPointer/IsValidWritePointer under windows...

> In addition, is there a "sanitary" version of the printf
> formatting that is publicly available. The issue here is that
> printf and friends can do all sorts of ugly things.
>

True. Do not use %s

> The context is an error exit routine. The prototype looks
> something like this:
>
> void errexit(FILE * fptr,char * fmt,...);
>
> The idea is that errexit will write an error message to the
> specified file and then call exit. It would be couth if the
> errexit routine would not crash the program. Some potential
> failure points:
>

Much better would be:

void errexit(char *function_name, char *message, int flags);

Error messages do not need to be SO nicely formatted. Just print the
location of the code, the errormessage. Flags could be something that
tells you if you should exit or not (warning/error) but it can be
eliminated.

At this point, the software is going to stop running. Do NOT
complicate things, do NOT try to have fancy formatting. Just
print the message and exit.

REMEMBER: Only software people afre going to read this. They are not end
users. And if the log file is hard to read they can write a piece of
software for better formatting of the log file :-)

jacob


Seebs

unread,
Jan 13, 2010, 2:05:06 PM1/13/10
to
On 2010-01-13, jacob navia <ja...@spamsink.net> wrote:
> When you start the program open the log file and ensure that
> it is OK to write to it. Then store it in some place.
> Eliminate the FILE * argument from the log function specs.
>
> Why should be there anyway? Do you have several log files open
> at the same time?
>
> Simplify!

I agree with this part! It's a good insight.

> Much better would be:
>
> void errexit(char *function_name, char *message, int flags);
>
> Error messages do not need to be SO nicely formatted. Just print the
> location of the code, the errormessage. Flags could be something that
> tells you if you should exit or not (warning/error) but it can be
> eliminated.

I disagree with this part, though. There is a ton of stuff that is likely
to happen in log messages, all over the place. We have three options:

1. Allow format strings.
2. Make every caller do their own formatting, using snprintf and a buffer,
before handing us the message. This is error-prone at best, and will involve
MANY points at which the message could be screwed up.
3. Discourage users from including relevant data along with the error
message.

Consider the difference between:
Error: Value out of range
and
Error: Value (23) out of range (expecting 1-20).

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

Nick

unread,
Jan 13, 2010, 2:37:25 PM1/13/10
to
jacob navia <ja...@spamsink.net> writes:

> Richard Harter a écrit :


>> Is there any way to reliably check the legitimacy of something
>> that purports to be a file pointer?
>
> No.
>
> This is equivalent to checking a pointer. Under windows is an API that
> does that, maybe in an other systems there is something similar,
> but there isn't anything 100% reliable.

I'm intrigued. What does it check?

Suppose you've opened a file with fp as the pointer and then closed it.
What does it check about fp?

If there was a safe and easy way to do this, fclose could do it to check
you don't close the file twice (source of probably my all-time hardest
to spot bug: if you took a particular (and rare) path through the
program a file was closed twice. A year or more later I added code that
caused, in even rarer circumstances, another file to be opened further
through the flow. /That/ fopen was where it crashed).
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk

robert...@yahoo.com

unread,
Jan 13, 2010, 4:11:16 PM1/13/10
to
On Jan 13, 12:06 pm, jacob navia <ja...@spamsink.net> wrote:
> Richard Harter a crit :
>
> > Is there any way to reliably check the legitimacy of something
> > that purports to be a file pointer?
>
> No.
>
> This is equivalent to checking a pointer. Under windows is an API that
> does that, maybe in an other systems there is something similar,
> but there isn't anything 100% reliable.
>
>(...)
>
> IsVAlidReadPointer/IsValidWritePointer under windows...


The IsBad*Pointer() functions under Windows do not do what the OP, or
almost anyone else, really want. Worse, just using them can cause
some rather bad side effects that can lead to your program crashing.

First, they don't do what you want. They will check if the address
being pointed to is mapped into your address space. This has, a best,
a marginal relationship with storage that's been malloc'd, since the
allocator commonly requests large chunks from the OS (thus having big
unallocated parts that are mapped in virtual memory but are not valid
areas for C pointers to point to), and freed areas are often not
returned to the OS either, leaving all of those to pass
IsBad*Pointer. So those functions simply don't accomplish what you
most people hope they do.

And even if you validated a pointer to ensure it was actually pointing
to a validly allocated area of the heap (which you could do, slowly,
with the _heapwalk() function in Windows), that doesn't help you to
identify storage not allocated on the normal heap (and while whatever
a file pointer is pointing at is likely allocated from there, it's
certainly not guaranteed), and it doesn't help you verify that you're
actually pointing at an object of the correct type.

Second, if you happen to accidentally IsBad*Pointer() a stack guard
page (Windows, as most OSs, don't actually allocate real memory pages
to the whole stack until the program grows into those areas), you'll
end up eating the CPU exception that the OS uses to add a real page to
the stack - and then when you *do* grow the stack into that area,
you'll get a crash, since there will not be any memory allocated
there.

In short, unless you really know what you're doing, the IsBad*Pointer
() functions are to be avoided at all costs.

jacob navia

unread,
Jan 13, 2010, 6:42:27 PM1/13/10
to
Nick a écrit :

> jacob navia <ja...@spamsink.net> writes:
>
>> Richard Harter a écrit :
>>> Is there any way to reliably check the legitimacy of something
>>> that purports to be a file pointer?
>> No.
>>
>> This is equivalent to checking a pointer. Under windows is an API that
>> does that, maybe in an other systems there is something similar,
>> but there isn't anything 100% reliable.
>
> I'm intrigued. What does it check?
>

It checks that the RAM starting at the given address and with the
given length is readable/writable.

> Suppose you've opened a file with fp as the pointer and then closed it.
> What does it check about fp?
>
> If there was a safe and easy way to do this, fclose could do it to check
> you don't close the file twice (source of probably my all-time hardest
> to spot bug: if you took a particular (and rare) path through the
> program a file was closed twice. A year or more later I added code that
> caused, in even rarer circumstances, another file to be opened further
> through the flow. /That/ fopen was where it crashed).


Fine, but an fclose that doesn't check its parameters is really a pile of shit...
It is not that difficult to maintain a list of open files and verify that
the file is really open before closing it.

Keith Thompson

unread,
Jan 13, 2010, 8:39:55 PM1/13/10
to
jacob navia <ja...@nospam.org> writes:
> Nick a écrit :
[...]

>> Suppose you've opened a file with fp as the pointer and then closed it.
>> What does it check about fp?
>>
>> If there was a safe and easy way to do this, fclose could do it to check
>> you don't close the file twice (source of probably my all-time hardest
>> to spot bug: if you took a particular (and rare) path through the
>> program a file was closed twice. A year or more later I added code that
>> caused, in even rarer circumstances, another file to be opened further
>> through the flow. /That/ fopen was where it crashed).
>
>
> Fine, but an fclose that doesn't check its parameters is really a
> pile of shit... It is not that difficult to maintain a list of open
> files and verify that the file is really open before closing it.

I agree that fclose() can do some checking, and that it shouldn't be
too difficult in most implementations. (I won't comment on your
characterization of an implementation that doesn't do this.)

On the other hand, it's not hard to imagine an implementation that's
built on top of some lower level, where that lower level doesn't
provide this kind of checking.

Also (somebody else mentioned this scenario), consider:

fp1 = fopen(...);
fclose(fp1);
...
fp2 = fopen(...);
/* Suppose fp2 happens to point to the same FILE object that
fp1 had pointed to.
*/
...
fclose(fp1);
/* Oops, we closed fp1 twice, but the error isn't detected
because the pointer looks valid.
*/
...
fclose(fp2);
/* This should have beeen ok, but the previous fclose clobbered
the FILE object; if fclose() performs checking, it will
report the error here rather than where it really occurred
*/

That's not to say that performing checking in fclose() isn't a good
idea (and closing a file isn't likely to be performance-critical), but
it can't catch everything.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Richard Harter

unread,
Jan 14, 2010, 3:16:46 AM1/14/10
to
On Wed, 13 Jan 2010 19:06:42 +0100, jacob navia
<ja...@spamsink.net> wrote:

>Richard Harter a �crit :
>> Is there any way to reliably check the legitimacy of something
>> that purports to be a file pointer?
>
>No.
>
>This is equivalent to checking a pointer. Under windows is an API that
>does that, maybe in an other systems there is something similar,
>but there isn't anything 100% reliable.

There is a difference between checking whether a file pointer is
valid and checking whether an arbitrary pointer is valid. The
implementation/OS knows (or at least it can know) what files are
open and can potentially produce a list of all legitimate file
pointers.

All of which is moot - standard C doesn't provide any such thing.



>
>Solution:
>
>When you start the program open the log file and ensure that
>it is OK to write to it. Then store it in some place.
>Eliminate the FILE * argument from the log function specs.

Minor quibble: The context is an error exit function, not a log
function.

Actually, the code I use does that. The issue is that there is
no guarantee that the file pointer is still valid when the error
exit function is called. Any number of bad things may have
happened in the interim; indeed something bad must have happened
or the code wouldn't be calling the error exit function.

One can check by trying to put a character and then checking for
a write error. This may crash the program which is undesirable.

Is there anything better?


>
>Why should be there anyway? Do you have several log files open
>at the same time?
>
>Simplify!

I almost believe you have log files on the brain. Please stick
to the original topic; log files are irrelevant.

I disagree with your "much better". I've used it and I don't
like it. I want to be able to include data in the message.

Anyway, thank you for your comments.

Nick Keighley

unread,
Jan 14, 2010, 4:32:35 AM1/14/10
to
On 14 Jan, 08:16, c...@tiac.net (Richard Harter) wrote:
> On Wed, 13 Jan 2010 19:06:42 +0100, jacob navia
>
> <ja...@spamsink.net> wrote:
> >Richard Harter a écrit :

<snip>

> >> The context is an error exit routine.  The prototype looks
> >> something like this:
>
> >>     void errexit(FILE * fptr,char * fmt,...);
>
> >> The idea is that errexit will write an error message to the
> >> specified file and then call exit.  It would be couth if the
> >> errexit routine would not crash the program.  Some potential
> >> failure points:
>
> >Much better would be:
>
> >      void errexit(char *function_name, char *message, int flags);
>
> >Error messages do not need to be SO nicely formatted. Just print the
> >location of the code, the errormessage. Flags could be something that
> >tells you if you should exit or not (warning/error) but it can be
> >eliminated.

no. I hate error messages like this with a passion. I'd like to know
what went wrong!


> >At this point, the software is going to stop running. Do NOT
> >complicate things, do NOT try to have fancy formatting. Just
> >print the message and exit.
>
> >REMEMBER: Only software people afre going to read this. They are not end
> >users. And if the log file is hard to read they can write a piece of
> >software for better formatting of the log file :-)

but the magic formatter can't add information that isn't there. We log
messages received and sent in hex. The logfile post processor turns
these into human readable form. But you need the raw data in the first
place!

> I disagree with your "much better".  I've used it and I don't
> like it.  I want to be able to include data in the message.

yes. very very yes.


--
"Half-assed programming was a time-filler that, like knitting,
must date to the beginning of human experience."
"A Fire Upon The Deep" by Verne Vinge

Kenneth Brody

unread,
Jan 14, 2010, 11:06:25 AM1/14/10
to
On 1/13/2010 1:06 PM, jacob navia wrote:
> Richard Harter a �crit :
>> Is there any way to reliably check the legitimacy of something
>> that purports to be a file pointer?
>
> No.
>
> This is equivalent to checking a pointer. Under windows is an API that
> does that, maybe in an other systems there is something similar,
> but there isn't anything 100% reliable.
>
> Solution:
>
> When you start the program open the log file and ensure that
> it is OK to write to it. Then store it in some place.
> Eliminate the FILE * argument from the log function specs.
>
> Why should be there anyway? Do you have several log files open
> at the same time?
[...]

There could be a situation with multiple log files open at the same time.
However, in such cases, you could pass a "log file number", perhaps via an
enum, rather than the FILE*.

If you don't like the idea of global variables containing the FILE*'s, then
add a function to return the FILE* when passed the enum. (Or NULL if that
log file is not open.)

--
Kenneth Brody

io_x

unread,
Jan 14, 2010, 2:55:07 PM1/14/10
to

"Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
news:lnr5ptf...@nuthaus.mib.org...

> I agree that fclose() can do some checking, and that it shouldn't be
> too difficult in most implementations. (I won't comment on your
> characterization of an implementation that doesn't do this.)
>
> On the other hand, it's not hard to imagine an implementation that's
> built on top of some lower level, where that lower level doesn't
> provide this kind of checking.
>
> Also (somebody else mentioned this scenario), consider:
>
> fp1 = fopen(...);
> fclose(fp1);

> fp2 = fopen(...);


> /* Suppose fp2 happens to point to the same FILE object that
> fp1 had pointed to.
> */
> ...
> fclose(fp1);
> /* Oops, we closed fp1 twice, but the error isn't detected
> because the pointer looks valid.
> */

in how i see the subject:
here is the place where the program has to abort()

> fclose(fp2);
> /* This should have beeen ok, but the previous fclose clobbered
> the FILE object; if fclose() performs checking, it will
> report the error here rather than where it really occurred
> */
>
> That's not to say that performing checking in fclose() isn't a good
> idea (and closing a file isn't likely to be performance-critical), but
> it can't catch everything.

if the buffer of the file is returned from the malloc() function,
"that performing checking" could be done in free() function too;
free() could show there is a memory leak or better a double free

Flash Gordon

unread,
Jan 14, 2010, 5:51:42 PM1/14/10
to
Richard Harter wrote:
> On Wed, 13 Jan 2010 19:06:42 +0100, jacob navia
> <ja...@spamsink.net> wrote:
>
>> Richard Harter a �crit :
>>> Is there any way to reliably check the legitimacy of something
>>> that purports to be a file pointer?
>> No.

<snip>

>> Solution:
>>
>> When you start the program open the log file and ensure that
>> it is OK to write to it. Then store it in some place.
>> Eliminate the FILE * argument from the log function specs.
>
> Minor quibble: The context is an error exit function, not a log
> function.

I've got one of those as well...

> Actually, the code I use does that. The issue is that there is
> no guarantee that the file pointer is still valid when the error
> exit function is called. Any number of bad things may have
> happened in the interim; indeed something bad must have happened
> or the code wouldn't be calling the error exit function.

Mine has lots of things that should be open and should be closed, but
they might be figments of the corruption causing the crash...

> One can check by trying to put a character and then checking for
> a write error. This may crash the program which is undesirable.
>
> Is there anything better?

If it is Linux/Unix the most likely crash probably generates a SIGSEGV,
and on Windows and other OSs there might be an equivalent signal which
you could trap. So what you can do is something like...

static failstep = 0;

failstep++;

switch {
case 1: log failure
case 2: tidy up
...
}

add cases etc as required in an appropriate order, and you may need a
bit more stuff in the signal handler to re-install itself for the next
SIGSEGV.

It is far from perfect, but it does allow you to first try and abort
nicely with a log message, and gradually do less and less tidying up as
you find out what you can't do.

I would also recommend NOT freeing memory in the abort code, since if
you are crashing because the structures malloc/free use doing another
free only compounds the problem.

<snip>

>> Much better would be:
>>
>> void errexit(char *function_name, char *message, int flags);
>>
>> Error messages do not need to be SO nicely formatted. Just print the
>> location of the code, the errormessage. Flags could be something that
>> tells you if you should exit or not (warning/error) but it can be
>> eliminated.
>>
>> At this point, the software is going to stop running. Do NOT
>> complicate things, do NOT try to have fancy formatting. Just
>> print the message and exit.
>>
>> REMEMBER: Only software people afre going to read this. They are not end
>> users. And if the log file is hard to read they can write a piece of
>> software for better formatting of the log file :-)
>
> I disagree with your "much better". I've used it and I don't
> like it. I want to be able to include data in the message.

I agree, even the programmer needs more information than can be
contained in a fixed message if you can manage to get it out. A fall
back which just chucks out minimal information can also be useful (I
have a daemon that emails a fixed message if it crashes so that the
sysadmin at least knows it needs restarting before it tries to do any
tidying up or detailed error reporting).
--
Flash Gordon

Keith Thompson

unread,
Jan 14, 2010, 6:05:11 PM1/14/10
to
"io_x" <a...@b.c.invalid> writes:
> "Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
> news:lnr5ptf...@nuthaus.mib.org...
>> I agree that fclose() can do some checking, and that it shouldn't be
>> too difficult in most implementations. (I won't comment on your
>> characterization of an implementation that doesn't do this.)
>>
>> On the other hand, it's not hard to imagine an implementation that's
>> built on top of some lower level, where that lower level doesn't
>> provide this kind of checking.
>>
>> Also (somebody else mentioned this scenario), consider:
>>
>> fp1 = fopen(...);
>> fclose(fp1);
>
>> fp2 = fopen(...);
>> /* Suppose fp2 happens to point to the same FILE object that
>> fp1 had pointed to.
>> */
>> ...
>> fclose(fp1);
>> /* Oops, we closed fp1 twice, but the error isn't detected
>> because the pointer looks valid.
>> */
>
> in how i see the subject:
> here is the place where the program has to abort()

Then how you see it is inconsistent with the standard and, as far as I
can tell, with reality.

I agree that it would be nice if this particular error could be
detected (preferably by having fclose return an error indication
rather than by aborting the program), but I don't see how it could be
detected. I suppose the implementation could try to guarantee that
fopen() calls don't return a pointer to a previously closed file, but
that would mean remembering all previously closed files, which could
become unwieldy after a while. Remembering the last N, for some small
value of N, is probably feasible.

>> fclose(fp2);
>> /* This should have beeen ok, but the previous fclose clobbered
>> the FILE object; if fclose() performs checking, it will
>> report the error here rather than where it really occurred
>> */
>>
>> That's not to say that performing checking in fclose() isn't a good
>> idea (and closing a file isn't likely to be performance-critical), but
>> it can't catch everything.
>
> if the buffer of the file is returned from the malloc() function,
> "that performing checking" could be done in free() function too;
> free() could show there is a memory leak or better a double free

malloc and free can have the same kind of problem:

p1 = malloc(...);
free(p1);

p2 = malloc(...); /* p2 happens to point to the same location that
p1 previously pointed to */
free(p1); /* oops! */

The free(p1) call invokes undefined behavior, but without substantial
extra work there's no way the implementation can detect the problem.

Richard Tobin

unread,
Jan 14, 2010, 7:33:59 PM1/14/10
to
In article <lnfx68e...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

>I agree that it would be nice if this particular error could be
>detected (preferably by having fclose return an error indication
>rather than by aborting the program), but I don't see how it could be
>detected. I suppose the implementation could try to guarantee that
>fopen() calls don't return a pointer to a previously closed file, but
>that would mean remembering all previously closed files, which could
>become unwieldy after a while.

It's not unreasonable in a debugging mode. Some malloc()
implementations have a debugging option that effectively makes free()
a no-op, so they never return the same memory twice. For a system
that malloc()s FILE structs, this would have the side-effect of doing
what you suggest.

-- Richard
--
Please remember to mention me / in tapes you leave behind.

io_x

unread,
Jan 15, 2010, 4:14:35 AM1/15/10
to

"Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
news:lnfx68e...@nuthaus.mib.org...

fclose and free have the same problem
only the problem in fclose can be detected from free()
if the implementation of FILE struct type has one
char *buff;
element, with memory returned from malloc() function in that buff
when fopen not fail.

> p1 = malloc(...);
> free(p1);
>
> p2 = malloc(...); /* p2 happens to point to the same location that
> p1 previously pointed to */
> free(p1); /* oops! */
>
> The free(p1) call invokes undefined behavior, but without substantial
> extra work there's no way the implementation can detect the problem.

yes there is some,
if i remember well what i wrote, my home made free sees the list of pointers
returned from malloc; if the pointer is not present in that list it
call exit() function and show in stderr, the sys want to free one pointer
that is not in the malloc list

Because when i write routines i write memory like a stack
a1=malloc(23);
a2=malloc(24);
...
free(a2)
free(a1)
and because free linear search from the last to the first
the order of linear reserch is always O(1) (for my routines)
or at last i think that

don't know very well how fast it would be if i not follow the stack
model of malloc-free memory above...

Keith Thompson

unread,
Jan 15, 2010, 11:28:44 AM1/15/10
to
"io_x" <a...@b.c.invalid> writes:
> "Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
> news:lnfx68e...@nuthaus.mib.org...
[...]

>> p1 = malloc(...);
>> free(p1);
>>
>> p2 = malloc(...); /* p2 happens to point to the same location that
>> p1 previously pointed to */
>> free(p1); /* oops! */
>>
>> The free(p1) call invokes undefined behavior, but without substantial
>> extra work there's no way the implementation can detect the problem.
>
> yes there is some,
> if i remember well what i wrote, my home made free sees the list of pointers
> returned from malloc; if the pointer is not present in that list it
> call exit() function and show in stderr, the sys want to free one pointer
> that is not in the malloc list

And how would that catch the error in the code snippet above?

> Because when i write routines i write memory like a stack
> a1=malloc(23);
> a2=malloc(24);
> ...
> free(a2)
> free(a1)
> and because free linear search from the last to the first
> the order of linear reserch is always O(1) (for my routines)
> or at last i think that

Sure, if you consistently allocate and free in a stack-like manner,
you can avoid certain errors. But what if you don't?

> don't know very well how fast it would be if i not follow the stack
> model of malloc-free memory above...

--

io_x

unread,
Jan 16, 2010, 3:46:37 AM1/16/10
to

"Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
news:lnk4vjc...@nuthaus.mib.org...

> "io_x" <a...@b.c.invalid> writes:
>> "Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
>> news:lnfx68e...@nuthaus.mib.org...
> [...]
>>> p1 = malloc(...);
>>> free(p1);
>>>
>>> p2 = malloc(...); /* p2 happens to point to the same location that
>>> p1 previously pointed to */
>>> free(p1); /* oops! */
>>>
>>> The free(p1) call invokes undefined behavior, but without substantial
>>> extra work there's no way the implementation can detect the problem.
>>
>> yes there is some,
>> if i remember well what i wrote, my home made free sees the list of pointers
>> returned from malloc; if the pointer is not present in that list it
>> call exit() function and show in stderr, the sys want to free one pointer
>> that is not in the malloc list
>
> And how would that catch the error in the code snippet above?

after the first free(p1) that "p1" is not more a pointer in the list of malloc
memory, so when there is the other free(p1), free() not find p1 in the list
(linear search)
of mallokked pointers and make the program to exit because the sys want
free one pointer not returned from malloc

>> Because when i write routines i write memory like a stack
>> a1=malloc(23);
>> a2=malloc(24);
>> ...
>> free(a2)
>> free(a1)
>> and because free linear search from the last to the first
>> the order of linear reserch is always O(1) (for my routines)
>> or at last i think that
>
> Sure, if you consistently allocate and free in a stack-like manner,
> you can avoid certain errors. But what if you don't?

don't know for sure
but this below should not have the "stack-like manner"

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

int main(void)
{unsigned i, j, k;
char *a[500];
time_t tf, ti;

for(i=0; i<500; ++i)
a[i]=0;

ti=time(0);

for(i=0; i<50000000; ++i)
{k=rand()%500;
if(a[k]==0)
{a[k]=malloc(1+rand()%1000);
if(a[k]==0){printf("Out Malloc\n"); goto exi;}
}
if((i&0xFF)==0xFF)
{k=rand()%500;
if(a[k]!=0) {free(a[k]); a[k]=0;}
}
}
exi:;
for(i=0; i<500; ++i) free(a[i]);
tf=time(0);
printf("delta=%.4fs\n", (double)difftime(tf, ti));
return 0;
}

for 500 heap arrays,
the malloc of the compiler and the home made malloc
not show difference in the time of running (1s if i remember the time);
not know for 5000 500000 50000000 heap arrays

is it possible it is because the linear search is less heavy than
"rand()%1000"?

Keith Thompson

unread,
Jan 16, 2010, 12:54:18 PM1/16/10
to

But "p1" isn't in the list; the value that was assigned to "p1" is in
the list. malloc has no way of knowing what the caller did with the
result.

Here's what (probably) happens in a bit more detail. We'll assume
that the system maintains a list of malloced pointers.

p1 = malloc(100);
/* p1 obtains the value, let's say, (void*)0x8446008.
* The system adds 0x8446008 to a list of malloced pointers.
* (Note that it doesn't add p1 to the list; malloc doesn't
* know about p1.
*/

free(p1);
/* In principle, the value of p1 is now indeterminate.
* In practice, it almost certainly still retains the same bit
* pattern, 0x8446008. That address is removed from the list
* of malloced pointers, which is now empty.
*/

p2 = malloc(100);
/* We know there's a free block of at least 100 bytes starting
* at (void*)0x8446008. malloc() may or may not return that
* same address again. Let's assume it does. So now
* p2 == (void*)0x8446008. And p2 still has that same value.
* 0x8446008 is now on the malloc list again.
*/

free(p1);
/* This is incorrect; we meant to write free(p2).
* But all the system knows is that 0x8446008 is on its list,
* and free was just passed that address. As far as the system
* can tell, the call is perfectly valid.
*/

The problem is that, after the second malloc call, the values
stored in p1 and p2 are logically distinct; one is a pointer
(now indeterminate) to memory that's been freed, and the other
is a pointer to memory that's just been allocated. But both
pointer objects happen to hold the same bit pattern, which will be
interpreted as the same value; there's no way for the implementation
to tell the difference.

And if malloc could do the kind of checking you want it to, would it
allow the following perfectly legal code?

p1 = malloc(100);
p2 = p1;
free(p2);

[snip]

io_x

unread,
Jan 18, 2010, 2:37:01 AM1/18/10
to
"Keith Thompson" <ks...@mib.org> ha scritto nel messaggio
news:lnpr5aa...@nuthaus.mib.org...

yes, i were not much clear and possibly wrong too;

the list is not of pointers address,
but address returned from malloc;
if i have malloc(500) return the address 0xFF00FF00
than i add to the list 0xFF00FF00 number

> free(p1);
> /* In principle, the value of p1 is now indeterminate.
> * In practice, it almost certainly still retains the same bit
> * pattern, 0x8446008. That address is removed from the list
> * of malloced pointers, which is now empty.
> */

ok

> p2 = malloc(100);
> /* We know there's a free block of at least 100 bytes starting
> * at (void*)0x8446008. malloc() may or may not return that
> * same address again. Let's assume it does. So now
> * p2 == (void*)0x8446008. And p2 still has that same value.
> * 0x8446008 is now on the malloc list again.
> */

ok

> free(p1);
> /* This is incorrect; we meant to write free(p2).
> * But all the system knows is that 0x8446008 is on its list,
> * and free was just passed that address. As far as the system
> * can tell, the call is perfectly valid.
> */

follow the case you say, (hope i not miss anything)
[the two malloc call return the same value]
if instead of "free(p2)" you write "free(p1)" nothing change

if the program has only the two calls to malloc,
there is no memory allocated from the program,
and you not use p2 (because to believe that it be free
when write "free(p1)" above;)
so no problem, but the sys is silent and could be run
the case below

in the other case: p2 has one different value
free(p1) should detect it (because what p1 store address is not in
the malloced list of addresses)

> The problem is that, after the second malloc call, the values
> stored in p1 and p2 are logically distinct; one is a pointer
> (now indeterminate) to memory that's been freed, and the other
> is a pointer to memory that's just been allocated.

the second is free too

> But both
> pointer objects happen to hold the same bit pattern, which will be
> interpreted as the same value; there's no way for the implementation
> to tell the difference.
>
> And if malloc could do the kind of checking you want it to, would it
> allow the following perfectly legal code?
>
> p1 = malloc(100);
> p2 = p1;
> free(p2);

this is ok, free serach on all the address that return,
and the address of p1==p2 is free

Richard Harter

unread,
Jan 20, 2010, 5:03:05 PM1/20/10
to

My apolgies for not responding sooner, but I do want to thank you
for your suggestions. Catching SIGSEGV should catch most of the
problems. My error exit routines potentially dump out a lot of
information before actually releasing resources.

Good response, thank you.

0 new messages