No. It's the *pointer* that is no longer valid.
There's definitely a difference between "exists and is changed" and
It's not a change to the data behind it, it's a change to the *metadata*.
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 needNo.
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
--
On Thu, Jan 17, 2008 at 01:25:39PM -0800, Linus Torvalds wrote:
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
--
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 anotherThe 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 obv...
On Fri, Jan 18, 2008 at 02:31:16PM +0100, Björn Steinbrink wrote:
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}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
--
"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
--
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 factSometimes complexity is worth it.
-- Vadim Lobanov
--
On Fri, Jan 18, 2008 at 12:47:01PM +0100, Giacomo A. Catenazzi wrote:
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
--
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 theIt 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 doingIf 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 beNo, that's not what it means. It has nothing to do with memory. It has to do
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 inI 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'sBut 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 aI think you may be the only person in the world who thinks so.
DS
--
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 some extent, I agree. You can use "const" for pretty much any reason.
It's just a way to say that you have a pointer and you would like an error
if certain things are done with it.You could use it to mean anything you want it to mean. The most common use,
and the one intended, is to indicate that an object's logical state will notYou are the only one who has suggested it has anything to do with changes
through other pointers or in other ways. So you are arguing against only
yourself here.Nobody has said it has anything to do with anything but operations through
Actually, that is true of your position. On the one hand, you defend it
because kfree does not change the data. On the other hand, you claim that it
has nothing to do with whether or not the data is changed.The normal use of "const" is to indicate that the logical state of the
object should not be changed through that pointer. The 'kfree' function
changes the logical state of the object. So, logically, 'kfree' should not
be const.The usefulness of "const" is that you get an error if you unexpectedly
modify something you weren't expected to modify. If you are 'kfree'ing an
object that is supposed to be logically immutable, you should be made to
indicate that you are aware the object is logically immutable.Simply put, you you have to cast in any case where you mean to do something
that you want to get an error in if you do not cast. I would like to get an
error if I call 'kfree' through a const pointer, because that often is an
error. I may have a const pointer because my caller still plans to use the
object.Honestly, I find your position bizarre.
DS
--
So why do you complain?
No, I'm saying that "const" has absolutely *zero* meaning on writes to an
object through _other_ pointers (or direct access) to the object.And you're seemingly not understanding that *lack* of meaning.
kfree() doesn't do *squat* to the object pointed to by the pointer it is
passed. It only uses it to look up its own data structures, of which the
pointer is but a small detail... and I'm telling you: kfree() does *nothing* conceptually through that
pointer. No writes, and not even any reads! Which is exactly why it's
const.The only thing kfree does through that pointer is to update its own
concept of what memory it has free.Now, what it does to its own free memory is just an implementation detail,
and has nothing what-so-ever to do with the pointer you passed it.See?
Linus
--
Hints: "restrict" is the C99 keyword for such requirement (or better
"const restrict")BTW I think C use non const free as a BIG warning about not to be
to "smart" on optimization.ciao
cate
--
The restrict keyword controls aliasing, to be exact. And I'm skeptical that
I must ask what relationship you think the const keyword has to compiler
optimizations. I know of none, and I've yet to see that keyword cause any
difference in the resulting assembly. It forces you to make your code clean
and well-structured, but that's about it.Of course, it would be an interesting experiment to potentially redefine the
const keyword to have stronger semantics, such as having the compiler assume
that a function taking a const pointer argument will not modify the memory
the pointer points to, and thus saving itself a memory load in the caller
after the function executes, as long as the data is not global. I imagine
that this would lead to some simple and measurable optimizations, all the
while (this is where I get into hand-waving territory) breaking a minimum
amount of code in current existence.But that is emphatically not how C is currently defined, and you're basically
inventing an entirely new language... C2009 perhaps? :-)-- Vadim Lobanov
--
And to demostrate that Linus is not the only person
with this view, I copy some paragraphs from C99 rationale
(you can find standard, rationale and other documents
in http://clc-wiki.net/wiki/C_standardisation:ISO )Page 75 of C99 rationale:
Type qualifiers were introduced in part to provide greater control over optimization. Several
important optimization techniques are based on the principle of "cacheing": under certain
circumstances the compiler can remember the last value accessed (read or written) from a
location, and use this retained value the next time that location is read. (The memory, or
"cache", is typically a hardware register.) If this memory is a machine register, for instance, the
code can be smaller and faster using the register rather than accessing external memory.
The basic qualifiers can be characterized by the restrictions they impose on access and
cacheing:const No writes through this lvalue. In the absence of this qualifier, writes may occur
through this lvalue.volatile No cacheing through this lvalue: each operation in the abstract semantics must
be performed (that is, no cacheing assumptions may be made, since the location
is not guaranteed to contain any previous value). In the absence of this qualifier,
the contents of the designated location may be assumed to be unchanged except
for possible aliasing.restrict Objects referenced through a restrict-qualified pointer have a special
association with that pointer. All references to that object must directly or
indirectly use the value of this pointer. In the absence of this qualifier, other
pointers can alias this object. Cacheing the value in an object designated through
a restrict-qualified pointer is safe at the beginning of the block in which the
pointer is declared, because no pre-existing aliases may also be used to reference
...
I'd say this implies the exact opposite. It almost sounds like the
compiler is free to change:void foo(const int *x);
foo(x);
printf("%d", x);to:
void foo(const int *x);
printf("%d", x);
foo(x);especially if it can prove that the pointer to x doesn't otherwise
escape or that foo doesn't call anything that could see the pointer (and
given that gcc has special magical markings for malloc, one way this
could be "proven" is to have x be some freshly malloced object.If foo is kfree, then the above transformation is clearly invalid.
(Note that this isn't just a problem for optimizers -- a programmer
might expect that passing a pointer to a function that takes a const
pointer argument does not, in and of itself, change the pointed-to
value. Given that const certainly does not mean that no one else
changes the object, I'm not sure what else it could mean. kfree does
not have either property, so I'm don't think it makes sense for it to
take a const argument.)--
That's absolutely not true.
Let's unravel the code, by fixing usage of 'x' (which seems to vary at will
between value and pointer in the above example), and by replacing printf with
another opaque function. Our decls:
void foo(const int *ptr);
void bar(int val);
You're saying that this:
foo(&x);
bar(x);
can be reordered into this:
bar(x);
foo(&x);No way. First, the way that const is currently defined, the compiler cannot
assume that the value of x did not change while foo was executing. So, it
will not only be forced to leave the two functions in that order, it will
even reload the value of x before passing it into bar. Go figure.Second, even if const did have stronger semantics that forbade the value of x
from being modified during execution of foo, the compiler still could not
reorder the two function calls, before it cannot assume that the two
functions (in their internal implementations) do not touch some other,
unknown to this code, global variable.-- Vadim Lobanov
--
On Fri, 2008-01-18 at 11:14 -0800, Vadim Lobanov wrote:
This is why GCC has the pure and const function attributes. These
attributes are more powerful than the "const" keyword, and do allow
optimizations with assumptions about global state.
--=20
Zan Lynx <zlynx@acm.org>
Oh, absolutely. The problem, however, is that very very few people actually
use these function attributes in their code. Heck, we don't even use the
standard restrict keyword, much less gcc-specific function annotations.I think that one part of the problem is because gcc seems to have had
attribute diarrhea -- I know of noone who can recite more than 10% of the
available attributes without glancing at the documentation. The other part of
the problem is that gcc does no sanity checks on the provided attributes. For
example, the code below compiles perfectly fine without a peep, even
with -Wall and -Wextra.int global;
void foobar(const int *x) __attribute__((const));
void foobar(const int *x)
{
if (*x)
*(int *)x = 7;
global = 11;
}*grumble, grumble* :-)
-- Vadim Lobanov
--
I'd say this implies the exact opposite. It almost sounds like the
compiler is free to change:void foo(const int *x);
foo(x);
printf("%d", x);to:
void foo(const int *x);
printf("%d", x);
foo(x);especially if it can prove that the pointer to x doesn't otherwise
escape or that foo doesn't call anything that could see the pointer (and
given that gcc has special magical markings for malloc, one way this
could be "proven" is to have x be some freshly malloced object.If foo is kfree, then the above transformation is clearly invalid.
(Note that this isn't just a problem for optimizers -- a programmer
might expect that passing a pointer to a function that takes a const
pointer argument does not, in and of itself, change the pointed-to
value. Given that const certainly does not mean that no one else
changes the object, I'm not sure what else it could mean. kfree does
not have either property, so I'm don't think it makes sense for it to
take a const argument.)--
That's only if neither function has side effects noticeable by the
Most of the time, const pointer arguments means "I won't change the
contents of the object so that you'll notice by reading it in a normal
way afterwards". That's pretty much what mutable in a variety of
languages (including C++) is about, saying "this field is internal
management stuff not visible from the external interface, so I need to
be able to change it even through const pointers I got as parameters".
Reference counters for copy-on-write setups is the usual example of
use.In the case of deallocation functions you are not allowed to do
anything through the pointer or its aliases after the function
returns. So we're outside of the "most of the time" case, since
you're not allowed to try to notice any change. Pragmatism takes
over, you want the type that catches as many possible types as
possible while staying reasonable (volatile is never reasonable), and
that's const void *. As simple as that.As for releasing resources through const pointers, that happens all
the time as soon as your const use is tight, and if you think forcing
the systematic addition of a (void *) cast is going to make your code
more readable, well, you need more experience in maintaining otherdelete in C++ allows const pointers. Think about it.
OG.
--
That's what __attribute__ ((pure)) is for, but if none of the
functions is pure, the compiler can not be sure about side effects
and can not reorder things. Don't forget that functions can do
anything apart from mangling with their arguments.And allocator/deallocator functions never can be pure, they must
change global data, the pool of free blocks.--
J.A. Magallon <jamagallon()ono!com> \ Software is like sex:
\ It's better when it's free
Mandriva Linux release 2008.1 (Cooker) for i586
Linux 2.6.23-jam05 (gcc 4.2.2 20071128 (4.2.2-2mdv2008.1)) SMP PREEMPT
--
Though it seems it could legally transform:
void kfree(const int *x);
{
int v, *ptr = malloc(sizeof(int));
*ptr = 51;
v = *ptr;
kfree(ptr);
printf("%d", v);into:
{
int v, *ptr = malloc(sizeof(int));
*ptr = 51;
kfree(ptr);
v = *ptr;
printf("%d", v);
}if it knows that malloc generates unaliased pointers, which seems
reasonable in general.
--
Krzysztof Halasa
--
Because the object ceases to exist. However, any modification requires write
Nonsense. The 'kfree' function *destroys* the object pointer to by the
It destroys the object the pointer points to. Destroying an object requires
That is not what it does, that is how it does it. What it does is destroy
I now have a much better understanding of what you're saying, but I still
think it's nonsense.1) An operation that modifies the logical state of an object should not
normally be done through a 'const' pointer. The reason you make a pointer
'const' is to indicate that this pointer should not be used to change the
logical state of the object pointed to.2) The 'kfree' operation changes the logical state of the object pointed to,
as the object goes from existent to non-existent.3) It is most useful for 'kfree' to be non-const because destroying an
object through a const pointer can easily be done in error. One of the
reasons you provide a const pointer is because you need the function you
pass the pointer to not to modify the object. Since this is an unusual
operation that could be an error, it is logical to force the person doing it
to clearly indicate that he knows the pointer is const and that he knows it
is right anyway.I'm curious to hear how some other people on this feel. You are the first
competent coder I have *ever* heard make this argument.By the way, I disagree with your metadata versus data argument. I would
agree that a function that changes only an object's metadata could be done
through a const pointer without needed a cast. A good example would be a
function that updates a "last time this object was read" variable.However, *destroying* an object is not a metadata operation -- it destroys
the data as well. This is kind of a philosophical point, but an object does
not have a "does this object exist" piece of metadata. If an object does not
exist, it has no data. So destroying an object destroys the data and is thus
a write/modification operation on...
In C++ you can delete a const pointer. Now I know kernel hackers
aren't especially impressed with C++ but maybe someone could look up
the rationale for that design decision (I couldn't find it). It might
shed some light on this discussion./DM
--
Freeing a const pointer is not and has never been unusual. It happens
all the time for objects whose lifecycle is "initialise at the start,
readonly afterwards", of which names, in particular in the form of
strings, are a large subset. It also happens in cases of late
deletion on refcounted objects, when the main owner (the one who is
allowed to change the object and has the non-const pointer) has
dropped its reference, but some object needs a readonly instance a
little longer. Think virtual files in proc, sysfs or friends kept
open after the underlying information source, often a device, is gone.OG.
--
Here's an idea. Think it through.
Why don't we need write permissions to a file to unlink it?
Here's a hint: because unlinking doesn't *write* to it. In fact, it
doesn't read from it either. It doesn't do any access at all to that
object, it just *removes* it.Is the file gone after you unlink it? Yes (modulo refcounting for aliasing
"pointers" aka filenames, but that's the same for any memory manager -
malloc/free just doesn't have any, so you could think of it as a
non-hardlinking filesystem).So you're the one who are speaking nonsense. Making something "not exist"
is not at all the same thing as accessing it for a write (or a read). It
is a metadata operation that doesn't conceptually change the data in any
way, shape or form - it just makes it go away.And btw, exactly as with kfree(), a unlink() may well do something like
"disk scrubbing" for security purposes, or cancel pending writes to the
backing store. But even though it may write (or, by undoing a pending
write, effectively "change the state") to the disk sectors that used to
contain the file data, ONLY AN IDIOT would call it "writing to the file".
Because "the file" is gone. Writing to the place where the file used to be
is a different thing.So give it up. You're wrong. Freeing a memory area is not "writing to it"
or accessing it in *any* manner, it's an operation on another level
entirely.Linus
--
You cannot unlink a file. Given a file, if you were to attempt to unlink it,
what directory would you remove it from?Unlinking a file is an operation on the directory the file is in, not on the
directory itself. We do need write permissions to the directory.If you had only a const pointer to the data in the file, you should
definitely not be able to use that pointer to find a directory the file is
in and remove it without clearly indicating you know *exactly* what you're
doing. Given just that 'const' pointer, you're not supposed to be modifying
the data and certainly using that pointer to modify anything logically aboveRight. It's an operation on the directory the file is in that might have
The file is gone if and only if the directory was the only thing that needed
the file to exist. A file that is only on one directory "belongs to" that
directory. So write permission to the directory is all that is needed.What you are arguing is essentially that you should be able to remove a file
from any directory it is in just because you have write access to the file'sI agree with you about that part. I can't understand why you keep thinking
this is where our disagreement lies when I've stated at least three times
that I agree about this. The issue has nothing to do with whether or not
'kfree' modifies the particular bytes pointed to. It has to do with whether
or not 'kfree' is the kind of operation one would normally want to allow onNevertheless, it's a modification operation on an object that's not supposed
to be modified.By the way, I did think of one argument that supports your position: Suppose
you have a reference counted object. You have a 'release reference and free
if zero' function. Should it be 'const'? If not, how can a 'lookup and
reference for read' function return a const pointer to the object?However, on balance, I think a 'release reference and free if zero' function
that operates on a const pointer is sufficiently unusual that a cast to show
you kn...
I don't think that kfree() itself changes the state of the object. It
doesn't call a destructor or anything like that, so the object itself
must be "inert" before the call to kfree(). That is, at the time of the
kfree() call the system must have ensured that the object will no longer
be used by anything.The call to kfree() is simply bookkeeping--allowing that memory to be
I have a certain amount of sympathy for this view...it's a fairly
painless way to reduce the likelihood of errors. At the same time, I
don't think I've ever run into this problem myself--is it really all
that common?Chris
--
