[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080118133116.GA31790@atjola.homenet>
Date: Fri, 18 Jan 2008 14:31:16 +0100
From: Björn Steinbrink <B.Steinbrink@....de>
To: Jakob Oestergaard <jakob@...hought.net>,
Linus Torvalds <torvalds@...ux-foundation.org>,
David Schwartz <davids@...master.com>,
Johannes Weiner <hannes@...urebad.de>,
Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
clameter@....com, penberg@...helsinki.fi
Subject: 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 <stdio.h>
#include <stdlib.h>
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@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists