This is an archive of the discontinued LLVM Phabricator instance.

Warn on binding reference to null in copy initialization
ClosedPublic

Authored by nicholas on May 2 2016, 10:09 PM.

Details

Summary

The attached patch adds a warning when placing a call like:

func(*static_cast<mystruct*>(nullptr));

to the existing -Wnull-dereference warning.

The existing warning catches the case where the empty lvalue undergoes lvalue-to-rvalue conversion. The attached patch adds the check when it is used for copy initialization.

There's some significant opportunity for refactoring with the static CheckForNullPointerDereference function in SemaExpr.cpp (not to be confused with the one I'm adding to SemaInit.cpp). Also, I've chosen different warning text since all cases where the existing warning fires get compiled to nothing, while cases where this warning fires may generate object code (creating "null references" usually).

Please review!

Diff Detail

Event Timeline

nicholas updated this revision to Diff 55941.May 2 2016, 10:09 PM
nicholas retitled this revision from to Warn on binding reference to null in copy initialization.
nicholas updated this object.
nicholas added a reviewer: cfe-commits.
aaron.ballman added inline comments.
lib/Sema/SemaInit.cpp
3513

Can this take a const Expr * instead?

3632

const Expr * (or const auto *) instead?

test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
39

Missing > in the diagnostic text (I know it's not required, but it looks a bit strange if that's the only part missing from the diagnostic text).

nicholas marked 2 inline comments as done.May 4 2016, 12:16 AM

Richard Smith gave me some review feedback in person, the diagnostic should not be generated when setting up the Steps for the initializer sequence, but instead when InitializerSequence::Perform is called. This appears to work correctly and also catches a few more cases.

I did not expand this to SK_BindReferenceToTemporary, please review this decision. It's also missing missing bit-field and vector element checks that SK_BindReference has.

Also, I'd appreciate comments on the factoring with CheckForNullPointerDereference which was copied+pasted from SemaExpr.cpp. Please review this issue too, I did not expect to land the patch the way it's currently written.

test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
39

What follows lambda is the path to the file, then the closing )>. I'd rather not include that part. I could make it up with .* just to balance the parens, but I think that's not worth it.

nicholas updated this revision to Diff 56100.May 4 2016, 12:22 AM
aaron.ballman accepted this revision.May 4 2016, 12:11 PM
aaron.ballman edited edge metadata.

This generally LGTM, but you should wait for @rsmith to sign off before committing.

test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
39

Yeah, totally not worth it then. Thank you for the explanation.

This revision is now accepted and ready to land.May 4 2016, 12:11 PM
rsmith edited edge metadata.May 4 2016, 7:42 PM

I did not expand this to SK_BindReferenceToTemporary, please review this decision. It's also missing missing bit-field and vector element checks that SK_BindReference has.

That's fine. SK_BindReferenceToTemporary can never bind to a dereferenced null pointer.

lib/Sema/SemaInit.cpp
3514–3518

This comment doesn't make sense for this case. Binding a reference to a dereferenced null pointer isn't something that people would expect to trap. But the idea is the same: we might delete people's code and they're probably not expecting that.

3519–3522

It seems -- borderline -- worth factoring out these four lines between here and SemaExpr. Maybe isProvablyEmptyLvalue or similar, if you feel inclined to do so?

3523

I don't think we need to, or should, care whether the type is volatile-qualified here. The reference binding has undefined behavior either way. In SemaExpr we had this check because we wanted to warn people that we were going to delete their code, which we didn't do in the volatile case, but in this case we may delete the code even if it's a reference-to-volatile.

nicholas marked 2 inline comments as done.May 4 2016, 8:15 PM
nicholas added inline comments.
lib/Sema/SemaInit.cpp
3514–3518

We don't delete it, generally we "create a null reference" which is exactly what some programmers expect, when they think that references are just syntactically different pointers.

3519–3522

I'll pass. Initially I thought the two CheckForNullPointerDereference functions might be the same but for a diag::ID argument, but they're growing more and more different.

As for isProvablyEmptyLvalue we would still need to get the UO for the diagnostic anyways.

nicholas updated this revision to Diff 56235.May 4 2016, 8:15 PM
nicholas updated this revision to Diff 56236.
nicholas edited edge metadata.
nicholas marked an inline comment as done.

(Whoops, forgot to generate diff with full context for phab.)

nicholas updated this revision to Diff 56526.May 8 2016, 11:02 PM

Unsure why, but the previous diff didn't have the 'volatile' check removed.

rsmith accepted this revision.May 13 2016, 6:42 PM
rsmith edited edge metadata.
rsmith added inline comments.
include/clang/Basic/DiagnosticSemaKinds.td
5369

Maybe "binding dereferenced null pointer [...]"?

lib/Sema/SemaInit.cpp
6203

Something fishy in the indentation here?

nicholas closed this revision.May 14 2016, 10:50 AM

Closed by r269572.