How bad it is to dereference a null pointer

Discussion in 'C++' started by Armen Tsirunyan, Sep 30, 2010.

  1. Hi all,
    Consider the following code:
    <CODE>
    #include <iostream>

    struct X
    {
    void f()
    {
    std::cout << "f() called" << std::endl;
    }
    };

    int main()
    {
    X* p = 0;
    p->f();
    X x = *p;
    x.f();
    }
    </CODE>

    it works( on MSVC9.0), and prints f() called two times. Well,
    logically it should, because in X::f() 'this' is not used and
    therefore theoretically this could be null; The copy construction also
    is logical to succeed because its implicit definition is empty. On the
    other hand, if X had a member the copy construction X x = *p woud
    fail, because the "this" of the *p would be needed.

    Now, my question is,
    1. does the standard (the current one) say anything about
    dereferencing null pointers?
    2. Does the above code result in undefined behaviour?
    Armen Tsirunyan, Sep 30, 2010
    #1
    1. Advertising

  2. * Armen Tsirunyan, on 30.09.2010 17:03:
    > Hi all,
    > Consider the following code:
    > <CODE>
    > #include<iostream>
    >
    > struct X
    > {
    > void f()
    > {
    > std::cout<< "f() called"<< std::endl;
    > }
    > };
    >
    > int main()
    > {
    > X* p = 0;
    > p->f();
    > X x = *p;
    > x.f();
    > }
    > </CODE>
    >
    > it works( on MSVC9.0), and prints f() called two times. Well,
    > logically it should, because in X::f() 'this' is not used and
    > therefore theoretically this could be null; The copy construction also
    > is logical to succeed because its implicit definition is empty. On the
    > other hand, if X had a member the copy construction X x = *p woud
    > fail, because the "this" of the *p would be needed.
    >
    > Now, my question is,
    > 1. does the standard (the current one) say anything about
    > dereferencing null pointers?


    It mentions in non-normative text (as I recall) that it's UB to dereference a
    nullpointer, in general. That's somewhere right at the start, I think in the
    definitions of terms. However, even if there's no normative text that says that
    outright, absence of such text is just due to being an unnecessary clarification.

    The standard makes a special exception for a typeid expression, where you can
    safely dereference a nullpointer.

    That explicit exception wouldn't be necessary if dereferencing nullpointers
    wasn't UB in general.


    > 2. Does the above code result in undefined behaviour?


    In abundance.


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 30, 2010
    #2
    1. Advertising

  3. On Sep 30, 8:13 pm, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > wrote:
    > * Armen Tsirunyan, on 30.09.2010 17:03:
    >
    >
    >
    >
    >
    > > Hi all,
    > > Consider the following code:
    > > <CODE>
    > > #include<iostream>

    >
    > > struct X
    > > {
    > >     void f()
    > >     {
    > >        std::cout<<  "f() called"<<  std::endl;
    > >     }
    > > };

    >
    > > int main()
    > > {
    > >     X* p = 0;
    > >     p->f();
    > >     X x = *p;
    > >     x.f();
    > > }
    > > </CODE>

    >
    > > it works( on MSVC9.0), and prints f() called two times. Well,
    > > logically it should, because in X::f() 'this' is not used and
    > > therefore theoretically this could be null; The copy construction also
    > > is logical to succeed because its implicit definition is empty. On the
    > > other hand, if X had a member the copy construction X x = *p woud
    > > fail, because the "this" of the *p would be needed.

    >
    > > Now, my question is,
    > > 1. does the standard (the current one) say anything about
    > > dereferencing null pointers?

    >
    > It mentions in non-normative text (as I recall) that it's UB to dereference a
    > nullpointer, in general. That's somewhere right at the start, I think in the
    > definitions of terms. However, even if there's no normative text that says that
    > outright, absence of such text is just due to being an unnecessary clarification.
    >
    > The standard makes a special exception for a typeid expression, where you can
    > safely dereference a nullpointer.
    >
    > That explicit exception wouldn't be necessary if dereferencing nullpointers
    > wasn't UB in general.
    >
    > > 2. Does the above code result in undefined behaviour?

    >
    > In abundance.
    >
    > Cheers & hth.,
    >
    > - Alf
    >
    > --
    > blog at <url:http://alfps.wordpress.com>


    Yeah, the typeid would is an exception but it says it throws, not that
    it is ok. It's just defined behavior of throwing an exception. But in
    sizeof, I guess it would be defined and throw nothing, right?
    Anyway, what's wrong with allowing to call any member function that
    doesn't use 'this' with a null pointer?
    More formally, I found this
    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
    Is this proposal included in C++0x?
    Thanks,
    Armen.
    Armen Tsirunyan, Sep 30, 2010
    #3
  4. Armen Tsirunyan wrote:

    > On Sep 30, 8:13 pm, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > > wrote:
    >> * Armen Tsirunyan, on 30.09.2010 17:03:
    >>
    >>
    >>
    >>
    >>
    >> > Hi all,
    >> > Consider the following code:
    >> > <CODE>
    >> > #include<iostream>

    >>
    >> > struct X
    >> > {
    >> > void f()
    >> > {
    >> > std::cout<< "f() called"<< std::endl;
    >> > }
    >> > };

    >>
    >> > int main()
    >> > {
    >> > X* p = 0;
    >> > p->f();
    >> > X x = *p;
    >> > x.f();
    >> > }
    >> > </CODE>

    >>
    >> > it works( on MSVC9.0), and prints f() called two times. Well,
    >> > logically it should, because in X::f() 'this' is not used and
    >> > therefore theoretically this could be null; The copy construction also
    >> > is logical to succeed because its implicit definition is empty. On the
    >> > other hand, if X had a member the copy construction X x = *p woud
    >> > fail, because the "this" of the *p would be needed.

    >>
    >> > Now, my question is,
    >> > 1. does the standard (the current one) say anything about
    >> > dereferencing null pointers?

    >>
    >> It mentions in non-normative text (as I recall) that it's UB to
    >> dereference a nullpointer, in general. That's somewhere right at the
    >> start, I think in the definitions of terms. However, even if there's no
    >> normative text that says that outright, absence of such text is just due
    >> to being an unnecessary clarification.
    >>
    >> The standard makes a special exception for a typeid expression, where you
    >> can safely dereference a nullpointer.
    >>
    >> That explicit exception wouldn't be necessary if dereferencing
    >> nullpointers wasn't UB in general.
    >>
    >> > 2. Does the above code result in undefined behaviour?

    >>
    >> In abundance.
    >>
    >> Cheers & hth.,
    >>
    >> - Alf
    >>
    >> --
    >> blog at <url:http://alfps.wordpress.com>

    >
    > Yeah, the typeid would is an exception but it says it throws, not that
    > it is ok. It's just defined behavior of throwing an exception. But in
    > sizeof, I guess it would be defined and throw nothing, right?
    >


    In "sizeof", things are not evaluated. If you don't evaluate an expression,
    you will never figure out that you dereferenced a null pointer instead of a
    pointer to an actual object (the critical point is that you need to have an
    lvalue refer to an object or function. You can only find out whether it does
    by evaluation). So yeah, it's fine to dereference a null pointer within a
    sizeof expression.
    Johannes Schaub (litb), Sep 30, 2010
    #4
  5. Armen Tsirunyan

    Goran Guest

    On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > wrote:
    > * Armen Tsirunyan, on 30.09.2010 17:03:
    >
    >
    >
    > > Hi all,
    > > Consider the following code:
    > > <CODE>
    > > #include<iostream>

    >
    > > struct X
    > > {
    > >     void f()
    > >     {
    > >        std::cout<<  "f() called"<<  std::endl;
    > >     }
    > > };

    >
    > > int main()
    > > {
    > >     X* p = 0;
    > >     p->f();
    > >     X x = *p;
    > >     x.f();
    > > }
    > > </CODE>

    >
    > > it works( on MSVC9.0), and prints f() called two times. Well,
    > > logically it should, because in X::f() 'this' is not used and
    > > therefore theoretically this could be null; The copy construction also
    > > is logical to succeed because its implicit definition is empty. On the
    > > other hand, if X had a member the copy construction X x = *p woud
    > > fail, because the "this" of the *p would be needed.

    >
    > > Now, my question is,
    > > 1. does the standard (the current one) say anything about
    > > dereferencing null pointers?

    >
    > It mentions in non-normative text (as I recall) that it's UB to dereference a
    > nullpointer, in general. That's somewhere right at the start, I think in the
    > definitions of terms. However, even if there's no normative text that says that
    > outright, absence of such text is just due to being an unnecessary clarification.


    The question then becomes whether calling a member function on a null
    object reference counts as dereferencing the object (problem being, I
    would think, that the mere absence of a * or a -> does not count as
    dereferencing it, e.g. with sizeof or offsetof).

    Goran.
    Goran, Oct 1, 2010
    #5
  6. Armen Tsirunyan

    Goran Guest

    On Sep 30, 5:03 pm, Armen Tsirunyan <> wrote:
    > Hi all,
    > Consider the following code:
    > <CODE>
    > #include <iostream>
    >
    > struct X
    > {
    >    void f()
    >    {
    >       std::cout << "f() called" << std::endl;
    >    }
    >
    > };
    >
    > int main()
    > {
    >    X* p = 0;
    >    p->f();
    >    X x = *p;
    >    x.f();}
    >
    > </CODE>
    >
    > it works( on MSVC9.0), and prints f() called two times. Well,
    > logically it should, because in X::f() 'this' is not used and
    > therefore theoretically this could be null; The copy construction also
    > is logical to succeed because its implicit definition is empty. On the
    > other hand, if X had a member the copy construction X x = *p woud
    > fail, because the "this" of the *p would be needed.


    Putting standard and theory aside, what about practice? First, if
    object's method does not touch object's data, why isn't it static, or
    even a free function? IOW, there's a design error in your code.
    Second, what if you start doing these things and then add a member to
    X? IOW, there's a maintenance error in your code.

    I am reacting because good practice is more important than theory/
    standard; only when good prectice seems to disagree with theory/
    standard there is a problem, or a place for a question. And you didn't
    obey good practice ;-)

    Goran.
    Goran, Oct 1, 2010
    #6
  7. * Goran, on 01.10.2010 06:29:
    > On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    > > wrote:
    >> * Armen Tsirunyan, on 30.09.2010 17:03:
    >>
    >>
    >>
    >>> Hi all,
    >>> Consider the following code:
    >>> <CODE>
    >>> #include<iostream>

    >>
    >>> struct X
    >>> {
    >>> void f()
    >>> {
    >>> std::cout<< "f() called"<< std::endl;
    >>> }
    >>> };

    >>
    >>> int main()
    >>> {
    >>> X* p = 0;
    >>> p->f();
    >>> X x = *p;
    >>> x.f();
    >>> }
    >>> </CODE>

    >>
    >>> it works( on MSVC9.0), and prints f() called two times. Well,
    >>> logically it should, because in X::f() 'this' is not used and
    >>> therefore theoretically this could be null; The copy construction also
    >>> is logical to succeed because its implicit definition is empty. On the
    >>> other hand, if X had a member the copy construction X x = *p woud
    >>> fail, because the "this" of the *p would be needed.

    >>
    >>> Now, my question is,
    >>> 1. does the standard (the current one) say anything about
    >>> dereferencing null pointers?

    >>
    >> It mentions in non-normative text (as I recall) that it's UB to dereference a
    >> nullpointer, in general. That's somewhere right at the start, I think in the
    >> definitions of terms. However, even if there's no normative text that says that
    >> outright, absence of such text is just due to being an unnecessary clarification.

    >
    > The question then becomes whether calling a member function on a null
    > object reference counts as dereferencing the object (problem being, I
    > would think, that the mere absence of a * or a -> does not count as
    > dereferencing it, e.g. with sizeof or offsetof).


    That does not make sense.

    There is no such thing as a "null object reference".

    There is no such thing as "dereferencing the object".

    sizeof and offsetof are not examples of "absence of a * or a ->".

    So in summary, I can't make heads or tails of what you intend to communicate here.


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Oct 1, 2010
    #7
  8. On Oct 1, 9:40 am, Goran <> wrote:
    > On Sep 30, 5:03 pm, Armen Tsirunyan <> wrote:
    >
    >
    >
    >
    >
    > > Hi all,
    > > Consider the following code:
    > > <CODE>
    > > #include <iostream>

    >
    > > struct X
    > > {
    > >    void f()
    > >    {
    > >       std::cout << "f() called" << std::endl;
    > >    }

    >
    > > };

    >
    > > int main()
    > > {
    > >    X* p = 0;
    > >    p->f();
    > >    X x = *p;
    > >    x.f();}

    >
    > > </CODE>

    >
    > > it works( on MSVC9.0), and prints f() called two times. Well,
    > > logically it should, because in X::f() 'this' is not used and
    > > therefore theoretically this could be null; The copy construction also
    > > is logical to succeed because its implicit definition is empty. On the
    > > other hand, if X had a member the copy construction X x = *p woud
    > > fail, because the "this" of the *p would be needed.

    >
    > Putting standard and theory aside, what about practice? First, if
    > object's method does not touch object's data, why isn't it static, or
    > even a free function? IOW, there's a design error in your code.
    > Second, what if you start doing these things and then add a member to
    > X? IOW, there's a maintenance error in your code.
    >
    > I am reacting because good practice is more important than theory/
    > standard; only when good prectice seems to disagree with theory/
    > standard there is a problem, or a place for a question. And you didn't
    > obey good practice ;-)
    >
    > Goran.


    This piece of code was invented by me for pure theoretical purposes,
    so don't teach me good practice here :).
    Now, has anyone even looked at the link I gave? There seems to be a
    proposal
    to add a null lvalue thing which would be a valid thing unless you
    perform
    an lvalue-to-rvalue conversion to it. So, I was wondering if this
    thing is
    in the new c++0x standard draft or not.
    Thanks,
    Armen
    Armen Tsirunyan, Oct 1, 2010
    #8
  9. Armen Tsirunyan

    Goran Guest

    On Oct 1, 9:25 am, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > wrote:
    > * Goran, on 01.10.2010 06:29:
    >
    >
    >
    > > On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    > > >  wrote:
    > >> * Armen Tsirunyan, on 30.09.2010 17:03:

    >
    > >>> Hi all,
    > >>> Consider the following code:
    > >>> <CODE>
    > >>> #include<iostream>

    >
    > >>> struct X
    > >>> {
    > >>>      void f()
    > >>>      {
    > >>>         std::cout<<    "f() called"<<    std::endl;
    > >>>      }
    > >>> };

    >
    > >>> int main()
    > >>> {
    > >>>      X* p = 0;
    > >>>      p->f();
    > >>>      X x = *p;
    > >>>      x.f();
    > >>> }
    > >>> </CODE>

    >
    > >>> it works( on MSVC9.0), and prints f() called two times. Well,
    > >>> logically it should, because in X::f() 'this' is not used and
    > >>> therefore theoretically this could be null; The copy construction also
    > >>> is logical to succeed because its implicit definition is empty. On the
    > >>> other hand, if X had a member the copy construction X x = *p woud
    > >>> fail, because the "this" of the *p would be needed.

    >
    > >>> Now, my question is,
    > >>> 1. does the standard (the current one) say anything about
    > >>> dereferencing null pointers?

    >
    > >> It mentions in non-normative text (as I recall) that it's UB to dereference a
    > >> nullpointer, in general. That's somewhere right at the start, I think in the
    > >> definitions of terms. However, even if there's no normative text that says that
    > >> outright, absence of such text is just due to being an unnecessary clarification.

    >
    > > The question then becomes whether calling a member function on a null
    > > object reference counts as dereferencing the object (problem being, I
    > > would think, that the mere absence of a * or a ->  does not count as
    > > dereferencing it, e.g. with sizeof or offsetof).

    >
    > That does not make sense.
    >
    > There is no such thing as a "null object reference".


    Heh, true. I was thinking something along the lines of:

    TYPE& r = *(TYPE*)0;

    I used word "reference" because there's no "calling a member function
    on a pointer". There's calling it on an object that pointer points to,
    which I poorly named object reference (a __null__ one, since it's a
    null pointer).

    > There is no such thing as "dereferencing the object".


    Whoops, that's true, my bad. Should have been "dereferencing the
    pointer"

    > sizeof and offsetof are not examples of "absence of a * or a ->".


    I was thinking e.g.:

    TYPE* p=0;
    sizeof(*p);
    offsetof(p->field);

    >sizeof and offsetof are not examples of "absence of a * or a ->".


    My bad again, that should have been "presence", not absence.

    OK, so, to correct myself...

    The question then becomes whether calling a member function on a null
    object __pointer__ counts as dereferencing the __pointer__ (problem
    being, I would think, that the mere __presence__ of a * or a -> does
    not count as dereferencing it, e.g. with sizeof or offsetof).

    Sorry about the confusion.

    Goran.
    Goran, Oct 1, 2010
    #9
  10. Armen Tsirunyan

    Goran Guest

    On Oct 1, 10:14 am, Armen Tsirunyan <> wrote:
    > On Oct 1, 9:40 am, Goran <> wrote:
    >
    >
    >
    > > On Sep 30, 5:03 pm, Armen Tsirunyan <> wrote:

    >
    > > > Hi all,
    > > > Consider the following code:
    > > > <CODE>
    > > > #include <iostream>

    >
    > > > struct X
    > > > {
    > > >    void f()
    > > >    {
    > > >       std::cout << "f() called" << std::endl;
    > > >    }

    >
    > > > };

    >
    > > > int main()
    > > > {
    > > >    X* p = 0;
    > > >    p->f();
    > > >    X x = *p;
    > > >    x.f();}

    >
    > > > </CODE>

    >
    > > > it works( on MSVC9.0), and prints f() called two times. Well,
    > > > logically it should, because in X::f() 'this' is not used and
    > > > therefore theoretically this could be null; The copy construction also
    > > > is logical to succeed because its implicit definition is empty. On the
    > > > other hand, if X had a member the copy construction X x = *p woud
    > > > fail, because the "this" of the *p would be needed.

    >
    > > Putting standard and theory aside, what about practice? First, if
    > > object's method does not touch object's data, why isn't it static, or
    > > even a free function? IOW, there's a design error in your code.
    > > Second, what if you start doing these things and then add a member to
    > > X? IOW, there's a maintenance error in your code.

    >
    > > I am reacting because good practice is more important than theory/
    > > standard; only when good prectice seems to disagree with theory/
    > > standard there is a problem, or a place for a question. And you didn't
    > > obey good practice ;-)

    >
    > > Goran.

    >
    > This piece of code was invented by me for pure theoretical purposes,
    > so don't teach me good practice here :).


    Sorry, that really wasn't my intention. I was rather thinking "even if
    this works __and__ is legal, it should not be done; why even bother
    asking"?

    Hence the post.

    Goran.
    Goran, Oct 1, 2010
    #10
  11. On Oct 1, 3:59 pm, Goran <> wrote:
    > On Oct 1, 9:25 am, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    >
    >
    >
    >
    >
    > > wrote:
    > > * Goran, on 01.10.2010 06:29:

    >
    > > > On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    > > > >  wrote:
    > > >> * Armen Tsirunyan, on 30.09.2010 17:03:

    >
    > > >>> Hi all,
    > > >>> Consider the following code:
    > > >>> <CODE>
    > > >>> #include<iostream>

    >
    > > >>> struct X
    > > >>> {
    > > >>>      void f()
    > > >>>      {
    > > >>>         std::cout<<    "f() called"<<    std::endl;
    > > >>>      }
    > > >>> };

    >
    > > >>> int main()
    > > >>> {
    > > >>>      X* p = 0;
    > > >>>      p->f();
    > > >>>      X x = *p;
    > > >>>      x.f();
    > > >>> }
    > > >>> </CODE>

    >
    > > >>> it works( on MSVC9.0), and prints f() called two times. Well,
    > > >>> logically it should, because in X::f() 'this' is not used and
    > > >>> therefore theoretically this could be null; The copy construction also
    > > >>> is logical to succeed because its implicit definition is empty. On the
    > > >>> other hand, if X had a member the copy construction X x = *p woud
    > > >>> fail, because the "this" of the *p would be needed.

    >
    > > >>> Now, my question is,
    > > >>> 1. does the standard (the current one) say anything about
    > > >>> dereferencing null pointers?

    >
    > > >> It mentions in non-normative text (as I recall) that it's UB to dereference a
    > > >> nullpointer, in general. That's somewhere right at the start, I think in the
    > > >> definitions of terms. However, even if there's no normative text that says that
    > > >> outright, absence of such text is just due to being an unnecessary clarification.

    >
    > > > The question then becomes whether calling a member function on a null
    > > > object reference counts as dereferencing the object (problem being, I
    > > > would think, that the mere absence of a * or a ->  does not count as
    > > > dereferencing it, e.g. with sizeof or offsetof).

    >
    > > That does not make sense.

    >
    > > There is no such thing as a "null object reference".

    >
    > Heh, true. I was thinking something along the lines of:
    >
    > TYPE& r = *(TYPE*)0;
    >
    > I used word "reference" because there's no "calling a member function
    > on a pointer". There's calling it on an object that pointer points to,
    > which I poorly named object reference (a __null__ one, since it's a
    > null pointer).
    >
    > > There is no such thing as "dereferencing the object".

    >
    > Whoops, that's true, my bad. Should have been "dereferencing the
    > pointer"
    >
    > > sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > I was thinking e.g.:
    >
    > TYPE* p=0;
    > sizeof(*p);
    > offsetof(p->field);
    >
    > >sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > My bad again, that should have been "presence", not absence.
    >
    > OK, so, to correct myself...
    >
    > The question then becomes whether calling a member function on a null
    > object __pointer__ counts as dereferencing the __pointer__ (problem
    > being, I would think, that the mere __presence__ of a * or a ->  does
    > not count as dereferencing it, e.g. with sizeof or offsetof).
    >
    > Sorry about the confusion.
    >
    > Goran.


    You have a good point there. Calling a member function on via a
    pointer which is a null pointer is not dereferencing, is it?
    Well, naturally it __involves__ dereferencing if the member function
    cannot be made static, but what if it can? Is the wording in the
    standard clear with this respect?
    Armen Tsirunyan, Oct 1, 2010
    #11
  12. Armen Tsirunyan

    Goran Guest

    On Oct 1, 1:49 pm, Armen Tsirunyan <> wrote:
    > On Oct 1, 3:59 pm, Goran <> wrote:
    >
    >
    >
    > > On Oct 1, 9:25 am, "Alf P. Steinbach /Usenet" <alf.p.steinbach

    >
    > > > wrote:
    > > > * Goran, on 01.10.2010 06:29:

    >
    > > > > On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    > > > > >  wrote:
    > > > >> * Armen Tsirunyan, on 30.09.2010 17:03:

    >
    > > > >>> Hi all,
    > > > >>> Consider the following code:
    > > > >>> <CODE>
    > > > >>> #include<iostream>

    >
    > > > >>> struct X
    > > > >>> {
    > > > >>>      void f()
    > > > >>>      {
    > > > >>>         std::cout<<    "f() called"<<    std::endl;
    > > > >>>      }
    > > > >>> };

    >
    > > > >>> int main()
    > > > >>> {
    > > > >>>      X* p = 0;
    > > > >>>      p->f();
    > > > >>>      X x = *p;
    > > > >>>      x.f();
    > > > >>> }
    > > > >>> </CODE>

    >
    > > > >>> it works( on MSVC9.0), and prints f() called two times. Well,
    > > > >>> logically it should, because in X::f() 'this' is not used and
    > > > >>> therefore theoretically this could be null; The copy construction also
    > > > >>> is logical to succeed because its implicit definition is empty. On the
    > > > >>> other hand, if X had a member the copy construction X x = *p woud
    > > > >>> fail, because the "this" of the *p would be needed.

    >
    > > > >>> Now, my question is,
    > > > >>> 1. does the standard (the current one) say anything about
    > > > >>> dereferencing null pointers?

    >
    > > > >> It mentions in non-normative text (as I recall) that it's UB to dereference a
    > > > >> nullpointer, in general. That's somewhere right at the start, I think in the
    > > > >> definitions of terms. However, even if there's no normative text that says that
    > > > >> outright, absence of such text is just due to being an unnecessary clarification.

    >
    > > > > The question then becomes whether calling a member function on a null
    > > > > object reference counts as dereferencing the object (problem being, I
    > > > > would think, that the mere absence of a * or a ->  does not count as
    > > > > dereferencing it, e.g. with sizeof or offsetof).

    >
    > > > That does not make sense.

    >
    > > > There is no such thing as a "null object reference".

    >
    > > Heh, true. I was thinking something along the lines of:

    >
    > > TYPE& r = *(TYPE*)0;

    >
    > > I used word "reference" because there's no "calling a member function
    > > on a pointer". There's calling it on an object that pointer points to,
    > > which I poorly named object reference (a __null__ one, since it's a
    > > null pointer).

    >
    > > > There is no such thing as "dereferencing the object".

    >
    > > Whoops, that's true, my bad. Should have been "dereferencing the
    > > pointer"

    >
    > > > sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > > I was thinking e.g.:

    >
    > > TYPE* p=0;
    > > sizeof(*p);
    > > offsetof(p->field);

    >
    > > >sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > > My bad again, that should have been "presence", not absence.

    >
    > > OK, so, to correct myself...

    >
    > > The question then becomes whether calling a member function on a null
    > > object __pointer__ counts as dereferencing the __pointer__ (problem
    > > being, I would think, that the mere __presence__ of a * or a ->  does
    > > not count as dereferencing it, e.g. with sizeof or offsetof).

    >
    > > Sorry about the confusion.

    >
    > > Goran.

    >
    > You have a good point there. Calling a member function on via a
    > pointer which is a null pointer is not dereferencing, is it?
    > Well, naturally it __involves__ dereferencing if the member function
    > cannot be made static, but what if it can? Is the wording in the
    > standard clear with this respect?


    No idea about any of your questions. By looking around the word
    "dereference" in 03 draft, I didn't find anything of interest. But
    then, I am not much of a standard-dweller.

    Goran.
    Goran, Oct 1, 2010
    #12
  13. Armen Tsirunyan

    JaredGrubb Guest

    On Oct 1, 6:59 am, Goran <> wrote:
    >
    > Heh, true. I was thinking something along the lines of:
    >
    > TYPE& r = *(TYPE*)0;
    >
    > I used word "reference" because there's no "calling a member function
    > on a pointer". There's calling it on an object that pointer points to,
    > which I poorly named object reference (a __null__ one, since it's a
    > null pointer).
    >
    > > There is no such thing as "dereferencing the object".

    >
    > Whoops, that's true, my bad. Should have been "dereferencing the
    > pointer"
    >
    > > sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > I was thinking e.g.:
    >
    > TYPE* p=0;
    > sizeof(*p);
    > offsetof(p->field);
    >
    > >sizeof and offsetof are not examples of "absence of a * or a ->".

    >
    > My bad again, that should have been "presence", not absence.
    >
    > OK, so, to correct myself...
    >
    > The question then becomes whether calling a member function on a null
    > object __pointer__ counts as dereferencing the __pointer__ (problem
    > being, I would think, that the mere __presence__ of a * or a ->  does
    > not count as dereferencing it, e.g. with sizeof or offsetof).
    >
    > Sorry about the confusion.


    First, "0" is a valid memory address and is not treated differently by
    the compiler. For example, here's a write-up on how you can make Linux
    create an object at address 0, and then you can write to it and call
    it and whatever else you want to do.

    http://blog.ksplice.com/2010/03/null-pointers-part-i/

    There is nothing special about "0"; most OS/architectures/runtime
    environments will not allocate objects at 0 because it's incredibly
    "helpful" to have our programs crash when they pretend to have objects
    at 0 -- in almost every case, this is a programming error and bad
    things are going to happen.

    Second, sizeof and offsetof do not dereference anything; they compute
    values from *types*. So if p points to a type P, then sizeof(*p) and
    sizeof(P) are equivalent; further if p2 is another pointer of type P,
    sizeof(*p2) has the same value as the other two. That value is
    computed at compile-time by the compiler and the constant value is
    poked into the binary code itself. So at runtime, there is no pointer
    left; it's just a number.

    Jared
    JaredGrubb, Oct 2, 2010
    #13
  14. Armen Tsirunyan

    Luc Danton Guest

    On 02/10/2010 17:56, JaredGrubb wrote:
    > On Oct 1, 6:59 am, Goran<> wrote:
    >> >
    >> > Heh, true. I was thinking something along the lines of:
    >> >
    >> > TYPE& r = *(TYPE*)0;
    >> >
    >> > I used word "reference" because there's no "calling a member function
    >> > on a pointer". There's calling it on an object that pointer points to,
    >> > which I poorly named object reference (a __null__ one, since it's a
    >> > null pointer).
    >> >
    >>> > > There is no such thing as "dereferencing the object".
    >> >
    >> > Whoops, that's true, my bad. Should have been "dereferencing the
    >> > pointer"
    >> >
    >>> > > sizeof and offsetof are not examples of "absence of a * or a ->".
    >> >
    >> > I was thinking e.g.:
    >> >
    >> > TYPE* p=0;
    >> > sizeof(*p);
    >> > offsetof(p->field);
    >> >
    >>> > >sizeof and offsetof are not examples of "absence of a * or a ->".
    >> >
    >> > My bad again, that should have been "presence", not absence.
    >> >
    >> > OK, so, to correct myself...
    >> >
    >> > The question then becomes whether calling a member function on a null
    >> > object __pointer__ counts as dereferencing the __pointer__ (problem
    >> > being, I would think, that the mere __presence__ of a * or a -> does
    >> > not count as dereferencing it, e.g. with sizeof or offsetof).
    >> >
    >> > Sorry about the confusion.

    > First, "0" is a valid memory address and is not treated differently by
    > the compiler. For example, here's a write-up on how you can make Linux
    > create an object at address 0, and then you can write to it and call
    > it and whatever else you want to do.
    >
    > http://blog.ksplice.com/2010/03/null-pointers-part-i/
    >
    > There is nothing special about "0"; most OS/architectures/runtime
    > environments will not allocate objects at 0 because it's incredibly
    > "helpful" to have our programs crash when they pretend to have objects
    > at 0 -- in almost every case, this is a programming error and bad
    > things are going to happen.


    0 _is_ a special pointer value in C (and consequently, in C++). Please
    note that I am _not_ disagreeing with you on your other points: there
    OS/architecture/runtime are that behave as you describe. But consider
    that C and C++ have a very much simple notion of addresses: &a is the
    address of an object a and that's about it (not even sure if the
    Standard uses this terminology). There are however no notion of 'address
    space' and the like, and thus an 'address 0' has no meaning in C or C++.
    As you pointed out however, where it is defined it might be fine; but
    that's not covered by the C and C++ Standards.

    Furthermore, yes, a compiler _is_ free to treat 0 differently. The C++
    Standard mandates that every pointer initialized from or assigned to 0
    have the same special representation (actually there is one
    representation per pointer type). An implementation could behave as
    follows without triggering any assert and still be conforming:

    int* pint = 0; // int null pointer
    char* pchar = 0; // char null pointer

    intptr_t pint_rep;
    std::memcpy(&pint_rep, &pint, sizeof pint);
    assert( pint_rep != 0 ); // integral zero

    intptr_t pchar_rep;
    std::memcpy(&pchar_rep, &pchar, sizeof pchar);
    assert( pchar_rep != 0 ); // integral zero
    assert( pchar_rep != pint_rep );

    There are plenty of good items regarding null pointers on the C FAQ:
    http://c-faq.com/null/index.html

    such as:
    5.5 How should NULL be defined on a machine which uses a nonzero bit
    pattern as the internal representation of a null pointer?
    5.17 Seriously, have any actual machines really used nonzero null
    pointers, or different representations for pointers to different types?
    5.19 How can I access an interrupt vector located at the machine's
    location 0? If I set a pointer to 0, the compiler might translate it to
    some nonzero internal null pointer value.

    > Second, sizeof and offsetof do not dereference anything; they compute
    > values from*types*. So if p points to a type P, then sizeof(*p) and
    > sizeof(P) are equivalent; further if p2 is another pointer of type P,
    > sizeof(*p2) has the same value as the other two. That value is
    > computed at compile-time by the compiler and the constant value is
    > poked into the binary code itself. So at runtime, there is no pointer
    > left; it's just a number.
    >
    > Jared
    Luc Danton, Oct 3, 2010
    #14
  15. Luc Danton wrote:

    > On 02/10/2010 17:56, JaredGrubb wrote:
    >> On Oct 1, 6:59 am, Goran<> wrote:
    >>> >
    >>> > Heh, true. I was thinking something along the lines of:
    >>> >
    >>> > TYPE& r = *(TYPE*)0;
    >>> >
    >>> > I used word "reference" because there's no "calling a member function
    >>> > on a pointer". There's calling it on an object that pointer points
    >>> > to, which I poorly named object reference (a __null__ one, since it's
    >>> > a null pointer).
    >>> >
    >>>> > > There is no such thing as "dereferencing the object".
    >>> >
    >>> > Whoops, that's true, my bad. Should have been "dereferencing the
    >>> > pointer"
    >>> >
    >>>> > > sizeof and offsetof are not examples of "absence of a * or a ->".
    >>> >
    >>> > I was thinking e.g.:
    >>> >
    >>> > TYPE* p=0;
    >>> > sizeof(*p);
    >>> > offsetof(p->field);
    >>> >
    >>>> > >sizeof and offsetof are not examples of "absence of a * or a ->".
    >>> >
    >>> > My bad again, that should have been "presence", not absence.
    >>> >
    >>> > OK, so, to correct myself...
    >>> >
    >>> > The question then becomes whether calling a member function on a null
    >>> > object __pointer__ counts as dereferencing the __pointer__ (problem
    >>> > being, I would think, that the mere __presence__ of a * or a ->
    >>> > does not count as dereferencing it, e.g. with sizeof or offsetof).
    >>> >
    >>> > Sorry about the confusion.

    >> First, "0" is a valid memory address and is not treated differently by
    >> the compiler. For example, here's a write-up on how you can make Linux
    >> create an object at address 0, and then you can write to it and call
    >> it and whatever else you want to do.
    >>
    >> http://blog.ksplice.com/2010/03/null-pointers-part-i/
    >>
    >> There is nothing special about "0"; most OS/architectures/runtime
    >> environments will not allocate objects at 0 because it's incredibly
    >> "helpful" to have our programs crash when they pretend to have objects
    >> at 0 -- in almost every case, this is a programming error and bad
    >> things are going to happen.

    >
    > 0 _is_ a special pointer value in C (and consequently, in C++). Please
    > note that I am _not_ disagreeing with you on your other points: there
    > OS/architecture/runtime are that behave as you describe. But consider
    > that C and C++ have a very much simple notion of addresses: &a is the
    > address of an object a and that's about it (not even sure if the
    > Standard uses this terminology). There are however no notion of 'address
    > space' and the like, and thus an 'address 0' has no meaning in C or C++.
    > As you pointed out however, where it is defined it might be fine; but
    > that's not covered by the C and C++ Standards.
    >


    0 is not a pointer value. It's an integer value. As he said, there is
    nothing magic about "0". The null pointer conversion will yield a special
    pointer value when it is converted to a pointer type.

    > Furthermore, yes, a compiler _is_ free to treat 0 differently. The C++
    > Standard mandates that every pointer initialized from or assigned to 0
    > have the same special representation (actually there is one
    > representation per pointer type).


    Though I don't really see any practical use, there is no requirement in the
    Standard that "every pointer initialized from or assigned to 0 have the same
    special representation" even if we talk about only one pointer type. The
    only requirement is that all such pointers compare equal.

    The following probably makes no sense, but consider an implementation that
    has signed addresses, and which uses signed magnitude as representation and
    0x0 as an internal representation of a null pointer. Another interpretation
    could be -0x0 (highest bit set). I think that such a scenario could very
    well be possible in practice.
    Johannes Schaub (litb), Oct 3, 2010
    #15
  16. Armen Tsirunyan wrote:

    > On Oct 1, 3:59 pm, Goran <> wrote:
    >> On Oct 1, 9:25 am, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    >>
    >>
    >>
    >>
    >>
    >> > wrote:
    >> > * Goran, on 01.10.2010 06:29:

    >>
    >> > > On Sep 30, 5:13 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    >> > > > wrote:
    >> > >> * Armen Tsirunyan, on 30.09.2010 17:03:

    >>
    >> > >>> Hi all,
    >> > >>> Consider the following code:
    >> > >>> <CODE>
    >> > >>> #include<iostream>

    >>
    >> > >>> struct X
    >> > >>> {
    >> > >>> void f()
    >> > >>> {
    >> > >>> std::cout<< "f() called"<< std::endl;
    >> > >>> }
    >> > >>> };

    >>
    >> > >>> int main()
    >> > >>> {
    >> > >>> X* p = 0;
    >> > >>> p->f();
    >> > >>> X x = *p;
    >> > >>> x.f();
    >> > >>> }
    >> > >>> </CODE>

    >>
    >> > >>> it works( on MSVC9.0), and prints f() called two times. Well,
    >> > >>> logically it should, because in X::f() 'this' is not used and
    >> > >>> therefore theoretically this could be null; The copy construction
    >> > >>> also is logical to succeed because its implicit definition is
    >> > >>> empty. On the other hand, if X had a member the copy construction X
    >> > >>> x = *p woud fail, because the "this" of the *p would be needed.

    >>
    >> > >>> Now, my question is,
    >> > >>> 1. does the standard (the current one) say anything about
    >> > >>> dereferencing null pointers?

    >>
    >> > >> It mentions in non-normative text (as I recall) that it's UB to
    >> > >> dereference a nullpointer, in general. That's somewhere right at the
    >> > >> start, I think in the definitions of terms. However, even if there's
    >> > >> no normative text that says that outright, absence of such text is
    >> > >> just due to being an unnecessary clarification.

    >>
    >> > > The question then becomes whether calling a member function on a null
    >> > > object reference counts as dereferencing the object (problem being, I
    >> > > would think, that the mere absence of a * or a -> does not count as
    >> > > dereferencing it, e.g. with sizeof or offsetof).

    >>
    >> > That does not make sense.

    >>
    >> > There is no such thing as a "null object reference".

    >>
    >> Heh, true. I was thinking something along the lines of:
    >>
    >> TYPE& r = *(TYPE*)0;
    >>
    >> I used word "reference" because there's no "calling a member function
    >> on a pointer". There's calling it on an object that pointer points to,
    >> which I poorly named object reference (a __null__ one, since it's a
    >> null pointer).
    >>
    >> > There is no such thing as "dereferencing the object".

    >>
    >> Whoops, that's true, my bad. Should have been "dereferencing the
    >> pointer"
    >>
    >> > sizeof and offsetof are not examples of "absence of a * or a ->".

    >>
    >> I was thinking e.g.:
    >>
    >> TYPE* p=0;
    >> sizeof(*p);
    >> offsetof(p->field);
    >>
    >> >sizeof and offsetof are not examples of "absence of a * or a ->".

    >>
    >> My bad again, that should have been "presence", not absence.
    >>
    >> OK, so, to correct myself...
    >>
    >> The question then becomes whether calling a member function on a null
    >> object __pointer__ counts as dereferencing the __pointer__ (problem
    >> being, I would think, that the mere __presence__ of a * or a -> does
    >> not count as dereferencing it, e.g. with sizeof or offsetof).
    >>
    >> Sorry about the confusion.
    >>
    >> Goran.

    >
    > You have a good point there. Calling a member function on via a
    > pointer which is a null pointer is not dereferencing, is it?
    > Well, naturally it __involves__ dereferencing if the member function
    > cannot be made static, but what if it can? Is the wording in the
    > standard clear with this respect?


    The Standard says "If E1 has the type 'pointer to class X,' then the
    expression E1->E2 is converted to the equivalent form '(*(E1)).E2'; the
    remainder of 5.2.5 will address only the first option (dot)'. See 5.2.5/3.
    Johannes Schaub (litb), Oct 3, 2010
    #16
  17. Armen Tsirunyan

    James Kanze Guest

    On Oct 2, 4:56 pm, JaredGrubb <> wrote:
    > On Oct 1, 6:59 am, Goran <> wrote:


    [...]
    > > The question then becomes whether calling a member function
    > > on a null object __pointer__ counts as dereferencing the
    > > __pointer__ (problem being, I would think, that the mere
    > > __presence__ of a * or a -> does not count as dereferencing
    > > it, e.g. with sizeof or offsetof).


    In the past (I'm not sure about C++0x), calling a non-static
    member function (the expression o.f()) involves evaluating the
    expression to the left of the dot. If a -> is used, it is the
    equivalent of (*p).f(), so *p is evaluated (if the entire
    expression is evaluated). The result of *p is an lvalue, which
    must refer to an object or a function---otherwise, the behavior
    is undefined.

    This undefined behavior only occurs if the expression is
    "evaluated". Expressions which are operands of sizeof, for
    example, are never evaluated; nor are expressions in a flow path
    which is never executed. (In some ways, this can be considered
    "run-time" undefined behavior. A compiler can't refuse to
    compile code which contains it unless it can prove that the code
    will be executed for all possible input.)

    > > Sorry about the confusion.


    > First, "0" is a valid memory address and is not treated
    > differently by the compiler.


    A "null constant expression" converts to a pointer which is
    guaranteed not to point to a valid object. The expression "0"
    is a null constant expression. And the compiler is required to
    treat it differently.

    > For example, here's a write-up on how you can make Linux
    > create an object at address 0, and then you can write to it
    > and call it and whatever else you want to do.


    > http://blog.ksplice.com/2010/03/null-pointers-part-i/


    The author of the article doesn't seem to know C (or C++). But
    the issue is irrelevant with regards to C++ -- when you start
    playing games with specific system functions, you enter into the
    realm of undefined behavior.

    > There is nothing special about "0";


    There is according to the language standard.

    > most OS/architectures/runtime environments will not allocate
    > objects at 0 because it's incredibly "helpful" to have our
    > programs crash when they pretend to have objects at 0 -- in
    > almost every case, this is a programming error and bad things
    > are going to happen.


    Most OS's today will arrange things so that the null pointer
    constant 0 can be the address 0; it makes things a lot easier
    for the compiler. But that's neither here nor there.

    > Second, sizeof and offsetof do not dereference anything; they
    > compute values from *types*.


    The expressions in sizeof and typeof (if the type is not
    polymorphic) are not evaluated, so there is no problem. The
    macro offsetof doesn't even take a pointer, so there's no way of
    giving it a null pointer.

    --
    James Kanze
    James Kanze, Oct 5, 2010
    #17
  18. Armen Tsirunyan

    James Kanze Guest

    On Oct 3, 12:57 am, Luc Danton <> wrote:
    > On 02/10/2010 17:56, JaredGrubb wrote:


    [...]
    > > There is nothing special about "0"; most OS/architectures/runtime
    > > environments will not allocate objects at 0 because it's incredibly
    > > "helpful" to have our programs crash when they pretend to have objects
    > > at 0 -- in almost every case, this is a programming error and bad
    > > things are going to happen.


    > 0 _is_ a special pointer value in C (and consequently, in C++).


    No. 0 is an integral constant expression, not a pointer. It
    converts into any pointer type, and the results of that
    conversion is a pointer which cannot point to any valid object.

    Note that this is only true for integral constant expressions
    evaluating to 0. Given the following:

    int i = 0;
    char* p1 = reinterpret_cast<char*>(i);
    char* p2 = reinterpret_cast<char*>(0);
    assert(p1 == p2); // May fail!

    [...]
    > Furthermore, yes, a compiler _is_ free to treat 0 differently.


    It is required to treat 0 differently.

    > The C++ Standard mandates that every pointer initialized from
    > or assigned to 0 have the same special representation
    > (actually there is one representation per pointer type).


    Just a nit, but the standard doesn't require that. All that it
    requires is that all pointers initialized with 0 compare equal.
    (Of course, the easiest way for them to compare equal is for
    them to have the same representation, and I can't think of any
    reason why a compiler might use different representations.)

    > An implementation could behave as follows without triggering
    > any assert and still be conforming:


    > int* pint = 0; // int null pointer
    > char* pchar = 0; // char null pointer


    > intptr_t pint_rep;
    > std::memcpy(&pint_rep, &pint, sizeof pint);
    > assert( pint_rep != 0 ); // integral zero


    > intptr_t pchar_rep;
    > std::memcpy(&pchar_rep, &pchar, sizeof pchar);
    > assert( pchar_rep != 0 ); // integral zero
    > assert( pchar_rep != pint_rep );


    Exactly.

    --
    James Kanze
    James Kanze, Oct 5, 2010
    #18
  19. Armen Tsirunyan

    James Kanze Guest

    On Oct 3, 1:26 am, "Johannes Schaub (litb)" <>
    wrote:
    > Luc Danton wrote:


    [...]
    > > 0 _is_ a special pointer value in C (and consequently, in C++). Please
    > > note that I am _not_ disagreeing with you on your other points: there
    > > OS/architecture/runtime are that behave as you describe. But consider
    > > that C and C++ have a very much simple notion of addresses: &a is the
    > > address of an object a and that's about it (not even sure if the
    > > Standard uses this terminology). There are however no notion of 'address
    > > space' and the like, and thus an 'address 0' has no meaning in C or C++.
    > > As you pointed out however, where it is defined it might be fine; but
    > > that's not covered by the C and C++ Standards.


    > 0 is not a pointer value. It's an integer value. As he said, there is
    > nothing magic about "0". The null pointer conversion will yield a special
    > pointer value when it is converted to a pointer type.


    And that is magic:). There's nothing magic about the value 0,
    in itself, but there is magic when it's an integral constant
    expression evaluating to 0.

    --
    James Kanze
    James Kanze, Oct 5, 2010
    #19
    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. Denis Palmeiro

    NULL Pointer Dereference

    Denis Palmeiro, Jul 8, 2003, in forum: C Programming
    Replies:
    10
    Views:
    662
    Shill
    Jul 16, 2003
  2. Replies:
    6
    Views:
    448
    Alf P. Steinbach
    Oct 3, 2007
  3. Tony Jackson

    Avoiding dereference of NULL pointer

    Tony Jackson, Dec 15, 2007, in forum: C Programming
    Replies:
    17
    Views:
    780
    Randy Howard
    Dec 29, 2007
  4. aneuryzma
    Replies:
    3
    Views:
    704
    Jim Langston
    Jun 16, 2008
  5. rantingrick
    Replies:
    44
    Views:
    1,198
    Peter Pearson
    Jul 13, 2010
Loading...

Share This Page