From: "Björn Steinbrink" <B.Steinbrink@gmx.de>
To: Jakob Oestergaard <jakob@unthought.net>,
Linus Torvalds <torvalds@linux-foundation.org>,
David Schwartz <davids@webmaster.com>,
Johannes Weiner <hannes@saeurebad.de>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
clameter@sgi.com, penberg@cs.helsinki.fi
Subject: Re: Why is the kfree() argument const?
Date: Fri, 18 Jan 2008 14:31:16 +0100 [thread overview]
Message-ID: <20080118133116.GA31790@atjola.homenet> (raw)
In-Reply-To: <20080118094826.GN25527@unthought.net>
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
next prev parent reply other threads:[~2008-01-18 13:31 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <MDEHLPKNGKAHNMBLJOLKIEGIJJAC.davids@webmaster.com>
2008-01-17 21:25 ` Why is the kfree() argument const? Linus Torvalds
2008-01-17 22:28 ` David Schwartz
2008-01-17 23:10 ` Linus Torvalds
2008-01-18 0:56 ` David Schwartz
2008-01-18 1:15 ` Linus Torvalds
2008-01-18 5:02 ` David Schwartz
2008-01-18 15:38 ` Chris Friesen
2008-01-18 16:10 ` Linus Torvalds
2008-01-18 20:55 ` David Schwartz
2008-01-18 17:37 ` Olivier Galibert
2008-01-18 18:06 ` DM
2008-01-18 7:51 ` Giacomo Catenazzi
2008-01-18 8:20 ` Giacomo Catenazzi
2008-01-18 13:53 ` Andy Lutomirski
2008-01-18 17:24 ` Olivier Galibert
2008-01-18 22:29 ` J.A. Magallón
2008-01-18 23:44 ` Krzysztof Halasa
2008-01-18 13:54 ` Andy Lutomirski
2008-01-18 19:14 ` Vadim Lobanov
2008-01-18 19:31 ` Zan Lynx
2008-01-18 19:55 ` Vadim Lobanov
2008-01-18 8:30 ` Vadim Lobanov
2008-01-18 9:48 ` Jakob Oestergaard
2008-01-18 11:47 ` Giacomo A. Catenazzi
2008-01-18 14:39 ` Jakob Oestergaard
2008-01-18 19:06 ` Vadim Lobanov
2008-01-18 13:31 ` Björn Steinbrink [this message]
2008-01-18 14:53 ` Jakob Oestergaard
[not found] <fa.cHMztHfqJXv7vw5O0nQ8SdTrma0@ifi.uio.no>
[not found] ` <fa.V9M+5l8C/um5KEiBtZOjbJDQmu4@ifi.uio.no>
2013-01-12 19:18 ` antoine.trux
2013-01-13 8:10 ` Chen Gang F T
2013-01-13 17:41 ` Guenter Roeck
2013-01-14 1:45 ` Chen Gang F T
2013-01-13 20:54 ` Cong Ding
2013-01-14 1:18 ` Chen Gang F T
2008-01-18 19:10 ecolbus
-- strict thread matches above, loose matches on Subject: below --
2008-01-18 16:45 ecolbus
2008-01-18 18:20 ` Olivier Galibert
2008-01-18 12:45 ecolbus
2008-01-18 15:20 ` Giacomo A. Catenazzi
2008-01-16 16:32 Johannes Weiner
2008-01-16 16:48 ` Christoph Lameter
2008-01-16 17:34 ` Bernd Petrovitsch
2008-01-16 17:45 ` Pekka J Enberg
2008-01-16 18:39 ` Linus Torvalds
2008-01-16 22:19 ` Johannes Weiner
2008-01-16 22:20 ` Christoph Lameter
2008-01-16 22:37 ` Johannes Weiner
2008-01-16 23:13 ` Johannes Weiner
2008-01-16 23:18 ` Linus Torvalds
2008-01-16 23:16 ` Linus Torvalds
2008-01-16 22:33 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080118133116.GA31790@atjola.homenet \
--to=b.steinbrink@gmx.de \
--cc=clameter@sgi.com \
--cc=davids@webmaster.com \
--cc=hannes@saeurebad.de \
--cc=jakob@unthought.net \
--cc=linux-kernel@vger.kernel.org \
--cc=penberg@cs.helsinki.fi \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox