Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Pointer to small amount of storage

Reply
Thread Tools

Pointer to small amount of storage

 
 
santosh
Guest
Posts: n/a
 
      02-27-2008
Keith Thompson wrote:

> CBFalconer <(E-Mail Removed)> writes:
>> Richard Tobin wrote:
>>> CBFalconer <(E-Mail Removed)> wrote:
>>>>> Good catch. How about this case:
>>>>> long *q = malloc(2);
>>>>>
>>>>> assuming sizeof(long) > 2 ? Now the 'defence' of the pointer
>>>>> having to be able to be converted back to short, is no longer
>>>>> available.
>>>
>>>> That malloc doesn't assign enough space to hold the posited long.
>>>> Replace the '2' with "sizeof *q" (sans quotes) and all is well.
>>>
>>> There isn't any "posited long". The question is whether this is
>>> legal *if you don't store into q*.

>>
>> Yes there is. Its name is '*q'. It is uninitialized, and not
>> usable until initialized. Initializing would be illegal, because
>> the storage is too small. I guess the word 'posited' was not clear
>> to non-English speakers.
>>
>>>
>>> Bear in mind that long *q = malloc(0) is legal.

>>
>> But totally useless, for the same reasons.

>
> Chuck, I'm sorry to say that you persist in missing the point.
>
> ``*q'' is not of any concern if we never evaluate it.
>
> This was a technical question about whether the behavior of
>
> long *q = malloc(2);
>
> (assuming sizeof(long) > 2, and assuming malloc() returns a non-null
> pointer) is defined. Your statement that it's not useful is
> absolutely correct, and absolutely irrelevant to the question. The
> standard requires the pointer returned by malloc() to be "suitably
> aligned". The question is, what does this mean if the allocated space
> isn't big enough? You seem to be trying to answer some other
> question.


I suppose it would be okay until an attempt is made to write through the
pointer, at which point undefined behaviour might be invoked.

At least this is what seems sensible to me.

<snip>

 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      02-28-2008
Old Wolf <(E-Mail Removed)> writes:
> On Feb 23, 4:33 am, Eric Sosman <(E-Mail Removed)> wrote:
>> Old Wolf wrote:
>> > Is there undefined behaviour here:

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

>>
>> > int main()
>> > {
>> > short *p = malloc( sizeof *p );
>> > long *q = (long *)p;
>> > q;

>>
>> > return 0;
>> > }

>>
>> All's well. 6.3.2.3p7 tells us:
>>
>> "A pointer to an object or incomplete type may be
>> converted to a pointer to a different object or
>> incomplete type. If the resulting pointer is not
>> correctly aligned for the pointed-to type, the
>> behavior is undefined. Otherwise, when converted
>> back again, the result shall compare equal to the
>> original pointer. [...]"

>
> Good catch. How about this case:
> long *q = malloc(2);
>
> assuming sizeof(long) > 2 ? Now the 'defence' of
> the pointer having to be able to be converted
> back to short, is no longer available.


Here's (part of) what the standard says about the pointer returned by
malloc:

The pointer returned if the allocation succeeds is suitably
aligned so that it may be assigned to a pointer to any type of
object and then used to access such an object or an array of such
objects in the space allocated (until the space is explicitly
deallocated).

(The C90 wording is the same.)

I've always assumed that this meant that the result of malloc() can be
assigned to an object of any pointer-to-object type. For example,
suppose that type int is 4 bytes and requires strict alignment, and
assigning a misaligned void* to an int* causes a trap (even if it's
never dereferenced). Then ``int *ptr = malloc(1);'' will never cause
a trap, even though attempting to evaluate *ptr would invoke undefined
behavior.

I still think that's the intent, but look at what follows the "may be
assigned" stuff:

... and then used to access such an object or an array of such
objects in the space allocated ...

