News for hackers. Stuff that matters.
Re:Stop Memsetting Structures by Dylan16807 on Saturday April 27, 2019 @09:06PM (#19768669)
Technically I don't think memset forces the compiler to clear the padding and keep it clear either though. The magic of the C abstract machine.
Re:Stop Memsetting Structures by mehrdadn on Saturday April 27, 2019 @09:10PM (#19768679)
Why? memset followed by memcpy must return the same byte everywhere. Otherwise what would memset even mean?
Re:Stop Memsetting Structures by saagarjha on Saturday April 27, 2019 @10:57PM (#19769030)
I feel like accessing the bytes that correspond to padding might be implementation-defined, but I couldn't find this in the standard.
Re:Stop Memsetting Structures by DougBTX on Sunday April 28, 2019 @06:35AM (#19770363)
Parent comment was edited to include this quote:

_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 unspecified values. 51)_

So sure, a memcpy after a memset aught to preserve all the bytes, but if they are updated through a struct which contains padding then the values in the padding bytes will be left unspecified.

Re:Stop Memsetting Structures by mehrdadn on Saturday April 27, 2019 @11:03PM (#19769056)
I don't think it is. It wouldn't make sense since memcpy is basically supposed to convert between arbitrary binary data.
Re:Stop Memsetting Structures by saagarjha on Saturday April 27, 2019 @11:12PM (#19769092)
From a practical point of view, yes, but I would be very surprised if the C standard had any accommodation for memcpy being a way to leak the value of a structure's padding.
Re:Stop Memsetting Structures by jcr1488 on Sunday April 28, 2019 @05:23AM (#19770173)
You clearly haven't understood the thread.
Re:Stop Memsetting Structures by saagarjha on Sunday April 28, 2019 @05:26AM (#19770180)
How so? Did I miss something important?
Re:Stop Memsetting Structures by boulos on Saturday April 27, 2019 @09:13PM (#19768688)
Do you mean in the sense that a compiler can say "I know what memset is supposed to do" then decides that even though sizeof returns a particular size, that it might ignore that and set fewer bytes when it does a substitution for the memcpy call?
Re:Stop Memsetting Structures by Dylan16807 on Sunday April 28, 2019 @12:14AM (#19769311)
Yes. As long as the behavior observable by a conforming C program is the same, the compiler is allowed to change anything else.

Even if memset in a vacuum is guaranteed, look at the quote by anyfoo. "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 unspecified values."

If the compiler knows you're going to write to the members right after the memset, it can put the padding back to its previous values. And by that I mean as far as your code can tell it put it back, but in actuality it never zeroed the padding to begin with.

And since there are performance benefits to pretending, now you have a situation where a "helpful" compiler and a malicious compiler have the same effect: data can get leaked.

Re:Stop Memsetting Structures by jcr1488 on Sunday April 28, 2019 @11:04PM (#19775514)
As soon as a pointer to said memory is passed to an extern function in another translation unit, the compiler can't prove anything about how it's used, which is the case in pretty much all of the examples mentioned in this thread.

Also, type-punning is a thing. memset is byte-oriented/memory-oriented. Just because you're using it to zero a struct of a particular kind doesn't mean that's the only way the memory will accessed. Just because reading the padding of some struct is undefined behaviour doesn't mean accessing those bits by some other means is also undefined.

A compiler usually can't eliminate a call to memset() in most practical cases of initialization (where memory leakage is also a concern) because they almost always pass a reference to a routine in another translation unit. Something like memzero_explicit() can be used anyway -- but you're massively overstating the relevance of compilers eliminating dead stores done via memset(). It's much more of an issue for post-destruction memory sanitizing (which is the primary use case for memzero_explicit) than it is for compiler f*ckery when memset() is used for initialization.

Re:Stop Memsetting Structures by Dylan16807 on Sunday April 28, 2019 @11:40PM (#19775663)
> As soon as a pointer to said memory is passed to an extern function in another translation unit, the compiler can't prove anything about how it's used, which is the case in pretty much all of the examples mentioned in this thread.

You would have to call such a function between the memset and the first time you write to a member. Otherwise the compiler is allowed to say "I put the padding back, and you can't prove otherwise".

> Just because reading the padding of some struct is undefined behaviour doesn't mean accessing those bits by some other means is also undefined.

It's not always undefined, but it says very clearly that the value of padding becomes unspecified.

> they almost always pass a reference to a routine in another translation unit

> you're massively overstating the relevance of compilers eliminating dead stores done via memset

Unless inlining happened, or link-time optimization, or, or...

If the compiler zeroes the memory most of the time, that makes it even scarier. Because all your tests come back clean and safe, then four years later a macro changes and suddenly you're leaking data all over the place.

I don't think I'm overstating the relevance at all. Any security feature that could disappear because of a reasonable, trying-to-help optimization is one that should have a bright red warning label. And this is such a feature. It doesn't require a "sufficiently smart" compiler, and it doesn't require a malicious compiler. This is the kind of thing that can break by accident and ruin everyone's month.

Re:Stop Memsetting Structures by jcr1488 on Monday April 29, 2019 @03:18AM (#19776459)
> This is the kind of thing that can break by accident and ruin everyone's month.

Not in practice. Compilers make use of undefined behaviour to optimize things that are widely applicable and profitable. No real compiler does what you're saying and no future compiler is likely to without explicitly being asked to.

I agree that, by the letter of the spec, you're right, but you're still most certainly overstating the relevance.

I'm not arguing that this isn't a real problem or that people shouldn't use memzero_explicit() (or similar) where security is on the line, as I already said several times in another sub-thread -- I'm just saying that this kind of thing is extreme language-lawyering beyond the realms of probability. It's still not an excuse to be lax, but let's be realistic about the actual likelihood of it happening.

Re:Stop Memsetting Structures by Dylan16807 on Monday April 29, 2019 @04:00PM (#19782051)
It's just a type of dead store elimination. And objects are initialized so often that I could easily see it happening in the future. But I guess we'll just disagree on how likely it is.
Re:Stop Memsetting Structures by jcr1488 on Tuesday April 30, 2019 @03:16AM (#19785772)
> It's just a type of dead store elimination

It's not just any, typical kind of dead store elimination. It also would require other optimization passes that I can assure you no mainstream compiler actually does. You can disagree with me if you want, but you're simply wrong.

Re:Stop Memsetting Structures by Dylan16807 on Tuesday April 30, 2019 @07:34PM (#19793084)
Lots of mainstream compilers already have passes that check if every field in an object is definitely assigned. They use this to provide errors or warnings.

That step is 90% of the work. Once you can do that, it's straightforward to assess that every field is assigned after a memset, with no intervening reads, and then remove the memset.

Re:Stop Memsetting Structures by jcr1488 on Wednesday May 01, 2019 @08:38AM (#19796494)
> That step is 90% of the work

I spent several years working on a production grade compiler and I can assure you it's not. But keep just making things up off the top of your head if it makes you feel smart.

Re:Stop Memsetting Structures by Dylan16807 on Wednesday May 01, 2019 @06:02PM (#19802114)
Would you care to explain why?

Let's look at a basic common case, as a checklist.

1. All fields are definitely assigned.

2. No functions are called except intrisics.

3. Nothing reads from the object on any control path.

4. Memset happens between creation and first assignment.

We agreed that step 1 is a solved problem, right? Are any of 2-4 difficult? Did I miss any prerequisites for the optimization?

Once you can prove 1-4, isn't the optimization pass as simple as looking for memsets applied to structs, checking 1-4, then deleting the call?