Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #43358 > unrolled thread

free a pointer and have it point to NULL

Started byG G <gdotone@gmail.com>
First post2014-04-22 14:22 -0700
Last post2014-05-03 01:00 -0700
Articles 20 on this page of 36 — 16 participants

Back to article view | Back to comp.lang.c


Contents

  free a pointer and have it point to NULL G G <gdotone@gmail.com> - 2014-04-22 14:22 -0700
    Re: free a pointer and have it point to NULL James Kuyper <jameskuyper@verizon.net> - 2014-04-22 17:32 -0400
    Re: free a pointer and have it point to NULL G G <gdotone@gmail.com> - 2014-04-22 14:36 -0700
    Re: free a pointer and have it point to NULL Keith Thompson <kst-u@mib.org> - 2014-04-22 14:37 -0700
      Re: free a pointer and have it point to NULL Johannes Bauer <dfnsonfsduifb@gmx.de> - 2014-04-29 13:10 +0200
        Re: free a pointer and have it point to NULL Richard <rgrdev_@gmail.com> - 2014-04-29 13:14 +0200
          Re: free a pointer and have it point to NULL Ben Bacarisse <ben.usenet@bsb.me.uk> - 2014-04-29 13:19 +0100
            Re: free a pointer and have it point to NULL Kaz Kylheku <kaz@kylheku.com> - 2014-04-29 13:57 +0000
        Re: free a pointer and have it point to NULL Kaz Kylheku <kaz@kylheku.com> - 2014-04-29 13:43 +0000
        Re: free a pointer and have it point to NULL James Kuyper <jameskuyper@verizon.net> - 2014-04-29 09:59 -0400
          Re: free a pointer and have it point to NULL Keith Thompson <kst-u@mib.org> - 2014-04-29 07:58 -0700
            Re: free a pointer and have it point to NULL Keith Thompson <kst-u@mib.org> - 2014-04-29 11:50 -0700
              Re: free a pointer and have it point to NULL James Kuyper <jameskuyper@verizon.net> - 2014-04-29 15:47 -0400
          Re: free a pointer and have it point to NULL James Kuyper <jameskuyper@verizon.net> - 2014-04-29 12:41 -0400
            Re: free a pointer and have it point to NULL Robert Wessel <robertwessel2@yahoo.com> - 2014-04-29 13:15 -0500
              Re: free a pointer and have it point to NULL glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-29 21:29 +0000
        Re: free a pointer and have it point to NULL glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-29 15:26 +0000
    Re: free a pointer and have it point to NULL jt@toerring.de (Jens Thoms Toerring) - 2014-04-22 21:43 +0000
      Re: free a pointer and have it point to NULL Keith Thompson <kst-u@mib.org> - 2014-04-22 14:53 -0700
        Re: free a pointer and have it point to NULL Öö Tiib <ootiib@hot.ee> - 2014-04-24 00:38 -0700
          Re: free a pointer and have it point to NULL James Kuyper <jameskuyper@verizon.net> - 2014-04-24 07:52 -0400
            Re: free a pointer and have it point to NULL <william@wilbur.25thandClement.com> - 2014-04-24 16:13 -0700
              Re: free a pointer and have it point to NULL Ian Collins <ian-news@hotmail.com> - 2014-04-25 12:02 +1200
                Re: free a pointer and have it point to NULL <william@wilbur.25thandClement.com> - 2014-04-24 22:03 -0700
                  Re: free a pointer and have it point to NULL Ian Collins <ian-news@hotmail.com> - 2014-04-25 17:22 +1200
                    Re: free a pointer and have it point to NULL <william@wilbur.25thandClement.com> - 2014-04-24 23:00 -0700
            Re: free a pointer and have it point to NULL Öö Tiib <ootiib@hot.ee> - 2014-04-27 08:32 -0700
      Re: free a pointer and have it point to NULL Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2014-04-22 16:19 -0600
        Re: free a pointer and have it point to NULL Kaz Kylheku <kaz@kylheku.com> - 2014-04-22 22:41 +0000
          Re: free a pointer and have it point to NULL Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2014-04-22 18:17 -0600
            Re: free a pointer and have it point to NULL Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2014-04-24 08:48 -0600
      non-NULL pointers which have the value 0 (Was: Re: free a pointer and have it point to NULL) Andrew Cooper <root@127.0.0.1> - 2014-04-23 03:28 +0100
        Re: non-NULL pointers which have the value 0 (Was: Re: free a pointer and have it point to NULL) Kaz Kylheku <kaz@kylheku.com> - 2014-04-23 04:37 +0000
        Re: non-NULL pointers which have the value 0 glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-23 06:14 +0000
    Re: free a pointer and have it point to NULL Kaz Kylheku <kaz@kylheku.com> - 2014-04-22 22:18 +0000
    Re: free a pointer and have it point to NULL Michael Angelo Ravera <maravera@prodigy.net> - 2014-05-03 01:00 -0700

Page 1 of 2  [1] 2  Next page →


#43358 — free a pointer and have it point to NULL

FromG G <gdotone@gmail.com>
Date2014-04-22 14:22 -0700
Subjectfree a pointer and have it point to NULL
Message-ID<639a5283-8e4b-4f9a-aa7f-ef2c88174768@googlegroups.com>
memory allocated on the heap once freed should the pointer be assigned NULL?

[toc] | [next] | [standalone]


#43364

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-22 17:32 -0400
Message-ID<5356E006.3040900@verizon.net>
In reply to#43358
On 04/22/2014 05:22 PM, G G wrote:
> memory allocated on the heap once freed should the pointer be assigned NULL?

Only if there's a danger of the pointer being used again after being
free()'d. Even then, it's only useful if other code, elsewhere, checks
if(p) before trying to dereference p. Finally, if there are multiple
saved pointers, all pointing into the same block of allocated memory,
setting one of those pointers to be null won't help avoid problems with
any of the other pointers. They must all be protected by if(p).

I often use the following approach, which removes all need for nulling
out the free()'d pointer:

{
   int *p = malloc(num_elements*sizeof *p);
   if(p==NULL)
   {
       // Error handling
   }
   else
   {
       // Code which uses *p
       free(p);
   }
   // Key point: *p is not used anywhere in this section
}

Since the lifetime of 'p' ends immediately after free(p), there's no
need to write "p = NULL;". This approach cannot be used if the malloc()
and free() must occur in different functions, or at very different
levels within the same function.

[toc] | [prev] | [next] | [standalone]


#43366

FromG G <gdotone@gmail.com>
Date2014-04-22 14:36 -0700
Message-ID<d872c98b-c64e-4af0-8d8d-1a99fe446da6@googlegroups.com>
In reply to#43358
On Tuesday, April 22, 2014 5:22:34 PM UTC-4, G G wrote:

ok.

thanks Stefan and James

[toc] | [prev] | [next] | [standalone]


#43367

FromKeith Thompson <kst-u@mib.org>
Date2014-04-22 14:37 -0700
Message-ID<lny4yxvydz.fsf@nuthaus.mib.org>
In reply to#43358
G G <gdotone@gmail.com> writes:
> memory allocated on the heap once freed should the pointer be assigned NULL?

Maybe.

After free(ptr), the value of ptr is *indeterminate*, meaning that any
attempt to refer to its value has undefined behavior.  In practice, just
reading the pointer probably isn't going to do anything harmful.  But
having such a pointer value sitting around creates a potential source of
bugs, and setting it to NULL can remove *some* such bugs, or at least
change them into different bugs that might be easier to detect.

On the other hand, if the pointer object is just about to go out of
scope and therefore cease to exist, there's no point in setting it to
NULL.  Example:

    {
        unsigned char *buffer = malloc(some_size);
        /* error checking omitted */
        /* code that uses the pointer omitted */
        free(buffer);
    }

Setting buffer to NULL after calling free() would be pointless, because
there's no way to refer to its value accidentally.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43811

FromJohannes Bauer <dfnsonfsduifb@gmx.de>
Date2014-04-29 13:10 +0200
Message-ID<ljo1b6$rba$1@news.albasani.net>
In reply to#43367
On 22.04.2014 23:37, Keith Thompson wrote:
> G G <gdotone@gmail.com> writes:
>> memory allocated on the heap once freed should the pointer be assigned NULL?
> 
> Maybe.
> 
> After free(ptr), the value of ptr is *indeterminate*, meaning that any
> attempt to refer to its value has undefined behavior.

Woo, really? I find that rather surprising. Does this mean that free()
specifically is a special case or was this just a writing error on your
part? If free behaved like all other functions, the value of ptr would
be well defined after the free (to be the same value as before the free,
since pointers are call-by-value).

Defererencing that pointer after a free has obviously indeterminate
consequences, but is also the pointer *value* indeterminate?

Regards,
Johannes

-- 
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?
> Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
 - Karl Kaos über Rüdiger Thomas in dsa <hidbv3$om2$1@speranza.aioe.org>

[toc] | [prev] | [next] | [standalone]


#43812

FromRichard <rgrdev_@gmail.com>
Date2014-04-29 13:14 +0200
Message-ID<87fvkw75h8.fsf@gmail.com>
In reply to#43811
Johannes Bauer <dfnsonfsduifb@gmx.de> writes:

> On 22.04.2014 23:37, Keith Thompson wrote:
>> G G <gdotone@gmail.com> writes:
>>> memory allocated on the heap once freed should the pointer be assigned NULL?
>> 
>> Maybe.
>> 
>> After free(ptr), the value of ptr is *indeterminate*, meaning that any
>> attempt to refer to its value has undefined behavior.
>
> Woo, really? I find that rather surprising. Does this mean that free()
> specifically is a special case or was this just a writing error on your
> part? If free behaved like all other functions, the value of ptr would
> be well defined after the free (to be the same value as before the free,
> since pointers are call-by-value).
>
> Defererencing that pointer after a free has obviously indeterminate
> consequences, but is also the pointer *value* indeterminate?
>
> Regards,
> Johannes

Of course it isnt. The pointer value cant be changed since the parameter
is a void *  : VALUE. The free() function can not alter the value in the
pointer variable used to provide that void * value to the function.


-- 
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

[toc] | [prev] | [next] | [standalone]


#43815

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2014-04-29 13:19 +0100
Message-ID<0.0b3e0de7235790a9eb66.20140429131934BST.87d2g0xr8p.fsf@bsb.me.uk>
In reply to#43812
Richard <rgrdev_@gmail.com> writes:

> Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
>
>> On 22.04.2014 23:37, Keith Thompson wrote:
>>> G G <gdotone@gmail.com> writes:
>>>> memory allocated on the heap once freed should the pointer be
>>>> assigned NULL?
>>> 
>>> Maybe.
>>> 
>>> After free(ptr), the value of ptr is *indeterminate*, meaning that any
>>> attempt to refer to its value has undefined behavior.
>>
>> Woo, really?

Yes: "The value of a pointer becomes indeterminate when the object it
points to (or just past) reaches the end of its lifetime."  (6.2.4 p2).

>> I find that rather surprising. Does this mean that free()
>> specifically is a special case or was this just a writing error on your
>> part? If free behaved like all other functions, the value of ptr would
>> be well defined after the free (to be the same value as before the free,
>> since pointers are call-by-value).

I think you are reading too much into the phrase.  "Becomes
indeterminate" does not mean that any of the bits have to change.  If
the standard said "becomes invalid" I don't think you'd worry about it.

A pointer bit pattern could, for example, become invalid as a result of
the free function fiddling with some memory management registers; any
reference to that value might then cause undefined behaviour (which,
remember, includes nothing bad happening).  The standard has a term for
that sort of value: "indeterminate".  It's unfortunate that "becomes
indeterminate" suggest that you can't know anything about the bits that
make up the value, but, in the C standard, the value of an object is an
interpretation of its bits, and that can change without the bits
themselves changing.

>> Defererencing that pointer after a free has obviously indeterminate
>> consequences, but is also the pointer *value* indeterminate?
>>
>> Regards,
>> Johannes
>
> Of course it isnt. The pointer value cant be changed since the parameter
> is a void *  : VALUE. The free() function can not alter the value in the
> pointer variable used to provide that void * value to the function.

The representation in the object does not need to change for it to
represent a trap representation -- a term is just standardese for a
value you can't use without undefined behaviour.  When you unpack the
definitions of various the terms involved ("indeterminate value",
"unspecified value", "trap representation"), you end up with this
uncontroversial observation: before the call to free, the pointer is a
"valid value of the relevant type", but afterwards it "need not
represent a value of the object type".

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#43823

FromKaz Kylheku <kaz@kylheku.com>
Date2014-04-29 13:57 +0000
Message-ID<20140429064354.459@kylheku.com>
In reply to#43815
On 2014-04-29, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>Yes: "The value of a pointer becomes indeterminate when the object it
>>points to (or just past) reaches the end of its lifetime."  (6.2.4 p2).
>
>   Sometimes, in C there is a irritating distinction some people make
>   between address values and pointers. Some people say that &x is an
>   address value, but a pointer is /an object/ storing an address value.
>
>   There is some support in N1570 itself for this:
>
>       »A pointer type describes an object whose value provides
>       a reference to an entity of the referenced type.«

(But does not provide pass-by-reference, haha.)

>   It says »an object«, not »a value«!

It says "object, whose value ..."!

C types describe objects: i.e. they specify an in-memory representation
that can be broken down into bits and bytes (the quantity of the latter being
the "sizeof" that type).

C values are manipulated in the data processor such that they are not always
objects, but their type specifies details about what they look like when they
are stored.

The above sentence is primarily concerned with defining "pointer type".

[toc] | [prev] | [next] | [standalone]


#43822

FromKaz Kylheku <kaz@kylheku.com>
Date2014-04-29 13:43 +0000
Message-ID<20140429061755.912@kylheku.com>
In reply to#43811
On 2014-04-29, Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:
> On 22.04.2014 23:37, Keith Thompson wrote:
>> G G <gdotone@gmail.com> writes:
>>> memory allocated on the heap once freed should the pointer be assigned NULL?
>> 
>> Maybe.
>> 
>> After free(ptr), the value of ptr is *indeterminate*, meaning that any
>> attempt to refer to its value has undefined behavior.
>
> Woo, really? I find that rather surprising. Does this mean that free()
> specifically is a special case or was this just a writing error on your
> part? If free behaved like all other functions, the value of ptr would
> be well defined after the free (to be the same value as before the free,
> since pointers are call-by-value).

A pointer which refers to any object object that has been destroyed
(a "dangling pointer") is indeterminate. This is not limited to the free
function: pointers to objects defined in automatic storage (block scope
non-static local variables) also become indeterminate when their enclosing
block terminates.

This can happen without a change in the value which is stored.  The value
remains the same, but its meaning changes.  The value is no longer on the
roster of valid pointers, and so it is possible to diagnose any use of that
value, even a harmless transmission from one variable to another without
dereferencing.

A tracing technique related to garbage collection could be used to find
all dangling pointers and overwrite them with a value like null or some other
value deemed useful for debugging. Because such pointers have indeterminate
values, implementors have this freedom.

By far the most common implementation is that nothing happens to such values at
all, and when the storage is re-used for a new object, dangling pointers appear
to be valid pointers referencing the new object.

The rule allows for sophisticated debugging tools which catch problems as early
as possible.

Usually, any use whatsoever of a dangling pointer indicates a bug; there is no
useful purpose behind it.

The exception are introspective programs designed to inspect the behaviors of
memory allocation: to answer questions like "is an object recycled
immediately?":

  {
    char *p = malloc(10), *q;
    free(p);
    q = malloc(10);

    if (p == q) {
       puts("ten byte object was recycled immediately");
    }

    free(q);
  }

Or:

  void *p, *q;

  {
    int x;
    p = &x;
  }

  {
    int y;
    q = &y;
  }

  if (p == q) {
    puts("Cool: x and y were placed in overlapping storage");
  }

The rules in C are such that an implementation can diagnose these programs, and
even halt their execution.

(There is a workaround for that: to use memcmp to compare the pointers.
However, that raises the risk of the comparison being spoiled by
padding bits in a pointer which change its bitwise image, but not
it value (where it points)).

> Defererencing that pointer after a free has obviously indeterminate
> consequences, but is also the pointer *value* indeterminate?

It is the indeterminacy of the value which causes the behavior, upon
dereferencing, to be undefined.

The idea that the pointer value remains "good" from the point of view
of access, but cannot be dereferenced, would require a new category of value in
C, which isn't worth it: a category that isn't "indeterminate", but something
else.

There is a pointer value which has that behavior: it can be used, but not
dereferenced. Namely, the null pointer.  However, a location which might hold a
null pointer can be accessed for a useful purpose: to test whether or not it is
null.

[toc] | [prev] | [next] | [standalone]


#43824

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-29 09:59 -0400
Message-ID<ljob8f$f8i$1@dont-email.me>
In reply to#43811
On 04/29/2014 07:10 AM, Johannes Bauer wrote:
> On 22.04.2014 23:37, Keith Thompson wrote:
>> G G <gdotone@gmail.com> writes:
>>> memory allocated on the heap once freed should the pointer be assigned NULL?
>>
>> Maybe.
>>
>> After free(ptr), the value of ptr is *indeterminate*, meaning that any
>> attempt to refer to its value has undefined behavior.
> 
> Woo, really? I find that rather surprising. Does this mean that free()
> specifically is a special case or was this just a writing error on your
> part? If free behaved like all other functions, the value of ptr would
> be well defined after the free (to be the same value as before the free,
> since pointers are call-by-value).
> 
> Defererencing that pointer after a free has obviously indeterminate
> consequences, but is also the pointer *value* indeterminate?

Yes.
"... The value of a pointer becomes indeterminate when the object it
points to (or just past) reaches the end of its lifetime." (6.2.4p2)
"The lifetime of an allocated object extends from the allocation
until the deallocation." (7.22.3p1)
"The free function causes the space pointed to by ptr to be deallocated
..." (7.22.3.3p2)

Keep in mind that it is possible for the value of a pointer to become
indeterminate without any change to it's bit patterns. There are real
systems which have the ability to make blocks of memory switch from
being valid to being invalid while a program is running, and because of
the clauses listed above, a fully conforming implementation of free()
could have that effect.

I personally believe that such changes are the only permitted way for
free() to render a pointer invalid - that it is not permitted to modify
the bit pattern of the pointer itself. However, I've had extended
discussions about that on this newsgroup with people who felt otherwise,
with neither side ever accepting the validity of the other's arguments.

Keep in mind that all pointers anywhere in the program that point at any
part of an allocated block of memory have an indeterminate value after
that block is deallocated. Nothing remotely resembling the normal
semantics for C function calls would allow all of those pointers to have
their bit patterns modified just by calling free() on one of those pointers.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#43827

FromKeith Thompson <kst-u@mib.org>
Date2014-04-29 07:58 -0700
Message-ID<lnsiownpwl.fsf@nuthaus.mib.org>
In reply to#43824
James Kuyper <jameskuyper@verizon.net> writes:
[...]
> Keep in mind that it is possible for the value of a pointer to become
> indeterminate without any change to it's bit patterns. There are real
> systems which have the ability to make blocks of memory switch from
> being valid to being invalid while a program is running, and because of
> the clauses listed above, a fully conforming implementation of free()
> could have that effect.
>
> I personally believe that such changes are the only permitted way for
> free() to render a pointer invalid - that it is not permitted to modify
> the bit pattern of the pointer itself. However, I've had extended
> discussions about that on this newsgroup with people who felt otherwise,
> with neither side ever accepting the validity of the other's arguments.
>
> Keep in mind that all pointers anywhere in the program that point at any
> part of an allocated block of memory have an indeterminate value after
> that block is deallocated. Nothing remotely resembling the normal
> semantics for C function calls would allow all of those pointers to have
> their bit patterns modified just by calling free() on one of those pointers.

A compiler could treat the free() function specially, but it's unlikely
that

    char *p = malloc(10);
    if (p ! NULL) {
        p ++;
        free(p-1);
    }

would modify the representation if p.

Furthermore, the bytes that make up the representation of p are
themselves objects which "retain their last-stored values between
program startup and program termination".

On the other hand, I seem to recall that there's a DR that says free()
*can* change the representation of a pointer object after its value is
passed to free().  I'll try to track it down later.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43840

FromKeith Thompson <kst-u@mib.org>
Date2014-04-29 11:50 -0700
Message-ID<lnk3a8nf64.fsf@nuthaus.mib.org>
In reply to#43827
Keith Thompson <kst-u@mib.org> writes:
> James Kuyper <jameskuyper@verizon.net> writes:
> [...]
>> Keep in mind that it is possible for the value of a pointer to become
>> indeterminate without any change to it's bit patterns. There are real
>> systems which have the ability to make blocks of memory switch from
>> being valid to being invalid while a program is running, and because of
>> the clauses listed above, a fully conforming implementation of free()
>> could have that effect.
>>
>> I personally believe that such changes are the only permitted way for
>> free() to render a pointer invalid - that it is not permitted to modify
>> the bit pattern of the pointer itself. However, I've had extended
>> discussions about that on this newsgroup with people who felt otherwise,
>> with neither side ever accepting the validity of the other's arguments.
>>
>> Keep in mind that all pointers anywhere in the program that point at any
>> part of an allocated block of memory have an indeterminate value after
>> that block is deallocated. Nothing remotely resembling the normal
>> semantics for C function calls would allow all of those pointers to have
>> their bit patterns modified just by calling free() on one of those pointers.
>
> A compiler could treat the free() function specially, but it's unlikely
> that
>
>     char *p = malloc(10);
>     if (p ! NULL) {
>         p ++;
>         free(p-1);
>     }
>
> would modify the representation if p.
>
> Furthermore, the bytes that make up the representation of p are
> themselves objects which "retain their last-stored values between
> program startup and program termination".
>
> On the other hand, I seem to recall that there's a DR that says free()
> *can* change the representation of a pointer object after its value is
> passed to free().  I'll try to track it down later.

It's C99 DR #260, submitted by Clive D.W. Feather in 2004.
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm

As far as I can tell, the DR didn't lead to any specific wording in the
C11 standard, but the committee response was:

    Question 1:
    Values may have any bit-pattern that validly represents them 
    and the implementation is free to move between alternate
    representations (for example, it may normalize pointers,
    floating-point representations etc.). In the case of an
    indeterminate value all bit-patterns are valid representations
    and the actual bit-pattern may change without direct action of
    the program.

    Question 2:
    If two objects have identical bit-pattern representations and 
    their types are the same they may still compare as unequal
    (for example if one object has an indeterminate value) and if
    one is an indeterminate value attempting to read such an object
    invokes undefined behavior. Implementations are permitted to 
    track the origins of a bit-pattern and treat those representing 
    an indeterminate value as distinct from those representing a
    determined value. They may also treat pointers based on different
    origins as distinct even though they are bitwise identical.

In reference to "Question 1", I agree that it makes sense to permit an
implementation to normalize pointers and floating-point objects when two
or more representations have the same value.  I wrote above that the
bytes making up the representation of an object are themselves objects,
which are required by 6.2.4p2 to "retain[] its last-stored value
throughout its lifetime".

I'm no longer quite as sure of that, given the way 6.2.6.1 defines
*object representation*:

    Values stored in non-bit-field objects of any other object type
    consist of n × CHAR_BIT bits, where n is the size of an object
    of that type, in bytes. The value may be copied into an object
    of type unsigned char [n] (e.g., by memcpy); the resulting set
    of bytes is called the *object representation* of the value.

which talks about the bytes *after copying them from the object*,
so at least that paragraph doesn't imply that the bytes within the
object itself are objects.

On the other hand, an object is defined as a "region of data storage in
the execution environment, the contents of which can represent values";
a byte within a pointer object, for example, would seem to qualify.

On the other other hand, a program that depends on a byte within a freed
pointer retaining its previous value would be perverse, and I don't feel
*too* bad about the possibility of breaking it.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43841

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-29 15:47 -0400
Message-ID<536001B4.8010902@verizon.net>
In reply to#43840
On 04/29/2014 02:50 PM, Keith Thompson wrote:
...
> or more representations have the same value.  I wrote above that the
> bytes making up the representation of an object are themselves objects,
> which are required by 6.2.4p2 to "retain[] its last-stored value
> throughout its lifetime".
> 
> I'm no longer quite as sure of that, given the way 6.2.6.1 defines
> *object representation*:
> 
>     Values stored in non-bit-field objects of any other object type
>     consist of n × CHAR_BIT bits, where n is the size of an object
>     of that type, in bytes. The value may be copied into an object
>     of type unsigned char [n] (e.g., by memcpy); the resulting set
>     of bytes is called the *object representation* of the value.
> 
> which talks about the bytes *after copying them from the object*,
> so at least that paragraph doesn't imply that the bytes within the
> object itself are objects.
> 
> On the other hand, an object is defined as a "region of data storage in
> the execution environment, the contents of which can represent values";
> a byte within a pointer object, for example, would seem to qualify.
> 
> On the other other hand, a program that depends on a byte within a freed
> pointer retaining its previous value would be perverse, and I don't feel
> *too* bad about the possibility of breaking it.

At that level, I would agree. However, if 6.2.4p2 is not to be
interpreted as prohibiting such changes, it renders essentially all uses
of memcmp() useless, at least for any type that is allowed to have
multiple representations of the same value (which could includes any
integer type with padding bits, any signed type with anything other 2's
complement representation, and all floating point and pointer types).

[toc] | [prev] | [next] | [standalone]


#43836

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-04-29 12:41 -0400
Message-ID<535FD623.5000200@verizon.net>
In reply to#43824
On 04/29/2014 09:59 AM, James Kuyper wrote:
...
> ... There are real
> systems which have the ability to make blocks of memory switch from
> being valid to being invalid while a program is running, ...

I left out a key step: on such systems it is often the case that loading
an invalid into an address register is sufficient to cause your program
abort. Dereferencing the pointer isn't necessary. This is a safety
measure: the designers felt that any program written badly enough to
treat an invalid address as if were a valid one, is sufficiently
dangerous that it's safest to have a policy of stopping such programs as
soon as possible.

> ... and because of
> the clauses listed above, a fully conforming implementation of free()
> could have that effect.

