Pointer to small amount of storage

Discussion in 'C Programming' started by Old Wolf, Feb 22, 2008.

  1. Old Wolf

    Old Wolf Guest

    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?
     
    Old Wolf, Feb 22, 2008
    #1
    1. Advertising

  2. Old Wolf

    Guest

    On Feb 22, 4:37 pm, 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;
    >
    > }
    >
    >
    > Assuming so; then is it undefined before the `q;' line, or
    > is the code valid and q indeterminate?


    No, q becomes a dangling pointer (*IF* malloc does not return NULL)
    after the assignment.
     
    , Feb 22, 2008
    #2
    1. Advertising

  3. "Old Wolf" <> wrote in message
    news:...
    > 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?
    >

    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.

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
     
    Malcolm McLean, Feb 22, 2008
    #3
  4. Old Wolf

    Eric Sosman Guest

    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;
    > }
    >
    > 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?


    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. [...]"

    Since the value returned by malloc() is either NULL (in which
    case the conversions certainly work) or correctly aligned for
    any possible data type (7.20.3p1), the "otherwise" holds. If
    `long *q = (long*)p;' were followed by `short *r = (short*)q;',
    we would therefore have `r == p'. The requirement for `r == p'
    could not hold if undefined behavior had occurred somewhere along
    the way; therefore, there's no U.B.

    Also, the evaluation `q;' produces no U.B. The fact that
    a pointer is not dereferenceable does not imply that the pointer
    value is indeterminate; the values NULL and "one past the end"
    are examples of perfectly good non-dereferenceable pointers.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Feb 22, 2008
    #4
  5. Old Wolf

    CBFalconer Guest

    Malcolm McLean wrote:
    >

    .... snip ...
    >
    > 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.


    No. The NULL, if returned from a zero allocation, is already one
    past the assigned storage. It cannot be dereferenced.

    The simplest method is not to allow a zero allocation to be made.
    If you have access to the system code, and it does this, change it
    to read:

    void *malloc(size_t sz) {

    if (!sz) sz++;
    ... the rest of the code ...
    }

    otherwise interpose something to do the same.

    --
    [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
     
    CBFalconer, Feb 22, 2008
    #5
  6. "CBFalconer" <> wrote in message
    news:...
    > Malcolm McLean wrote:
    >>

    > ... snip ...
    >>
    >> 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.

    >
    > No. The NULL, if returned from a zero allocation, is already one
    > past the assigned storage. It cannot be dereferenced.
    >

    It's one past the last element of a zero-element array. Arguably.

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
     
    Malcolm McLean, Feb 22, 2008
    #6
  7. Old Wolf

    Old Wolf Guest

    On Feb 23, 4:33 am, Eric Sosman <> 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.
     
    Old Wolf, Feb 23, 2008
    #7
  8. Old Wolf

    Eric Sosman Guest

    Old Wolf wrote:
    > On Feb 23, 4:33 am, Eric Sosman <> 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.


    But it can still be converted back to void* and must
    then compare equal to the value of malloc():

    void *v = malloc(2);
    long *q = v;
    assert ((void*)q == v);

    .... so the argument still holds. Or so it seems to me.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Feb 23, 2008
    #8
  9. Old Wolf

    CBFalconer Guest

    Old Wolf wrote:
    >

    .... snip ...
    >
    > 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.

    --
    [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
     
    CBFalconer, Feb 24, 2008
    #9
  10. On Sat, 23 Feb 2008 19:56:44 -0500, CBFalconer wrote:
    > Old Wolf wrote:
    >>

    > ... snip ...
    >>
    >> 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.


    That's the point. And the assignment's fine, since malloc's result is
    properly aligned.
     
    Harald van Dijk, Feb 24, 2008
    #10
  11. Old Wolf

    Flash Gordon Guest

    CBFalconer wrote, On 24/02/08 00:56:
    > Old Wolf wrote:
    > ... snip ...
    >> 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.


    Which was the point of the value selected and the stated assumption.

    > Replace the '2' with "sizeof *q" (sans quotes) and all is well.


    I somehow suspect that Old Wolf knows that.
    --
    Flash Gordon
     
    Flash Gordon, Feb 24, 2008
    #11
  12. Old Wolf

    CBFalconer Guest

    Harald van D?k wrote:
    > CBFalconer wrote:
    >> Old Wolf wrote:
    >>>

    >> ... snip ...
    >>>
    >>> 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.

    >
    > That's the point. And the assignment's fine, since malloc's
    > result is properly aligned.


    I see no point. And the assignment is NOT fine, since it writes
    into memory it doesn't own.

    --
    [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
     
    CBFalconer, Feb 24, 2008
    #12
  13. On Sun, 24 Feb 2008 09:24:15 -0500, CBFalconer wrote:
    >>> Old Wolf wrote:
    >>>> long *q = malloc(2);

    >
    > And the assignment is NOT fine, since it writes into
    > memory it doesn't own.


    The initialisation (I mistakenly called it assignment) does not write to
    anything except q. *q is not accessed at all.
     
    Harald van Dijk, Feb 24, 2008
    #13
  14. In article <>,
    CBFalconer <> 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*.

    Bear in mind that long *q = malloc(0) is legal.

    -- Richard
    --
    :wq
     
    Richard Tobin, Feb 24, 2008
    #14
  15. Old Wolf

    Kaz Kylheku Guest

    On Feb 22, 7:28 am, "Malcolm McLean" <> wrote:
    > 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.


    However, I don't think that a malloc of, say, four bytes, is required
    to have a stricter alignment than four bytes. No addressable object in
    C has a stricter alignment requirement than its own size.

    A malloced block of four bytes clearly cannot be used for any purpose
    whatsoever, but only for those purposes which can be satisified by a
    four byte block. Why should it be aligned for purposes to which it is
    not suited?
     
    Kaz Kylheku, Feb 27, 2008
    #15
  16. Old Wolf

    Eric Sosman Guest

    Kaz Kylheku wrote:
    > On Feb 22, 7:28 am, "Malcolm McLean" <> wrote:
    >> 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.

    >
    > However, I don't think that a malloc of, say, four bytes, is required
    > to have a stricter alignment than four bytes. No addressable object in
    > C has a stricter alignment requirement than its own size.


    This was debated donkey's years ago in a slightly different
    guise: Could calloc(64,2) return memory that satisfied a two-byte
    alignment but nothing stricter? After a good deal of debate, the
    consensus answer was that Standard's "is suitably aligned so that
    it may be assigned to a pointer of any type" does not imply that
    the resulting pointer can be dereferenced. The resulting pointer
    could, for example, be compared for equality with a different (and
    "proper") pointer of the same type, and the comparison would have
    to work; the [x]alloc() result could not be "damaged" by assignment
    to any pointer type whatsoever.

    > A malloced block of four bytes clearly cannot be used for any purpose
    > whatsoever, but only for those purposes which can be satisified by a
    > four byte block. Why should it be aligned for purposes to which it is
    > not suited?


    "Because the Standard says so." It's a little bit like the
    obstreperous child's "Why do I have to brush my teeth? I don't
    want to!" being answered by "Because I'm Your Mother, So Do It."

    --
    Eric Sosman
    lid
     
    Eric Sosman, Feb 27, 2008
    #16
  17. In article <>,
    Eric Sosman <> wrote:

    >> A malloced block of four bytes clearly cannot be used for any purpose
    >> whatsoever, but only for those purposes which can be satisified by a
    >> four byte block. Why should it be aligned for purposes to which it is
    >> not suited?


    >"Because the Standard says so."


    But it's often been suggested that the as-if rule applies here.

    If the only effect of misalignment is to prevent you dereferencing,
    and it's not big enough to hold a type whose dereferencing would
    fail, then you can't tell the difference.

    On the other hand, if misalignment causes a trap when you load
    the value into a register, you might well be able to.

    -- Richard
    --
    :wq
     
    Richard Tobin, Feb 27, 2008
    #17
  18. Old Wolf

    Eric Sosman Guest

    Richard Tobin wrote:
    > In article <>,
    > Eric Sosman <> wrote:
    >
    >>> A malloced block of four bytes clearly cannot be used for any purpose
    >>> whatsoever, but only for those purposes which can be satisified by a
    >>> four byte block. Why should it be aligned for purposes to which it is
    >>> not suited?

    >
    >> "Because the Standard says so."

    >
    > But it's often been suggested that the as-if rule applies here.
    >
    > If the only effect of misalignment is to prevent you dereferencing,
    > and it's not big enough to hold a type whose dereferencing would
    > fail, then you can't tell the difference.
    >
    > On the other hand, if misalignment causes a trap when you load
    > the value into a register, you might well be able to.


    Right. So on a machine where pointers to different data
    types "smell the same" -- are losslessly interconvertible and
    so on -- [x]alloc() can get away with murder. But if the
    machine uses different representations for T1* and T2* such
    that conversion from either to the other loses information,
    [x]alloc() must play by the book.

    In the case at hand, where sizeof(long) > 2 by assumption,

    long *ptr = malloc(2);

    .... must not lose information: free(ptr) has to work. So if
    malloc() is playing games with sizes, it must have knowledge
    that its un-aligned result behaves no differently than would
    an aligned result, so long as it's not dereferenced.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Feb 27, 2008
    #18
  19. Old Wolf

    CBFalconer Guest

    Richard Tobin wrote:
    > CBFalconer <> 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.

    --
    [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
     
    CBFalconer, Feb 27, 2008
    #19
  20. CBFalconer <> writes:
    > Richard Tobin wrote:
    >> CBFalconer <> 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'll probably post some thoughts on the actual original question
    later.

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Feb 27, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    8,795
  2. sarathy
    Replies:
    2
    Views:
    694
    sarathy
    Jul 17, 2006
  3. spinoza1111

    On eating a small amount of crow

    spinoza1111, Nov 16, 2009, in forum: C Programming
    Replies:
    0
    Views:
    350
    spinoza1111
    Nov 16, 2009
  4. PerlFAQ Server
    Replies:
    0
    Views:
    140
    PerlFAQ Server
    Feb 1, 2011
  5. PerlFAQ Server
    Replies:
    0
    Views:
    127
    PerlFAQ Server
    Mar 31, 2011
Loading...

Share This Page