Skip to content

Commit 4ece510

Browse files
Merge branch 'master' of github.com:microsoft/checkedc-clang into merge-from-microsoft-20210908
2 parents 07c5311 + 82b7208 commit 4ece510

22 files changed

+2221
-233
lines changed

clang/include/clang/AST/ExprUtils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ class ExprUtil {
145145
// pointer). Returns false if E is nullptr.
146146
static bool ReadsMemoryViaPointer(Expr *E, bool IncludeAllMemberExprs = false);
147147

148+
// IsDereferenceOrSubscript returns true if the expression e is a pointer
149+
// dereference *e1 or an array subscript expression e1[e2].
150+
static bool IsDereferenceOrSubscript(Expr *E);
151+
152+
// IsReturnValueExpr return true if the expression E is a _Return_value
153+
// expression.
154+
static bool IsReturnValueExpr(Expr *E);
155+
148156
// FindLValue returns true if the given lvalue expression occurs in E.
149157
static bool FindLValue(Sema &S, Expr *LValue, Expr *E);
150158

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11386,6 +11386,10 @@ def err_bounds_type_annotation_lost_checking : Error<
1138611386
"argument has unknown bounds, bounds expected because the "
1138711387
"%ordinal0 parameter has bounds">;
1138811388

11389+
def err_expected_bounds_for_return : Error<
11390+
"return value has unknown bounds, bounds expected because the "
11391+
"function %0 has bounds">;
11392+
1138911393
def err_initializer_expected_with_bounds : Error<
1139011394
"automatic variable %0 with bounds must have initializer">;
1139111395

@@ -11507,7 +11511,7 @@ def err_bounds_type_annotation_lost_checking : Error<
1150711511
"variable arguments function cannot be made in a checked scope">;
1150811512

1150911513
def err_checked_scope_no_variadic_func_for_expression : Error<
11510-
"cannot use a variable arguments function in a checked scope or function">;
11514+
"cannot use this variable arguments function in a checked scope or function">;
1151111515

1151211516
def err_checked_scope_no_assume_bounds_casting : Error<
1151311517
"_Assume_bounds_cast not allowed in a checked scope or function">;
@@ -11520,6 +11524,12 @@ def err_bounds_type_annotation_lost_checking : Error<
1152011524
"%select{'_Unchecked'|'_Checked _Bounds_only|'_Checked'}0 "
1152111525
"can only appear on functions">;
1152211526

11527+
def err_checked_scope_invalid_format_specifier_argument : Error<
11528+
"in a checked scope %0 format specifier requires %1 argument">;
11529+
11530+
def err_checked_scope_scanf_width : Error<
11531+
"in a checked scope width is not allowed with format specifier in scanf">;
11532+
1152311533
def err_pragma_pop_checked_scope_mismatch : Error<
1152411534
"#pragma CHECKED_SCOPE pop with no matching #pragma CHECKED_SCOPE push">;
1152511535

@@ -11619,8 +11629,32 @@ def err_bounds_type_annotation_lost_checking : Error<
1161911629
def error_static_cast_bounds_invalid : Error<
1162011630
"cast source bounds are too narrow for %0">;
1162111631

11632+
def error_modified_return_bounds : Error<
11633+
"modified expression '%0' used in the declared return bounds for %1">;
11634+
11635+
def error_return_bounds_invalid : Error<
11636+
"return value bounds do not imply declared return bounds for %0">;
11637+
11638+
def error_return_bounds_unprovable: Error<
11639+
"it is not possible to prove that return value bounds "
11640+
"imply declared return bounds for %0">;
11641+
11642+
def warn_return_bounds_invalid: Warning<
11643+
"cannot prove return value bounds imply declared return bounds for %0">,
11644+
InGroup<CheckBoundsDeclsUnchecked>;
11645+
11646+
def warn_checked_scope_return_bounds_invalid : Warning<
11647+
"cannot prove return value bounds imply declared return bounds for %0">,
11648+
InGroup<CheckBoundsDeclsChecked>;
11649+
11650+
def note_declared_return_bounds : Note<
11651+
"(expanded) declared return bounds are '%0'">;
11652+
11653+
def note_inferred_return_bounds : Note<
11654+
"(expanded) inferred return value bounds are '%0'">;
11655+
1162211656
def error_out_of_bounds_access : Error<
11623-
"out-of-bounds %select{||memory access|base value}0">;
11657+
"out-of-bounds %select{|||memory access|base value}0">;
1162411658

1162511659
def note_source_bounds_empty : Note<"source bounds are an empty range">;
1162611660

@@ -11631,21 +11665,22 @@ def err_bounds_type_annotation_lost_checking : Error<
1163111665
def note_destination_bounds_invalid : Note<"destination bounds are an invalid range">;
1163211666

1163311667
def note_bounds_too_narrow : Note<
11634-
"%select{destination bounds are|target bounds are|memory accessed is|"
11635-
"struct/union pointed to by base is}0 wider than the "
11636-
"%select{source|source||}0 bounds">;
11668+
"%select{destination bounds are|target bounds are|declared return bounds are|"
11669+
"memory accessed is|struct/union pointed to by base is|}0 wider "
11670+
"than the %select{source|source|return value|source|source}0 bounds">;
1163711671

1163811672
def note_lower_out_of_bounds : Note<
11639-
"%select{destination lower bound is|target lower bound is|accesses memory|"
11640-
"base value is}0 below %select{source|source|the|its}0 lower bound">;
11673+
"%select{destination lower bound is|target lower bound is|"
11674+
"declared return lower bound is|accesses memory|base value is}0 "
11675+
"below %select{source|source|return value|the|its}0 lower bound">;
1164111676

1164211677
def note_upper_out_of_bounds : Note<
1164311678
"%select{destination upper bound is|target upper bound is|"
11644-
"accesses memory at or|base value is}0 "
11645-
"above %select{source|source|the|its}0 upper bound">;
11679+
"declared return upper bound is|accesses memory at or|base value is}0 "
11680+
"above %select{source|source|return value|the|its}0 upper bound">;
1164611681

1164711682
def note_bounds_partially_overlap : Note<
11648-
"%select{||accesses memory that|struct/union pointed to by base value}0 is "
11683+
"%select{|||accesses memory that|struct/union pointed to by base value}0 is "
1164911684
"only partially in bounds">;
1165011685

1165111686
def no_prototype_generic_function : Error<
@@ -11680,5 +11715,75 @@ def err_bounds_type_annotation_lost_checking : Error<
1168011715
def err_expanding_cycle : Error<
1168111716
"expanding cycle in struct definition">;
1168211717

11718+
// -Wformat warnings issued as errors in checked scope.
11719+
def err_format_nonliteral_noargs : Error<
11720+
"format string is not a string literal (potentially insecure)">;
11721+
def err_format_nonliteral : Error<
11722+
"format string is not a string literal">;
11723+
def err_printf_insufficient_data_args : Error<
11724+
"more '%%' conversions than data arguments">;
11725+
def err_printf_data_arg_not_used : Error<
11726+
"data argument not used by format string">;
11727+
def err_format_invalid_conversion : Error<
11728+
"invalid conversion specifier '%0'">;
11729+
def err_printf_incomplete_specifier : Error<
11730+
"incomplete format specifier">;
11731+
def err_missing_format_string : Error<
11732+
"format string missing">;
11733+
def err_scanf_nonzero_width : Error<
11734+
"zero field width in scanf format string is unused">;
11735+
def err_format_conversion_argument_type_mismatch : Error<
11736+
"format specifies type %0 but the argument has "
11737+
"%select{type|underlying type}2 %1">;
11738+
def err_format_conversion_argument_type_mismatch_pedantic : Error<
11739+
err_format_conversion_argument_type_mismatch.Text>;
11740+
def err_format_conversion_argument_type_mismatch_confusion : Error<
11741+
err_format_conversion_argument_type_mismatch.Text>;
11742+
def err_format_argument_needs_cast : Error<
11743+
"%select{values of type|enum values with underlying type}2 '%0' should not "
11744+
"be used as format arguments; add an explicit cast to %1 instead">;
11745+
def err_format_argument_needs_cast_pedantic : Error<
11746+
err_format_argument_needs_cast.Text>;
11747+
def err_printf_positional_arg_exceeds_data_args : Error <
11748+
"data argument position '%0' exceeds the number of data arguments (%1)">;
11749+
def err_format_invalid_positional_specifier : Error<
11750+
"invalid position specified for %select{field width|field precision}0">;
11751+
def err_format_mix_positional_nonpositional_args : Error<
11752+
"cannot mix positional and non-positional arguments in format string">;
11753+
def err_empty_format_string : Error<
11754+
"format string is empty">;
11755+
def err_format_string_is_wide_literal : Error<
11756+
"format string should not be a wide string">;
11757+
def err_printf_format_string_contains_null_char : Error<
11758+
"format string contains '\\0' within the string body">;
11759+
def err_printf_format_string_not_null_terminated : Error<
11760+
"format string is not null-terminated">;
11761+
def err_printf_asterisk_missing_arg : Error<
11762+
"'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">;
11763+
def err_printf_asterisk_wrong_type : Error<
11764+
"field %select{width|precision}0 should have type %1, but argument has type %2">;
11765+
def err_printf_nonsensical_optional_amount: Error<
11766+
"%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">;
11767+
def err_printf_nonsensical_flag: Error<
11768+
"flag '%0' results in undefined behavior with '%1' conversion specifier">;
11769+
def err_format_nonsensical_length: Error<
11770+
"length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">;
11771+
def err_format_non_standard_positional_arg: Error<
11772+
"positional arguments are not supported by ISO C">;
11773+
def err_format_non_standard: Error<
11774+
"'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">;
11775+
def err_format_non_standard_conversion_spec: Error<
11776+
"using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">;
11777+
def err_format_invalid_annotation : Error<
11778+
"using '%0' format specifier annotation outside of os_log()/os_trace()">;
11779+
def err_format_P_no_precision : Error<
11780+
"using '%%P' format specifier without precision">;
11781+
def err_printf_ignored_flag: Error<
11782+
"flag '%0' is ignored when flag '%1' is present">;
11783+
def err_scanf_scanlist_incomplete : Error<
11784+
"no closing ']' for '%%[' in scanf format string">;
11785+
def err_format_bool_as_character : Error<
11786+
"using '%0' format specifier, but argument has boolean value">;
11787+
1168311788
} // end of Checked C Category
1168411789
} // end of sema component.

clang/lib/AST/ExprUtils.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,25 @@ bool ExprUtil::ReadsMemoryViaPointer(Expr *E, bool IncludeAllMemberExprs) {
306306
}
307307
}
308308

309+
bool ExprUtil::IsDereferenceOrSubscript(Expr *E) {
310+
if (!E)
311+
return false;
312+
E = E->IgnoreParens();
313+
if (isa<ArraySubscriptExpr>(E))
314+
return true;
315+
UnaryOperator *UO = dyn_cast<UnaryOperator>(E);
316+
if (!UO)
317+
return false;
318+
return UO->getOpcode() == UnaryOperatorKind::UO_Deref;
319+
}
320+
321+
bool ExprUtil::IsReturnValueExpr(Expr *E) {
322+
BoundsValueExpr *BVE = dyn_cast_or_null<BoundsValueExpr>(E);
323+
if (!BVE)
324+
return false;
325+
return BVE->getKind() == BoundsValueExpr::Kind::Return;
326+
}
327+
309328
namespace {
310329
class FindLValueHelper : public RecursiveASTVisitor<FindLValueHelper> {
311330
private:
@@ -341,6 +360,22 @@ namespace {
341360
return true;
342361
}
343362

363+
bool VisitUnaryOperator(UnaryOperator *E) {
364+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
365+
return true;
366+
if (Lex.CompareExprSemantically(E, LValue))
367+
Found = true;
368+
return true;
369+
}
370+
371+
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
372+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
373+
return true;
374+
if (Lex.CompareExprSemantically(E, LValue))
375+
Found = true;
376+
return true;
377+
}
378+
344379
// Do not traverse the child of a BoundsValueExpr.
345380
// Expressions within a BoundsValueExpr should not be considered
346381
// when looking for LValue.
@@ -430,6 +465,22 @@ namespace {
430465
return true;
431466
}
432467

468+
bool VisitUnaryOperator(UnaryOperator *E) {
469+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
470+
return true;
471+
if (Lex.CompareExprSemantically(E, LValue))
472+
++Count;
473+
return true;
474+
}
475+
476+
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
477+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
478+
return true;
479+
if (Lex.CompareExprSemantically(E, LValue))
480+
++Count;
481+
return true;
482+
}
483+
433484
// Do not traverse the child of a BoundsValueExpr.
434485
// If a BoundsValueExpr uses the expression LValue (or a variable whose
435486
// declaration matches V), this should not count toward the total

