lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 16 Jan 2008 10:39:00 -0800 (PST)
From:	Linus Torvalds <torvalds@...ux-foundation.org>
To:	Johannes Weiner <hannes@...urebad.de>
cc:	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
	clameter@....com, penberg@...helsinki.fi
Subject: Re: Why is the kfree() argument const?



On Wed, 16 Jan 2008, Johannes Weiner wrote:
> 
> 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?

"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 like

		struct 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 pointer is wrong.

   How do you free it?

   That's right, you do:

		kfree(mystruct->name);

   and this is why "kfree()" should take a const pointer. If it doesn't, 
   you have to add an *incorrect* and totally useless cast to code that 
   was correct.

So never believe that "const" is some guarantee that the memory under the 
pointer doesn't change.  That is *never* true. It has never been true in 
C, since there can be arbitrary pointer aliases to that memory that aren't 
actually const. If you think "const *p" means that the memory behind "p" 
is immutable, you're simply wrong.

Anybody who thinks that kfree() cannot (or should not) be const doesn't 
understand the C type system.

			Linus
--
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