[toc] | [prev] | [next] | [standalone]


#43838

FromRobert Wessel <robertwessel2@yahoo.com>
Date2014-04-29 13:15 -0500
Message-ID<viqvl9he4oah9fqr5n1fjmlfac17q1mv0k@4ax.com>
In reply to#43836
On Tue, 29 Apr 2014 12:41:07 -0400, James Kuyper
<jameskuyper@verizon.net> wrote:

>On 04/29/2014 09:59 AM, James Kuyper wrote:
>...
>> ... There are real
>> systems which have the ability to make blocks of memory switch from
>> being valid to being invalid while a program is running, ...
>
>I left out a key step: on such systems it is often the case that loading
>an invalid into an address register is sufficient to cause your program
>abort. Dereferencing the pointer isn't necessary. This is a safety
>measure: the designers felt that any program written badly enough to
>treat an invalid address as if were a valid one, is sufficiently
>dangerous that it's safest to have a policy of stopping such programs as
>soon as possible.


While not specifically a C example, we supported the Realia Cobol
compiler in the 16-bit era, and on protected mode systems, you'd have
exactly that problem.

Cobol is mostly pass-by-reference (in those days it was all
pass-by-ref, there is some pass-by-value in the modern standards), and
the Realia calling convention put the (pointers to the) first two
parameters in DS:SI and ES:DI.  Merely calling a subroutine with a
pointer to storage that had been returned to the OS would cause an
abend when the caller tried to load the appropriate segment register.

[toc] | [prev] | [next] | [standalone]


#43846

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-04-29 21:29 +0000
Message-ID<ljp5ji$6k8$1@speranza.aioe.org>
In reply to#43838
Robert Wessel <robertwessel2@yahoo.com> wrote:
> On Tue, 29 Apr 2014 12:41:07 -0400, James Kuyper
> <jameskuyper@verizon.net> wrote:

(snip)
>>I left out a key step: on such systems it is often the case that loading
>>an invalid into an address register is sufficient to cause your program
>>abort. Dereferencing the pointer isn't necessary. This is a safety
>>measure: the designers felt that any program written badly enough to
>>treat an invalid address as if were a valid one, is sufficiently
>>dangerous that it's safest to have a policy of stopping such programs as
>>soon as possible.

More specifically, the way x86 processors starting with the 80286
work, is that when you load a segment selector into a segment
register, the processor also loads a segment descriptor from the
appropriate entry in a descriptor table. If the descriptor is 
invalid, an interrupt occurs.

> While not specifically a C example, we supported the Realia Cobol
> compiler in the 16-bit era, and on protected mode systems, you'd have
> exactly that problem.

C compilers I know tend to avoid loading segment registers until
they are pretty much ready to use them. For example, pointer
assignment and pointer comparison are not done using a segment
register. (I don't believe that there are compare instructions
for segment registers. Assignment could be done through load
and store, though.)
 
> Cobol is mostly pass-by-reference (in those days it was all
> pass-by-ref, there is some pass-by-value in the modern standards), and
> the Realia calling convention put the (pointers to the) first two
> parameters in DS:SI and ES:DI.  Merely calling a subroutine with a
> pointer to storage that had been returned to the OS would cause an
> abend when the caller tried to load the appropriate segment register.

There have been many systems where you could load from any memory
address, such as real mode MS-DOS. Some programmers for those
systems tend to ignore fetch from bad addresses, such as past the
end of arrays. (In most cases, just after the end of an array is
still part of your address space.) 

Much code for languages that don't require short-circuit IF
evaluation works because the out of bounds fetch doesn't cause
any problems.

And, by the way, all the segment selector logic is still in
current, and likely future, x86 processors.  It isn't some strange
system that died out years ago, now only found in a museum.
(But there are some of those, too.)

-- glen

[toc] | [prev] | [next] | [standalone]


#43831

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-04-29 15:26 +0000
Message-ID<ljogah$cht$1@speranza.aioe.org>
In reply to#43811
Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:
> On 22.04.2014 23:37, Keith Thompson wrote:

(snip)

>> After free(ptr), the value of ptr is *indeterminate*, meaning that any
>> attempt to refer to its value has undefined behavior.
 
> Woo, really? I find that rather surprising. Does this mean that free()
> specifically is a special case or was this just a writing error on your
> part? If free behaved like all other functions, the value of ptr would
> be well defined after the free (to be the same value as before the free,
> since pointers are call-by-value).
 
> Defererencing that pointer after a free has obviously indeterminate
> consequences, but is also the pointer *value* indeterminate?

For protected mode x86 (80286 and up) loading a segment selector
for a non-allocated segment will fail. That is, a segmentation
violation. (You always wondered where the name came from?)

Now, most compilers won't actually load one into a segment
register when not needed to actually reference data, but the
standard allows it to fail.

(Selector zero is reserved as the null segment, so there is some
value to use when there is nothing else to load.)

-- glen

[toc] | [prev] | [next] | [standalone]


#43371

Fromjt@toerring.de (Jens Thoms Toerring)
Date2014-04-22 21:43 +0000
Message-ID<bro63iFojnqU2@mid.uni-berlin.de>
In reply to#43358
G G <gdotone@gmail.com> wrote:
> memory allocated on the heap once freed should the pointer be assigned NULL?

It can't hurt since any attempt to use the now invalid pointer
again would lead to an immediate crash of the program. But then
it depends a bit on circumstances: if the free() is at the end
of a function and there's no chance that the pointer is acci-
dentally used again, then there's not much good it will do.
And, of course, each free() will have to be followed by
another line of code, which can become tedious and make
things a bit harder to read - unless you use a macro like

#define safe_free( addr )   \
  do {                      \
          free( addr );     \
          addr = NULL;      \
  } while ( 1 == 0 )

instead of free() everywhere. I've done that in several cases
where I felt the need to be paranoid;-)

                          Regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de

[toc] | [prev] | [next] | [standalone]


#43374

FromKeith Thompson <kst-u@mib.org>
Date2014-04-22 14:53 -0700
Message-ID<lntx9lvxod.fsf@nuthaus.mib.org>
In reply to#43371
jt@toerring.de (Jens Thoms Toerring) writes:
> G G <gdotone@gmail.com> wrote:
>> memory allocated on the heap once freed should the pointer be assigned NULL?
>
> It can't hurt since any attempt to use the now invalid pointer
> again would lead to an immediate crash of the program. But then
> it depends a bit on circumstances: if the free() is at the end
> of a function and there's no chance that the pointer is acci-
> dentally used again, then there's not much good it will do.
> And, of course, each free() will have to be followed by
> another line of code, which can become tedious and make
> things a bit harder to read - unless you use a macro like
>
> #define safe_free( addr )   \
>   do {                      \
>           free( addr );     \
>           addr = NULL;      \
>   } while ( 1 == 0 )
>
> instead of free() everywhere. I've done that in several cases
> where I felt the need to be paranoid;-)

"do { ... } while (0)" is the usual idiom for writing a macro that can
be used in a context requiring a statement; the "1 == 0" just seems
(mildly) obfuscated.

But when possible, it's usually better to write a macro that can be used
wherever an expression can appear.  In this case:

    #define safe_free(addr) ( free(addr), (addr) = NULL )

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#43494

FromÖö Tiib <ootiib@hot.ee>
Date2014-04-24 00:38 -0700
Message-ID<bb6ae6cb-b7bc-470f-aed6-2f83aa3ff768@googlegroups.com>
In reply to#43374
On Wednesday, 23 April 2014 00:53:06 UTC+3, Keith Thompson  wrote:
> jt@toerring.de (Jens Thoms Toerring) writes:
> > G G <gdotone@gmail.com> wrote:
> >> memory allocated on the heap once freed should the pointer be assigned NULL?
> >
> > It can't hurt since any attempt to use the now invalid pointer
> > again would lead to an immediate crash of the program. But then
> > it depends a bit on circumstances: if the free() is at the end
> > of a function and there's no chance that the pointer is acci-
> > dentally used again, then there's not much good it will do.
> > And, of course, each free() will have to be followed by
> > another line of code, which can become tedious and make
> > things a bit harder to read - unless you use a macro like
> >
> > #define safe_free( addr )   \
> >   do {                      \
> >           free( addr );     \
> >           addr = NULL;      \
> >   } while ( 1 == 0 )
> >
> > instead of free() everywhere. I've done that in several cases
> > where I felt the need to be paranoid;-)
> 
> "do { ... } while (0)" is the usual idiom for writing a macro that can
> be used in a context requiring a statement; the "1 == 0" just seems
> (mildly) obfuscated.

I have seen even 'while (__LINE__ == -1)' there to silence a warning
of particular compiler that sometimes complained about condition
being constant expression (like on case of  '0' or '1 == 0' but not on
case  of '__LINE__ == -1').

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web