Not logged in
Log in now
Create an account
Subscribe to LWN
LWN.net Weekly Edition for May 16, 2013
A look at the PyPy 2.0 release
PostgreSQL 9.3 beta: Federated databases and more
LWN.net Weekly Edition for May 9, 2013
(Nearly) full tickless operation in 3.10
Object-oriented design patterns in the kernel, part 1
Posted Jun 1, 2011 18:31 UTC (Wed) by juliank (subscriber, #45896)
19 The initialization shall occur in
initializer list order,each initializer provided for a
particular subobject overriding any previously listed
initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
Posted Jun 1, 2011 20:15 UTC (Wed) by arjan (subscriber, #36785)
Posted Jun 1, 2011 21:15 UTC (Wed) by pr1268 (subscriber, #24648)
Interesting... Just curious, has this been observed thus far? If so, has it been addressed (patch, git commit, etc.)?
Based on the standard, I'm unsure whether the padding you mention needs to be initialized. Assuming it does, then is the leaked stack data a compiler bug? Or, if it doesn't, then does this fall into the category of "making the compiler more efficient"?
Posted Jun 2, 2011 0:26 UTC (Thu) by elanthis (guest, #6227)
It's not a compiler bug by any means. It's correct, normal, expected behavior. There's no reason to initialize padding space in most circumstances, and doing so is just a loss of efficiency for no gain for those overwhelmingly common cases.
The only cases where this ever comes up as a problem are in security contexts (e.g. kernel stack data leakage) and when you're trying to do "undefined" operations like hashing a chunk of memory representing a struct. In the former case, you should be more careful and explicitly zero out memory via memset or calloc (or equivalent APIs) which you need to do anything for just about every other data structure you use so it's not a big deal, and in the later case you should be beaten with a stick until you stop doing such stupid things. :)
Posted Jun 2, 2011 0:39 UTC (Thu) by foom (subscriber, #14868)
Furthermore, gcc emits *terrible* code when explicitly initializing a bunch of integer members to 0 (especially where some of them are bitfields). My solution was to make a parent class call bzero to clear out sizeof(*this), and not explicitly initialize any of the initially-zero integer members. Made faster code *and* didn't have any padding issues. (But now someone's probably going to tell me that doing that is undefined and that gcc 4.8's optimizer is going to decide to transform my app into nethack, because I invoked some undefined behavior).
Posted Jun 2, 2011 13:48 UTC (Thu) by cesarb (subscriber, #6266)
That is, I believe what you are doing is safe only if:
- All the integer and bitfield members (and only them) are in the parent class;
- The parent class is zeroing only itself (that is, it is doing the sizeof(*this) itself, instead of being passed that value by the child class);
- The parent class has no virtual member functions or anything else that could make the compiler add C++ magic to it.
That said, I am no language lawyer, and would not be surprised if several clauses scattered all over the standard combine to say that even then you are still doing something undefined.
Why not move all these variables into a plain C-style struct, add it to your object as a member, and zero it on the constructor? That way sounds much safer to me, and I doubt the C++ standard would break it (since breaking it would break compatibility with C).
Posted Jun 3, 2011 11:20 UTC (Fri) by liljencrantz (subscriber, #28458)
Posted Jun 3, 2011 13:51 UTC (Fri) by sethml (subscriber, #8471)
I've written this bug in C++ (memset(this, 0, sizeof(*this))) - clobbering your vtable pointer is pretty annoying to debug. My horrible hacky fix was just to zero the data portion of the class: memset(&firstMember, 0, (char *)(&lastMember + 1) - (char *)&firstMember)
Posted Jun 4, 2011 10:11 UTC (Sat) by liljencrantz (subscriber, #28458)
Posted Jun 2, 2011 17:49 UTC (Thu) by marcH (subscriber, #57642)
Performance over security: a very important design choice of C, one to keep in mind at all times. One carried over to C++. One responsible for zillions of security flaws written by thousands of programmers who should rather have used another, safer language (or stayed in bed).
Posted Jun 2, 2011 9:25 UTC (Thu) by juliank (subscriber, #45896)
6 When a value is stored in an object of structure or union type, including in a member
object, the bytes of the object representation that correspond to any padding bytes take
Posted Jun 2, 2011 17:49 UTC (Thu) by jwakely (subscriber, #60262)
> Check commit 1c40be12f7d8ca1d387510d39787b12e512a7ce8 for an example
> (net sched: fix some kernel memory leaks)
Posted Jun 2, 2011 13:05 UTC (Thu) by pixelbeat (guest, #7440)
I previously did some analysis to verify.
Posted Jun 2, 2011 13:08 UTC (Thu) by juliank (subscriber, #45896)
Posted Jun 2, 2011 14:30 UTC (Thu) by pixelbeat (guest, #7440)
Posted Jun 2, 2011 16:19 UTC (Thu) by juliank (subscriber, #45896)
> I'd be very interested if there was a counter example in the wild
Posted Jun 3, 2011 1:59 UTC (Fri) by pixelbeat (guest, #7440)
They concur with my testing I think.
I.E. only in the case where all members are specified
in the initializer list, is the padding not zeroed.
Posted Jun 2, 2011 18:00 UTC (Thu) by nix (subscriber, #2304)
Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds