Hi,
is there any reason why kfree() takes a const pointer just to degrade it
with the call to slab_free()/__cache_free() again? The promise that the
pointee is not modified is just bogus in this case, anyway, isn't it?Hannes
--
"const" has *never* been about the thing not being modified. Forget all
that claptrap. C does not have such a notion."const" is a pointer type issue, and is meant to make certain mis-uses
more visible at compile time. It has *no* other meaning, and anybody who
thinks it has is just setting himself up for problems.In the particular case of kfree(), the pointer argument *should* be const,
and the fact that the C library gets this wrong is not the kernels
problem, it's a problem with the C library.Why?
- From a very obvious and very *real* caller perspective, "free()" really
doesn't change the thing the pointer points to. It does something
totally different: it makes the *pointer* itself invalid.In other words, if you think that "kfree()" changed the thing you
free'd, you're simply wrong. It did no such thing. The memory is 100%
the same, it's just that you cannot access it any more, and if you try,
you'll get somebody elses memory.In other words, "kfree()" can be const.
- Anything that *can* take a const pointer should always do so.
Why? Because we want the types to be as tight as possible, and normal
code should need as few casts as possible.Here's a question for you: let's say that you have a structure that
has a member that is never changed. To make that obvious, and to allow
the compiler to warn about mis-use of a pointer, the structure should
look something likestruct mystruct {
const char *name;
..and let's look at what happens if the allocation of that const thing is
dynamic.The *correct* way to do that is:
char *name = kmalloc(...)
/* Fill it in */
snprintf(name, ...)
mystruct->name = name;and there are no casts anywhere, and you get exactly the semantics you
want: "name" itself isn't constant (it's obviously modified), but at
the same time the type system makes it very clear that trying to change
it through that mystruct member p...
This is where I disagree. If a struct has a constant pointer to it, then
the usage of that pointer by the struct should never modify it. If I
need to allocate memory for a name to a struct, I would not expect that
struct to ever free it.Let's use your example. I'll assume that the struct was created by some
constructor and the destructor freed it. I'd argue the correct way would
be to have the kfree with a typecast.Why?
- const pointers (especially strings) should be able to point to
static data. One thing that we would like to avoid is:mystruct->name = "myobj";
...
kfree(mystruct->name);- really, kfree should match kmalloc for types. What kmalloc returns
should be what kfree accepts. Passing in a const pointer to kfreechar *name = kmalloc(...);
...
mystruct->name = name; /* this is an implicit cast */So adding a cast to kfree isn't incorrect. C automatically casts
name to a const pointer, which means if we want to free it, thenOK, I think that kfree should not be const, but not because of the
explanation that you gave, but because of the C type system in general.kfree should match the kmalloc type. We don't declare
const void *kmalloc(...)
so we shouldn't do the same with kfree. If you assign a const pointer to
something from kmalloc, C implicitly does the cast. This doesn't mean
that we should ignore doing the cast back in kfree. Especially since
this could help us avoid the kfree("mystring") issue.Just my $0.02
-- Steve
--
Hi,
Linus Torvalds <torvalds@linux-foundation.org> writes:
Okay, I understood that now. A const qualifier just forbids modifying
the underlying memory _through this particular pointer_, right?In the case of slub's kfree(), which takes a const pointer, you pass it
on to slab_free() which actually _DOES_ modification of the underlying
memory when linking the object to the freelist (as far as I understood
the code).So if I got it right and you actually modify the memory you only got a
const pointer to, you reach a level where you _have to_ break this
policy and cast to a non-const pointer, as it is currently done in
kfree(). No?Hannes
--
First off, the whole concept of "underlying memory" is all about the fact
that pointers point not to separate objects with its own existence, but
point to a shared resource ("memory") that can be accessed many different
ways.So immediately when you talk about "underlying memory", you need to
realize that now you're not talking about "that pointer" any more, but you
are talking about the stuff that *other* pointers can access.And the whole (and *only*) point of a memory allocator is turning that
amorphous notion of "infinitely aliasable underlying memory" model into
more of a "C pointer to separate objects" model.No. YOU DO NOT.
You *invalidate* the pointer. Then, the memory allocator releases that
portion of the "infinitely aliasable underlying memory", but that means
that THAT POINTER NO LONGER EXISTS ON A C LEVEL.So no, you don't "modify the memory you only got a const pointer to".
What you do is that the memory allocator
- keeps track of the NON-const memory that it always had
- it sees the const pointer you gave it, and uses that pointer to look up
ITS OWN DATA STRUCTURES.
- it then accesses those memory locations using its own pointers.The "const pointer" you passed to kfree() simply no longer exists. The
object it pointed to has gone away. That particular pointer simply isn't
valid any more.But the memory management code, which maintains its own structures for
what it has allocated and not allocated, can (and will) generally use the
knowledge *it* has about its own pointers to modify its own data
structures.The fact that they (obviously) alias in memory is irrelevant. It has no
meaning for the "const void *" you passed in. That pointer is not usable
for the caller any more.And no, this is not just a semantic argument. It's a real issue. The
pointer you pass in to kfree() is obviously used to *find* the data
structures that the memory allocator maintains, and there is almost
inevitably a rather direct mapping ...
Correct and we have gcc 4.2 currently spitting out warnings because of
casting to non const. Any idea how to convince gcc that this is okay?--
Either don't use a broken compiler (casting a const pointer to a non-const
is definitely not a bug), or cast to "unsigned long" (if it still
complains, now the compiler is not just stupid, it's broken).The whole point of memory management is that we know how pointers work,
and understand that they have a *bit* representation, not just the C
semantics.Linus
--
Hi,
Just for the record, this really seems to be a gcc bug, I can not
explain this otherwise:$ cat test.c
#include <stdio.h>static void test(void *p)
{
char *v = p;
puts(v);
}int main(void)
{
const char foo[] = "foo";
test((void *)foo);
return 0;
}
$ gcc -Wall test.c -o test
$ gcc -Wall -O test.c -o test
test.c: In function 'main':
test.c:12: warning: passing argument 1 of 'test' discards qualifiers from pointer target type
$ gcc -Wall -O -fno-inline test.c -o test
$gcc is version 4.2.2.
Hannes
--
Hi,
Two dirty hacks where gcc at least does not complain:
void *y = (void *)x;
and then pass y, or passing
*(void **)&x
directly.
Both approaches seem just too ugly to silence a bogus warning.
Hannes
--
The object is modified in various cases f.e. because of poisoning or the
need to store the free pointer. So its bogus, yes. Pekka?--
Hi,
Yeah, bogus, and has been that way for a long time according to git. I'm
ok with removing that (which would make it consistent with the user-space
equivalent free(3) function btw).Pekka
--
Technically one should be able to pass a "const $type *" (which may
have been a "non-const $type *" before but at some point in time it
became "const $type *") to kfree().The (formerly) constant contents as such vanishes IMHO (and it is not
really "modified").
Poisoning and free memory handling is IMHO internal stuff to the free
memory management subsystem and basically unrelated to the "life" of the
pointered contents before it's death with kfree().Bernd
--
Firmix Software GmbH http://www.firmix.at/
mobil: +43 664 4416156 fax: +43 1 7890849-55
Embedded Linux Development and Services--
| Greg Kroah-Hartman | [PATCH 006/196] Chinese: add translation of oops-tracing.txt |
| Jan Engelhardt | intel iommu (Re: -mm merge plans for 2.6.23) |
| James Bottomley | Re: Integration of SCST in the mainstream Linux kernel |
| Borislav Petkov | 2.6.23-rc1: no setup signature found... |
git: | |
| Gerrit Renker | [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side) |
| David Miller | [GIT]: Networking |
| David Miller | Re: [PATCH] pkt_sched: Destroy gen estimators under rtnl_lock(). |
| David Miller | Re: [BUG] New Kernel Bugs |