clang/lib/AST/PreorderAST.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,14 @@ void PreorderAST::CreateUnaryOperator(UnaryOperator *E, Node *Parent) {
168168
}
169169

170170
void PreorderAST::CreateArraySubscript(ArraySubscriptExpr *E, Node *Parent) {
171-
// e1[e2] has the same canonical form as *(e1 + e2).
171+
// e1[e2] has the same canonical form as *(e1 + e2 + 0).
172172
auto *DerefExpr = BinaryOperator::Create(Ctx, E->getBase(), E->getIdx(),
173173
BinaryOperatorKind::BO_Add, E->getType(),
174174
E->getValueKind(), E->getObjectKind(),
175175
E->getExprLoc(), FPOptionsOverride());
176176
auto *N = new UnaryOperatorNode(UnaryOperatorKind::UO_Deref, Parent);
177177
AttachNode(N, Parent);
178-
Create(DerefExpr, N);
178+
AddZero(DerefExpr, N);
179179
}
180180

181181
void PreorderAST::CreateMember(MemberExpr *E, Node *Parent) {

clang/lib/Sema/BoundsUtils.cpp

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ BoundsExpr *BoundsUtil::ExpandToRange(Sema &S, VarDecl *D, BoundsExpr *B) {
186186
BoundsExpr *BoundsUtil::ReplaceLValueInBounds(Sema &S, BoundsExpr *Bounds,
187187
Expr *LValue, Expr *OriginalValue,
188188
CheckedScopeSpecifier CSS) {
189+
if (Bounds->isUnknown() || Bounds->isAny())
190+
return Bounds;
189191
Expr *Replaced = ReplaceLValue(S, Bounds, LValue, OriginalValue, CSS);
190192
if (!Replaced)
191193
return CreateBoundsUnknown(S);
@@ -223,10 +225,9 @@ namespace {
223225
if (Lex.CompareExpr(V, E) == Lexicographic::Result::Equal) {
224226
if (OriginalValue)
225227
return OriginalValue;
226-
else
227-
return ExprError();
228-
} else
229-
return E;
228+
return ExprError();
229+
}
230+
return E;
230231
}
231232

232233
ExprResult TransformMemberExpr(MemberExpr *E) {
@@ -236,34 +237,56 @@ namespace {
236237
if (Lex.CompareExprSemantically(M, E)) {
237238
if (OriginalValue)
238239
return OriginalValue;
239-
else
240-
return ExprError();
241-
} else
240+
return ExprError();
241+
}
242+
return E;
243+
}
244+
245+
ExprResult TransformUnaryOperator(UnaryOperator *E) {
246+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
242247
return E;
248+
if (Lex.CompareExprSemantically(LValue, E)) {
249+
if (OriginalValue)
250+
return OriginalValue;
251+
return ExprError();
252+
}
253+
return E;
254+
}
255+
256+
ExprResult TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
257+
if (!ExprUtil::IsDereferenceOrSubscript(LValue))
258+
return E;
259+
if (Lex.CompareExprSemantically(LValue, E)) {
260+
if (OriginalValue)
261+
return OriginalValue;
262+
return ExprError();
263+
}
264+
return E;
243265
}
244266

245267
// Overriding TransformImplicitCastExpr is necessary since TreeTransform
246268
// does not preserve implicit casts.
247269
ExprResult TransformImplicitCastExpr(ImplicitCastExpr *E) {
248-
// Replace V with OV (if applicable) in the subexpression of E.
270+
// Replace LValue with OriginalValue (if applicable) in the
271+
// subexpression of E.
249272
ExprResult ChildResult = TransformExpr(E->getSubExpr());
250273
if (ChildResult.isInvalid())
251274
return ChildResult;
252275

253276
Expr *Child = ChildResult.get();
254277
CastKind CK = E->getCastKind();
255278

279+
// Only cast children of lvalue to rvalue or array to pointer casts
280+
// to an rvalue if necessary. The transformed child expression may
281+
// no longer be an lvalue, depending on the original value.
282+
// For example, if x is transformed to the original value x + 1, it
283+
// does not need to be cast to an rvalue.
256284
if (CK == CastKind::CK_LValueToRValue ||
257285
CK == CastKind::CK_ArrayToPointerDecay)
258-
// Only cast children of lvalue to rvalue casts to an rvalue if
259-
// necessary. The transformed child expression may no longer be
260-
// an lvalue, depending on the original value. For example, if x
261-
// is transformed to the original value x + 1, it does not need to
262-
// be cast to an rvalue.
263286
return ExprCreatorUtil::EnsureRValue(SemaRef, Child);
264-
else
265-
return ExprCreatorUtil::CreateImplicitCast(SemaRef, Child,
266-
CK, E->getType());
287+
288+
return ExprCreatorUtil::CreateImplicitCast(SemaRef, Child,
289+
CK, E->getType());
267290
}
268291
};
269292
}

0 commit comments

Comments
 (0)