Skip to content

Commit 376c28e

Browse files
committed
[ubsan] PR34266: When sanitizing the 'this' value for a member function that happens to be a lambda call operator, use the lambda's 'this' pointer, not the captured enclosing 'this' pointer (if any).
Do not sanitize the 'this' pointer of a member call operator for a lambda with no capture-default, since that call operator can legitimately be called with a null this pointer from the static invoker function. Any actual call with a null this pointer should still be caught in the caller (if it is being sanitized). This reinstates r311589 (reverted in r311680) with the above fix. llvm-svn: 311695
1 parent 6810765 commit 376c28e

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,10 @@ class CXXMethodDecl : public FunctionDecl {
20272027

20282028
/// \brief Returns the type of the \c this pointer.
20292029
///
2030-
/// Should only be called for instance (i.e., non-static) methods.
2030+
/// Should only be called for instance (i.e., non-static) methods. Note
2031+
/// that for the call operator of a lambda closure type, this returns the
2032+
/// desugared 'this' type (a pointer to the closure type), not the captured
2033+
/// 'this' type.
20312034
QualType getThisType(ASTContext &C) const;
20322035

20332036
unsigned getTypeQualifiers() const {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "CodeGenPGO.h"
2323
#include "TargetInfo.h"
2424
#include "clang/AST/ASTContext.h"
25+
#include "clang/AST/ASTLambda.h"
2526
#include "clang/AST/Decl.h"
2627
#include "clang/AST/DeclCXX.h"
2728
#include "clang/AST/StmtCXX.h"
@@ -1014,11 +1015,22 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
10141015
}
10151016

10161017
// Check the 'this' pointer once per function, if it's available.
1017-
if (CXXThisValue) {
1018+
if (CXXABIThisValue) {
10181019
SanitizerSet SkippedChecks;
10191020
SkippedChecks.set(SanitizerKind::ObjectSize, true);
10201021
QualType ThisTy = MD->getThisType(getContext());
1021-
EmitTypeCheck(TCK_Load, Loc, CXXThisValue, ThisTy,
1022+
1023+
// If this is the call operator of a lambda with no capture-default, it
1024+
// may have a static invoker function, which may call this operator with
1025+
// a null 'this' pointer.
1026+
if (isLambdaCallOperator(MD) &&
1027+
cast<CXXRecordDecl>(MD->getParent())->getLambdaCaptureDefault() ==
1028+
LCD_None)
1029+
SkippedChecks.set(SanitizerKind::Null, true);
1030+
1031+
EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
1032+
: TCK_MemberCall,
1033+
Loc, CXXABIThisValue, ThisTy,
10221034
getContext().getTypeAlignInChars(ThisTy->getPointeeType()),
10231035
SkippedChecks);
10241036
}

clang/test/CodeGenCXX/catch-undef-behavior.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,28 @@ void upcast_to_vbase() {
449449
}
450450
}
451451

452+
struct ThisAlign {
453+
void this_align_lambda();
454+
void this_align_lambda_2();
455+
};
456+
void ThisAlign::this_align_lambda() {
457+
// CHECK-LABEL: define {{.*}}@"_ZZN9ThisAlign17this_align_lambdaEvENK3$_0clEv"
458+
// CHECK-SAME: (%{{.*}}* %[[this:[^)]*]])
459+
// CHECK: %[[this_addr:.*]] = alloca
460+
// CHECK: store %{{.*}}* %[[this]], %{{.*}}** %[[this_addr]],
461+
// CHECK: %[[this_inner:.*]] = load %{{.*}}*, %{{.*}}** %[[this_addr]],
462+
// CHECK: %[[this_outer_addr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %[[this_inner]], i32 0, i32 0
463+
// CHECK: %[[this_outer:.*]] = load %{{.*}}*, %{{.*}}** %[[this_outer_addr]],
464+
//
465+
// CHECK: %[[this_inner_isnonnull:.*]] = icmp ne %{{.*}}* %[[this_inner]], null
466+
// CHECK: %[[this_inner_asint:.*]] = ptrtoint %{{.*}}* %[[this_inner]] to i
467+
// CHECK: %[[this_inner_misalignment:.*]] = and i{{32|64}} %[[this_inner_asint]], {{3|7}},
468+
// CHECK: %[[this_inner_isaligned:.*]] = icmp eq i{{32|64}} %[[this_inner_misalignment]], 0
469+
// CHECK: %[[this_inner_valid:.*]] = and i1 %[[this_inner_isnonnull]], %[[this_inner_isaligned]],
470+
// CHECK: br i1 %[[this_inner_valid:.*]]
471+
[&] { return this; } ();
472+
}
473+
452474
namespace CopyValueRepresentation {
453475
// CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_
454476
// CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
@@ -532,4 +554,18 @@ namespace CopyValueRepresentation {
532554
}
533555
}
534556

557+
void ThisAlign::this_align_lambda_2() {
558+
// CHECK-LABEL: define {{.*}}@"_ZZN9ThisAlign19this_align_lambda_2EvENK3$_1clEv"
559+
// CHECK-SAME: (%{{.*}}* %[[this:[^)]*]])
560+
// CHECK: %[[this_addr:.*]] = alloca
561+
// CHECK: store %{{.*}}* %[[this]], %{{.*}}** %[[this_addr]],
562+
// CHECK: %[[this_inner:.*]] = load %{{.*}}*, %{{.*}}** %[[this_addr]],
563+
//
564+
// Do not perform a null check on the 'this' pointer if the function might be
565+
// called from a static invoker.
566+
// CHECK-NOT: icmp ne %{{.*}}* %[[this_inner]], null
567+
auto *p = +[] {};
568+
p();
569+
}
570+
535571
// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }

0 commit comments

Comments
 (0)