This is an archive of the discontinued LLVM Phabricator instance.

[UBSan] Strengthen pointer checks in 'new' expressions
ClosedPublic

Authored by sepavloff on Jul 19 2018, 10:24 PM.

Details

Summary

With this change compiler generates alignment checks for wider range
of types. Previously such checks were generated only for the record types
with non-trivial default constructor. So the types like:

struct alignas(32) S2 { int x; };
typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;

did not get checks when allocated by 'new' expression.

This change also optimizes the checks generated for the arrays created
in 'new' expressions. Previously the check was generated for each
invocation of type constructor. Now the check is generated only once
for entire array.

Diff Detail

Repository
rL LLVM

Event Timeline

sepavloff created this revision.Jul 19 2018, 10:24 PM

You may want to add a test for placement new, no?

rjmccall added inline comments.Jul 21 2018, 12:33 PM
lib/CodeGen/CodeGenFunction.h
380 ↗(On Diff #156428)

I don't think this is a good way of doing this. Using global state makes this unnecessarily difficult to reason about and can have unintended effects. For example, you are unintentionally suppressing any checks that would be done as part of e.g. evaluating default arguments to the default constructor.

You should pass a parameter down that says whether checks are necessary. You can also use that parameter to e.g. suppress checks when constructing local variables and temporaries, although you may already have an alternative mechanism for doing that.

Did you consider dividing the patch into two separate changes to solve the two described issues independently?

Did you consider dividing the patch into two separate changes to solve the two described issues independently?

The both tow issues have the same cause: the check is genereated too late. Now it is generated during contructor generation. For arrays it means that every array element gets its own check. For types like vectors with required alignment it means no check at all, because technically such type do not have a constructor. If the check is generated earlier, while processing 'new' expression, both the problems are solved. But in this case we need to inform EmitCXXConstructorCall that the checks are already generated, because this function may be called in cases other than 'new' expression.

Updated patch

  • Modified check generation. Now for each 'new' expression compiler tries to

generate the checks. It solves problem of 'nested' new expressions, which
appear when 'new' is used in default arguments.

  • Field and RAII class names are made more specific.
  • Added new tests including that with inplace new operator.
sepavloff added inline comments.Jul 24 2018, 12:25 PM
lib/CodeGen/CodeGenFunction.h
380 ↗(On Diff #156428)

Passing parameter that inctructs whether to generate checks or not hardly can be directly implemented. This information is used in EmitCXXConstructorCall and it is formed during processing of new expression. The distance between these points can be 10 call frames, in some of them (StmtVisitor interface of AggExprEmitter) we cannot change function parameters.
The case of new expression in default arguments indeed handled incorrectly, thank you for the catch. The updated version must process this case correctly.

rjmccall added inline comments.Jul 24 2018, 2:06 PM
lib/CodeGen/CodeGenFunction.h
380 ↗(On Diff #156428)

I'm not going to accept a patch based on global state here. AggValueSlot already propagates a bunch of flags about the slot into which we're emitting an expression; I don't think it would be difficult to propagate some sort of "alignment is statically known or already checked" flag along with that.

vsk added a subscriber: vsk.Jul 24 2018, 3:10 PM
vsk added inline comments.
lib/CodeGen/CodeGenFunction.h
380 ↗(On Diff #156428)

+ 1. @rjmccall offered similar advice in D25448, which led us to find a few more bugs / missed opportunities we otherwise wouldn't have.

Updated patch

Now the information, if the pointer produced by 'new' operator is checked,
is stored in objects used for pointer representation (Address and
AggValueSlot) rather than globally.

Also the tests were cleaned up a bit.

rjmccall added inline comments.Jul 25 2018, 10:40 AM
lib/CodeGen/Address.h
46 ↗(On Diff #157305)

Address is a pretty low-level type to be changing here. Is this necessary? Can you find a way to propagate this just in higher-level types like AggValueSlot, RValue, and LValue?

Also, please remember that your analysis is not the only thing happening in the compiler. isChecked is not a meaningful name taken out of context.

Updated patch

Now information, if sanitizer checks are generated while processing 'new'
expression, is passed through function call arguments.

Also, please remember that your analysis is not the only thing happening in the compiler. isChecked is not a meaningful name taken out of context.

Address is not modified in the current patch version. As for AggValueSlot, this method name is leaved, as there is no other meaning for this class. Please let me know if it is inappropriate.

rjmccall added inline comments.Jul 26 2018, 12:38 PM
lib/CodeGen/CGClass.cpp
2190 ↗(On Diff #157519)

Please include /* */ comments to describe what true and false mean as arguments throughout this patch, just like the /*Delegating*/ comment here.

lib/CodeGen/CGValue.h
487 ↗(On Diff #157519)

Are those checks anything more than pointer alignment? If so, please call this
(and all the methods for it) SanitizerCheckedFlag; otherwise, please just call it
AlignmentCheckedFlag.

sepavloff updated this revision to Diff 157643.Jul 26 2018, 9:50 PM

Updated patch

Added names for boolean arguments, renamed a field in AggValueSlot.
No functional changes.

Okay, thank you, that's better, but I should've been clearer. What I was really asking for was this: in *all* the code you're adding in this patch, where you've currently written IsChecked or isChecked or NewPointerIsChecked, please instead write IsSanitizerChecked or isSanitizerChecked or NewPointerIsSanitizerChecked unless it is literally something like a local variable in a function about performing sanitizer checks.

sepavloff updated this revision to Diff 157677.Jul 27 2018, 6:05 AM

Updated patch

Use SanitizerCheck instead of Check in method and enum names.
No functional changes.

rjmccall accepted this revision.Jul 27 2018, 10:13 AM

Thanks, that'll do.

This revision is now accepted and ready to land.Jul 27 2018, 10:13 AM
This revision was automatically updated to reflect the committed changes.