Clearly, given ``int *ptr = malloc(1);'', you *can't* use the result
to "access such an object". (One could argue that there's a
zero-length array, but C really doesn't support zero-sized objects, so
I don't think that argument holds up.)

I suspect that the author(s) of that section just didn't think about
the possibility of assigning the result of malloc to a pointer to a
type bigger than the allocated object, or perhaps didn't want to
expend the effort to craft the wording necessary to describe a case
that really isn't useful.

It's not immediately obvious whether the behavior is defined or not,
but IMHO it would be no great loss if it were undefined.

--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Flash Gordon
Guest
Posts: n/a
 
      03-01-2008
Keith Thompson wrote, On 28/02/08 07:18:

<snip question of whether pointer returned by malloc must be suitably
alligned for data which would not fit in the space>

> Clearly, given ``int *ptr = malloc(1);'', you *can't* use the result
> to "access such an object". (One could argue that there's a
> zero-length array, but C really doesn't support zero-sized objects, so
> I don't think that argument holds up.)


In terms of malloc it does since malloc(0) is allowed to return a
non-null pointer and at the very least that is a pointer to a zero
length array of (signed/unsigned/plain) char and it could reasonably be
considered to be a pointer to a 0 length array of any type.

> I suspect that the author(s) of that section just didn't think about
> the possibility of assigning the result of malloc to a pointer to a
> type bigger than the allocated object, or perhaps didn't want to
> expend the effort to craft the wording necessary to describe a case
> that really isn't useful.


I agree that one of those is quite likely.

> It's not immediately obvious whether the behavior is defined or not,
> but IMHO it would be no great loss if it were undefined.


For the degenerate case of malloc(0) it could be an inconvenience on
occasion. Suppose you have some code of the form...

ptr = malloc(count * sizeof *ptr);
for (i=0; i<count; i++) {
/* do stuff using ptr */
}
free(ptr);

If you cannot safely assign the result returned by malloc because you
could not legally dereference it then you have to special case for
count==0, if you can then it will just work by magic with no need for a
special case.
--
Flash Gordon
 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      03-01-2008
Flash Gordon wrote:
>

.... snip ...
>
> For the degenerate case of malloc(0) it could be an inconvenience
> on occasion. Suppose you have some code of the form...
>
> ptr = malloc(count * sizeof *ptr);
> for (i=0; i<count; i++) {
> /* do stuff using ptr */
> }
> free(ptr);
>
> If you cannot safely assign the result returned by malloc because
> you could not legally dereference it then you have to special
> case for count==0, if you can then it will just work by magic
> with no need for a special case.


Covered in the standard. From N869:

7.20.3 Memory management functions

[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated). Each such allocation shall yield a pointer to
an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the
allocated space. If the space cannot be allocated, a null
pointer is returned. If the size of the space requested is <
zero, the behavior is implementation-defined: either a null <
pointer is returned, or the behavior is as if the size were <
some nonzero value, except that the returned pointer shall <
not be used to access an object. The value of a pointer <
that refers to freed space is indeterminate.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      03-01-2008
Flash Gordon <(E-Mail Removed)> writes:
> Keith Thompson wrote, On 28/02/08 07:18:
> <snip question of whether pointer returned by malloc must be suitably
> alligned for data which would not fit in the space>
>
>> Clearly, given ``int *ptr = malloc(1);'', you *can't* use the result
>> to "access such an object". (One could argue that there's a
>> zero-length array, but C really doesn't support zero-sized objects, so
>> I don't think that argument holds up.)

>
> In terms of malloc it does since malloc(0) is allowed to return a
> non-null pointer and at the very least that is a pointer to a zero
> length array of (signed/unsigned/plain) char and it could reasonably
> be considered to be a pointer to a 0 length array of any type.


If malloc(0) returns a non-null pointer, then "the behavior is as if
the size were some nonzero value, except that the returned pointer
shall not be used to access an object" (C99 7.20.3p1). It may well be
that that behavior matches the behavior that a pointer to the
(nonexistent) first element of a zero-length array *would* have if the
standard actually talked about zero-length arrays, but it wouldn't be
easy to prove it.

And, of course, an implementation can choose to always return a null
pointer for malloc(0).

The authors of the standard *could* have defined a non-null value
returned by malloc(0) in terms of a zero-length array. Either it
didn't occur to them, or they specifically chose not to, likely
because they didn't want to open that particular can of worms.

I'd be pleased if the standard did treat zero-length arrays, and
perhaps zero-sized structs, consistently. But note that zero-length
arrays, and other zero-sized objects, could introduce all sorts of
confusion. Distinct objects, or array elements, or struct members,
could have the same address; distinct struct members could have the
same offset.

[...]

>> It's not immediately obvious whether the behavior is defined or not,
>> but IMHO it would be no great loss if it were undefined.

>
> For the degenerate case of malloc(0) it could be an inconvenience on
> occasion. Suppose you have some code of the form...
>
> ptr = malloc(count * sizeof *ptr);
> for (i=0; i<count; i++) {
> /* do stuff using ptr */
> }
> free(ptr);
>
> If you cannot safely assign the result returned by malloc because you
> could not legally dereference it then you have to special case for
> count==0, if you can then it will just work by magic with no need for
> a special case.


If you can't assign the result of malloc(), it's not "because you
could not legally dereference it"; after all, it's clear that you can
assign either a null pointer or a pointer just past the end of an
array, even though you can't dereference either of those.

Again, quoting C99 7.20.3p1:

The pointer returned if the allocation succeeds is suitably
aligned so that it may be assigned to a pointer to any type of
object and then used to access such an object or an array of such
objects in the space allocated (until the space is explicitly
deallocated).

I think it's *intended* that (assuming sizeof(int) > 1):

int *ptr;
*ptr = malloc(sizeof(int)/2);

has defined behavior. Assuming malloc() succeeds, the result is a
pointer that's properly aligned for type int, but that points to a
space that's too small to hold an int.

The assignment certainly won't blow up due to misalignment. But the
the standard (a) incorrectly assumes that *dereferencing* a properly
aligned pointer is ok (it's clearly not if the space it points to is
properly aigned but too small) and thereby (b) fails to guarantee that
just *assigning* such a pointer is ok.

To clarify point (a), the standard says the pointer "is suitably
aligned so that it may be ... used to access such an object". This
implies that suitable alignment is enough to guarantee this; it isn't.

It's easy to imagine an implementation in which assigning a pointer
that's properly aligned, but that doesn't point to a sufficiently
large space, can cause a trap. The standard doesn't do enough to
forbid such a trap in this particular case (though it might be a
useful check in some other cases).

Suggested wording:

The pointer returned if the allocation succeeds is suitably
aligned so that it may be assigned to a pointer to any type of
object. If the space allocated is sufficiently large, the pointer
may then be used to access such an object or an array of such
objects in the space allocated (until the space is explicitly
deallocated).

(Perhaps the authors thought that the "sufficiently large" requirement
was so obvious that it didn't need to be stated.)

Note that in the above, including both quotes from the standard and my
own wording, the term "pointer" refers to a pointer *value*, not a
pointer object, and the alignment of a pointer refers to the alignment
of the object it points to, not to the alignment of a pointer object.

--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
christian.bau
Guest
Posts: n/a
 
      03-01-2008
On Feb 22, 2:37*pm, Old Wolf <(E-Mail Removed)> wrote:
> Is there undefined behaviour here:
>
> #include <stdlib.h>
>
> int main()
> {
> * short *p = malloc( sizeof *p );
> * long *q = (long *)p;
> * q;
>
> * return 0;
>
> }
>
> Rationale being that evaluating q causes undefined
> behaviour because q is neither null, nor pointing to storage
> suitable for an object of type *q.
>
> Assuming so; then is it undefined before the `q;' line, or
> is the code valid and q indeterminate?


Remember that in C99 an implementation can use two possible strategies
to implement malloc (0): Either the implementation allows returns a
null pointer, _or_ the implementation tries to return malloc (1), and
only returns a null pointer in the rare case that malloc (1) fails.

So in C99, the harmless

long *p = malloc (0);

would on some implementations usually produce exactly the same
situation that you are asking about. I would assume that the behaviour
must be defined, otherwise C99 is in serious trouble.
 
Reply With Quote
 
David Thompson
Guest
Posts: n/a
 
      03-02-2008
On Fri, 22 Feb 2008 15:28:49 -0000, "Malcolm McLean"
<(E-Mail Removed)> wrote:

>
> "Old Wolf" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...


> > short *p = malloc( sizeof *p );
> > long *q = (long *)p;


> I think you've hit on an ambiguity in the standard.
> Casting from a short * to a long * is not guaranteed to work. The short may
> be improperly aligned, and so you could generate some sort of runtime error.
>
> However the return from malloc() is guaranteed to be aligned for any
> purpose. That leaves open the question of whether a too small allocation
> can be assigned to the pointer. We could say it is OK because an allocation
> of zero bytes can be assigned. However the zero allocation could fall under
> the "one past" rule, in which case we are back to allowing the behaviour to
> be undefined.


DR075 to C90 affirmed that the space allocated (and pointer returned)
by malloc and friends must be aligned for _any_ object type, even if
it's not big enough to actually store such an object. The wording to
which this applied did not change in C99 or AFAICS the TCs thereto.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
Reply With Quote
 
David Thompson
Guest
Posts: n/a
 
      03-10-2008
On Sat, 01 Mar 2008 12:55:44 -0800, Keith Thompson <(E-Mail Removed)>
wrote:
<snip>
> I think it's *intended* that (assuming sizeof(int) > 1):
>
> int *ptr;
> *ptr = malloc(sizeof(int)/2);
>

Nit: I'm certain you didn't mean the star on the second line.

> has defined behavior. Assuming malloc() succeeds, the result is a
> pointer that's properly aligned for type int, but that points to a
> space that's too small to hold an int.
>

<snip>
- formerly david.thompson1 || achar(64) || worldnet.att.net
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      03-10-2008
David Thompson <(E-Mail Removed)> writes:
> On Sat, 01 Mar 2008 12:55:44 -0800, Keith Thompson <(E-Mail Removed)>
> wrote:
> <snip>
>> I think it's *intended* that (assuming sizeof(int) > 1):
>>
>> int *ptr;
>> *ptr = malloc(sizeof(int)/2);
>>

> Nit: I'm certain you didn't mean the star on the second line.


Quite right, thanks. (I may have first written it as an initialized
declaration, then split it into an uninitialized expression and an
assignment.)

>> has defined behavior. Assuming malloc() succeeds, the result is a
>> pointer that's properly aligned for type int, but that points to a
>> space that's too small to hold an int.


--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
FAQ 5.24 All I want to do is append a small amount of text to the end of a file. Do I still have to use locking? PerlFAQ Server Perl Misc 0 03-31-2011 04:00 AM
FAQ 5.24 All I want to do is append a small amount of text to the end of a file. Do I still have to use locking? PerlFAQ Server Perl Misc 0 02-01-2011 05:00 PM
On eating a small amount of crow spinoza1111 C Programming 0 11-16-2009 11:57 AM
OutOf Memory exception under Eclipse when using relatively small amount of heap lennyw@comcast.net Java 2 05-24-2006 08:13 PM
DVD Data only writes a small amount, and then freezes. xx75vulcan@juno.com DVD Video 0 03-17-2006 03:54 AM



Advertisments