RE: Why is the kfree() argument const? - Kernel

This is a discussion on RE: Why is the kfree() argument const? - Kernel ; On Thu, 17 Jan 2008, David Schwartz wrote: > > Which does change the thing the pointer points to. It goes from being a > valid object to not existing. No. It's the *pointer* that is no longer valid. There's ...

+ Reply to Thread
Results 1 to 9 of 9

Thread: RE: Why is the kfree() argument const?

  1. RE: Why is the kfree() argument const?



    On Thu, 17 Jan 2008, David Schwartz wrote:
    >
    > Which does change the thing the pointer points to. It goes from being a
    > valid object to not existing.


    No. It's the *pointer* that is no longer valid.

    There's definitely a difference between "exists and is changed" and
    "doesn't exist any more".

    > How is ceasing to exist not a change?


    It's not a change to the data behind it, it's a change to the *metadata*.
    Which is somethign that "const" doesn't talk about at all.

    > > Why? Because we want the types to be as tight as possible, and normal
    > > code should need as few casts as possible.

    >
    > Right, and that's why you are wrong.


    No, it's why I'm right.

    "kmalloc/kfree" (or any memory manager) by definition has to play games
    with pointers and do things like cast them. But the users shouldn't need
    to, not for something like this.

    > No, it's both correct and useful. This code is the exception to a rule. The
    > rule is that the object remain unchanged and this violates that rule.


    No.

    You are continuing to make the mistake that you think that "const" means
    that the memory behind the pointer is not going to change.

    Why do you make that mistake, when it is PROVABLY NOT TRUE!

    Try this trivial program:

    int main(int argc, char **argv)
    {
    int i;
    const int *c;

    i = 5;
    c = &i;
    i = 10;
    return *c;
    }

    and realize that according to the C rules, if it returns anything but 10,
    the compiler is *buggy*.

    The fact is, that in spite of us having a "const int *", the data behind
    that pointer may change.

    So it doesn't matter ONE WHIT if you pass in a "const *" to "kfree()": it
    does not guarantee that the data doesn't change, because the object you
    point to has other pointers pointing to it.

    This isn't worth discussing. It's really simple: a conforming program
    CANNOT POSSIBLY TELL whether "kfree()" modified the data or not. As such,
    AS FAR AS THE PROGRAM IS CONCERNED, kfree() takes a const pointer, and the
    rule that "if it can be considered const, it should be marked const" comes
    and says that kfree() should take a const pointer.

    In other words - anythign that could ever disagree with "const *" is BY
    DEFINITION buggy.

    It really is that simple.

    Linus
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. RE: Why is the kfree() argument const?



    > On Thu, 17 Jan 2008, David Schwartz wrote:


    > > Which does change the thing the pointer points to. It goes from being a
    > > valid object to not existing.


    > No. It's the *pointer* that is no longer valid.


    The pointer is no longer valid because the object it pointed to no longer
    exists. The pointer is also no longer valid, but that is not the end of the
    story.

    > There's definitely a difference between "exists and is changed" and
    > "doesn't exist any more".


    > > How is ceasing to exist not a change?


    > It's not a change to the data behind it, it's a change to the *metadata*.
    > Which is somethign that "const" doesn't talk about at all.


    It doesn't matter what has changed. All that matters is whether this is
    something we normally want to happen to a const pointer or whether doing
    this to a const pointer is not normal.

    > > > Why? Because we want the types to be as tight as possible,
    > > > and normal
    > > > code should need as few casts as possible.

    > >
    > > Right, and that's why you are wrong.

    >
    > No, it's why I'm right.


    > "kmalloc/kfree" (or any memory manager) by definition has to play games
    > with pointers and do things like cast them. But the users shouldn't need
    > to, not for something like this.


    If you don't like having to cast, don't use 'const'. But if you use 'const',
    you have to cast when you mean to do something that you would like to be
    warned about if you do it by accident.

    > > No, it's both correct and useful. This code is the exception to

    > a rule. The
    > > rule is that the object remain unchanged and this violates that rule.


    > No.
    >
    > You are continuing to make the mistake that you think that "const" means
    > that the memory behind the pointer is not going to change.


    No, that's not what it means. It has nothing to do with memory. It has to do
    with logical state.

    > Why do you make that mistake, when it is PROVABLY NOT TRUE!


    I don't. You do, because you argue 'kfree' can be const because it doesn't
    change the memory. The change in the memory is meaningless, the change in
    the logical state of the object is what matters.

    > Try this trivial program:
    >
    > int main(int argc, char **argv)
    > {
    > int i;
    > const int *c;
    >
    > i = 5;
    > c = &i;
    > i = 10;
    > return *c;
    > }
    >
    > and realize that according to the C rules, if it returns anything but 10,
    > the compiler is *buggy*.
    >
    > The fact is, that in spite of us having a "const int *", the data behind
    > that pointer may change.


    I don't know what you think this example proves. Nobody is arguing that so
    long as one const pointer to an object exists, no code anywhere should ever
    be able to change it.

    All I'm saying is that changing the logical state of an object *through* a
    const pointer is unusual. You should need a cast to do this because that's
    the only way to get a warning if you do it by mistake.

    > So it doesn't matter ONE WHIT if you pass in a "const *" to "kfree()": it
    > does not guarantee that the data doesn't change, because the object you
    > point to has other pointers pointing to it.


    Right, nobody said this was about guaranteeing that data doesn't change.

    > This isn't worth discussing. It's really simple: a conforming program
    > CANNOT POSSIBLY TELL whether "kfree()" modified the data or not.


    But that's exactly what doesn't matter. As you've said at least twice now,
    it has nothing to do with changing the data. It has to do with changing the
    logical state of the object. That's what you're not supposed to do through a
    'const' pointer.

    > As such,
    > AS FAR AS THE PROGRAM IS CONCERNED, kfree() takes a const
    > pointer, and the
    > rule that "if it can be considered const, it should be marked
    > const" comes
    > and says that kfree() should take a const pointer.


    That's crazy.

    > In other words - anythign that could ever disagree with "const *" is BY
    > DEFINITION buggy.
    >
    > It really is that simple.


    I think you may be the only person in the world who thinks so.

    DS


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. RE: Why is the kfree() argument const?



    On Thu, 17 Jan 2008, David Schwartz wrote:
    >
    > No, that's not what it means. It has nothing to do with memory. It has to do
    > with logical state.


    Blah. That's just your own made-up explanation of what you think "const"
    should mean. It has no logical background or any basis in the C language.

    "const" has nothing to do with "logical state". It has one meaning, and
    one meaning only: the compiler should complain if that particular type is
    used to do a write access.

    It says nothing at all about the "logical state of the object". It cannot,
    since a single object can - and does - have multiple pointers to it.

    So your standpoint not only has no relevant background to it, it's also
    not even logically consistent.

    Linus
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. Re: Why is the kfree() argument const?

    On Thu, Jan 17, 2008 at 01:25:39PM -0800, Linus Torvalds wrote:
    ....
    > Why do you make that mistake, when it is PROVABLY NOT TRUE!
    >
    > Try this trivial program:
    >
    > int main(int argc, char **argv)
    > {
    > int i;
    > const int *c;
    >
    > i = 5;
    > c = &i;
    > i = 10;
    > return *c;
    > }
    >
    > and realize that according to the C rules, if it returns anything but 10,
    > the compiler is *buggy*.


    That's not how this works (as we obviously agree).

    Please consider a rewrite of your example, demonstrating the usefulness and
    proper application of const pointers:

    extern foo(const int *);

    int main(int argc, char **argv)
    {
    int i;

    i = 5;
    foo(&i);
    return i;
    }

    Now, if the program returns anything else than 5, it means someone cast away
    const, which is generally considered a bad idea in most other software
    projects, for this very reason.

    *That* is the purpose of const pointers.

    Besides, for most debugging-enabled free() implementations, free() does indeed
    touch the memory pointed to by its argument, which makes giving it a const
    pointer completely bogus except for a single potential optimized special-case
    where it might actually not touch the memory.

    --

    / jakob

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. Re: Why is the kfree() argument const?

    Jakob Oestergaard wrote:
    > On Thu, Jan 17, 2008 at 01:25:39PM -0800, Linus Torvalds wrote:
    > ...
    >> Why do you make that mistake, when it is PROVABLY NOT TRUE!
    >>
    >> Try this trivial program:
    >>
    >> int main(int argc, char **argv)
    >> {
    >> int i;
    >> const int *c;
    >>
    >> i = 5;
    >> c = &i;
    >> i = 10;
    >> return *c;
    >> }
    >>
    >> and realize that according to the C rules, if it returns anything but 10,
    >> the compiler is *buggy*.

    >
    > That's not how this works (as we obviously agree).
    >
    > Please consider a rewrite of your example, demonstrating the usefulness and
    > proper application of const pointers:
    >
    > extern foo(const int *);
    >
    > int main(int argc, char **argv)
    > {
    > int i;
    >
    > i = 5;
    > foo(&i);
    > return i;
    > }
    >
    > Now, if the program returns anything else than 5, it means someone cast away
    > const, which is generally considered a bad idea in most other software
    > projects, for this very reason.
    >
    > *That* is the purpose of const pointers.


    "restrict" exists for this reason. const is only about lvalue.

    You should draw a line, not to make C more complex!

    Changing the name of variables in your example:

    extern print_int(const int *);

    int main(int argc, char **argv)
    {
    extern int errno;

    errno = 0;
    print_int(&i);
    return errno;
    }

    print_int() doesn't know that errno is also the argument.
    and this compilation unit doesn't know that print_int() will
    modify errno.

    Ok, I changed int to extern int, but you see the point?
    Do you want complex rules about const, depending on
    context (extern, volatile,...) ?

    ciao
    cate
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. Re: Why is the kfree() argument const?

    On 2008.01.18 10:48:26 +0100, Jakob Oestergaard wrote:
    > On Thu, Jan 17, 2008 at 01:25:39PM -0800, Linus Torvalds wrote:
    > ...
    > > Why do you make that mistake, when it is PROVABLY NOT TRUE!
    > >
    > > Try this trivial program:
    > >
    > > int main(int argc, char **argv)
    > > {
    > > int i;
    > > const int *c;
    > >
    > > i = 5;
    > > c = &i;
    > > i = 10;
    > > return *c;
    > > }
    > >
    > > and realize that according to the C rules, if it returns anything but 10,
    > > the compiler is *buggy*.

    >
    > That's not how this works (as we obviously agree).
    >
    > Please consider a rewrite of your example, demonstrating the usefulness and
    > proper application of const pointers:
    >
    > extern foo(const int *);
    >
    > int main(int argc, char **argv)
    > {
    > int i;
    >
    > i = 5;
    > foo(&i);
    > return i;
    > }
    >
    > Now, if the program returns anything else than 5, it means someone cast away
    > const, which is generally considered a bad idea in most other software
    > projects, for this very reason.


    Not at all.

    #include
    #include

    char *lookup[5];

    const char *get()
    {
    *(*lookup = malloc(1)) = '1';
    return *lookup;
    }

    void set(const char *d, char val)
    {
    for (int i = 0; i < 5; ++i)
    if (lookup[i] == d)
    *(lookup[i]) = val;
    }

    int main()
    {
    const char *p = get();

    printf("%c\n", *p);
    set(p, '2');
    printf("%c\n", *p);

    return 0;
    }

    Do you see anything that casts the const away? No? Me neither. Still,
    the memory that p points to was changed, because there was another
    pointer and that was not const.

    > *That* is the purpose of const pointers.


    The only thing that const can tell you is that you should not modify the
    value _yourself_, using that pointer _directly_. It's somewhat like a
    soft "half" protected/private specifier. You may read this value, but if
    you want to write to it, please use the setter function I provide for
    you. Because that setter function might do some special stuff, like
    counting how often that value was written.

    And accepting a pointer to a const as an argument does _only_ say: It's
    ok to call this function if you only received a pointer to a const, the
    function does the Right Thing for such pointers. It does not guarantee
    at all, that the function won't change the memory the pointer is
    pointing to. Take a set of functions that manage memory for foo objects:

    const struct foo *get(someIdentifier);
    struct foo *makeWritable(const struct foo *);
    void free(const struct foo *);

    get() returns a pointer to a foo object, and it might return a pointer
    to a _shared_ instance. Obviously it should make the pointer const, the
    caller should not modify the shared instance.

    makeWritable() accepts a pointer to a const foo, because you generally
    want to pass it such a pointer to get a non-const one instead. The
    function might just use ref-counting and see if it needs to create a
    copy returning a pointer to points to a different location in memory or
    if it can just return its _internal_ _non-const_ pointer. No casts!

    free() also accepts a pointer to a const foo, because you obviously want
    to be able to free the shared stuff, too. It just happens to not always
    go away immediately, because there's some ref-counting going on. But you
    are _still_ invalidating your const pointer. You lost all rights to
    using it, because you _gave it up_ when you called free(). An important
    part of free() is to _invalidate_ the _pointer_. Whether or not the
    object it pointed to was modified or not doesn't matter at all, because
    you have no valid means of accessing it _anyway_, it's totally out of
    scope.

    Now I can hear you screaming "But that's refcounting! That's totally
    different!". It's _not_. Just "pretend" that get() cannot return the
    same thing twice, then your ref-counting only goes up to one and boom,
    you've just reinvented malloc/free, with a const pointer being passed to
    free().

    Passing a pointer to free invalidates that pointer, and all pointers
    that share the same value. And then, when no valid ways to access the
    object are left, free() is free to use the memory in any way it wants.
    Without any stricht need to use the const pointer to perform any writes.
    That might be an optimization, but you can do without.

    What you're arguing about is actually that you don't want anyone to be
    able to use a const pointer to invalidate any other pointer, not that
    you don't want an object to be changed through a const pointer, because
    that is simply not what happens.

    If you want to restrict the set of pointers that can be invalidated by
    an other pointer, you'll have to use something else because const does
    not talk about invalidating aliasing pointers.

    Björn
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. Re: Why is the kfree() argument const?

    On Fri, Jan 18, 2008 at 12:47:01PM +0100, Giacomo A. Catenazzi wrote:
    ....
    > "restrict" exists for this reason. const is only about lvalue.


    You think that I try to put more meaning into const than I do - but I don't.

    Please read what I wrote, not what you want to think I wrote.

    I agree that if I said what you seem to imply I said, then I would have been
    wrong. But I didn't so I'm not


    --

    / jakob

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. Re: Why is the kfree() argument const?

    On Fri, Jan 18, 2008 at 02:31:16PM +0100, Björn Steinbrink wrote:
    ....
    >
    > Do you see anything that casts the const away? No? Me neither. Still,
    > the memory that p points to was changed, because there was another
    > pointer and that was not const.


    *another* being key here.

    >
    > > *That* is the purpose of const pointers.

    >
    > The only thing that const can tell you is that you should not modify the
    > value _yourself_, using that pointer _directly_.


    Which is pretty damn useful.

    Think about it. Don't you ever use const? Is it ever only in the way?

    ....
    {snip long explanation about how one can avoid the benefits of const, without
    using casts}
    ....
    > If you want to restrict the set of pointers that can be invalidated by
    > an other pointer, you'll have to use something else because const does
    > not talk about invalidating aliasing pointers.


    Precisely, so why are we discussing this?

    I claim that const is useful. You claim that it can't solve all the worlds
    problems. I agree with that, but I maintain it is still useful.

    But, in order for it to be useful, it requires that people do not circumvent it
    in the wrong places (such as kfree).

    --

    / jakob

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. Re: Why is the kfree() argument const?

    On Friday 18 January 2008 03:47:01 am Giacomo A. Catenazzi wrote:
    > Changing the name of variables in your example:
    >
    > extern print_int(const int *);
    >
    > int main(int argc, char **argv)
    > {
    > extern int errno;
    >
    > errno = 0;
    > print_int(&i);
    > return errno;
    > }


    Except that changing int to extern int makes all the difference in the world:
    the variable went from being local to being global. The way const is
    currently defined, however, the compiler cannot take advantage of the fact
    that the variable was local in the former case.

    > Ok, I changed int to extern int, but you see the point?
    > Do you want complex rules about const, depending on
    > context (extern, volatile,...) ?


    Sometimes complexity is worth it.

    -- Vadim Lobanov
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread