1 //===-- SemaBoundsSafety.cpp - Bounds Safety specific routines-*- C++ -*---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file declares semantic analysis functions specific to `-fbounds-safety` 10 /// (Bounds Safety) and also its attributes when used without `-fbounds-safety` 11 /// (e.g. `counted_by`) 12 /// 13 //===----------------------------------------------------------------------===// 14 #include "clang/Lex/Lexer.h" 15 #include "clang/Sema/Initialization.h" 16 #include "clang/Sema/Sema.h" 17 18 namespace clang { 19 20 static CountAttributedType::DynamicCountPointerKind 21 getCountAttrKind(bool CountInBytes, bool OrNull) { 22 if (CountInBytes) 23 return OrNull ? CountAttributedType::SizedByOrNull 24 : CountAttributedType::SizedBy; 25 return OrNull ? CountAttributedType::CountedByOrNull 26 : CountAttributedType::CountedBy; 27 } 28 29 static const RecordDecl *GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) { 30 const auto *RD = FD->getParent(); 31 // An unnamed struct is anonymous struct only if it's not instantiated. 32 // However, the struct may not be fully processed yet to determine 33 // whether it's anonymous or not. In that case, this function treats it as 34 // an anonymous struct and tries to find a named parent. 35 while (RD && (RD->isAnonymousStructOrUnion() || 36 (!RD->isCompleteDefinition() && RD->getName().empty()))) { 37 const auto *Parent = dyn_cast<RecordDecl>(RD->getParent()); 38 if (!Parent) 39 break; 40 RD = Parent; 41 } 42 return RD; 43 } 44 45 enum class CountedByInvalidPointeeTypeKind { 46 INCOMPLETE, 47 SIZELESS, 48 FUNCTION, 49 FLEXIBLE_ARRAY_MEMBER, 50 VALID, 51 }; 52 53 bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes, 54 bool OrNull) { 55 // Check the context the attribute is used in 56 57 unsigned Kind = getCountAttrKind(CountInBytes, OrNull); 58 59 if (FD->getParent()->isUnion()) { 60 Diag(FD->getBeginLoc(), diag::err_count_attr_in_union) 61 << Kind << FD->getSourceRange(); 62 return true; 63 } 64 65 const auto FieldTy = FD->getType(); 66 if (FieldTy->isArrayType() && (CountInBytes || OrNull)) { 67 Diag(FD->getBeginLoc(), 68 diag::err_count_attr_not_on_ptr_or_flexible_array_member) 69 << Kind << FD->getLocation() << /* suggest counted_by */ 1; 70 return true; 71 } 72 if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) { 73 Diag(FD->getBeginLoc(), 74 diag::err_count_attr_not_on_ptr_or_flexible_array_member) 75 << Kind << FD->getLocation() << /* do not suggest counted_by */ 0; 76 return true; 77 } 78 79 LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = 80 LangOptions::StrictFlexArraysLevelKind::IncompleteOnly; 81 if (FieldTy->isArrayType() && 82 !Decl::isFlexibleArrayMemberLike(getASTContext(), FD, FieldTy, 83 StrictFlexArraysLevel, true)) { 84 Diag(FD->getBeginLoc(), 85 diag::err_counted_by_attr_on_array_not_flexible_array_member) 86 << Kind << FD->getLocation(); 87 return true; 88 } 89 90 CountedByInvalidPointeeTypeKind InvalidTypeKind = 91 CountedByInvalidPointeeTypeKind::VALID; 92 QualType PointeeTy; 93 int SelectPtrOrArr = 0; 94 if (FieldTy->isPointerType()) { 95 PointeeTy = FieldTy->getPointeeType(); 96 SelectPtrOrArr = 0; 97 } else { 98 assert(FieldTy->isArrayType()); 99 const ArrayType *AT = getASTContext().getAsArrayType(FieldTy); 100 PointeeTy = AT->getElementType(); 101 SelectPtrOrArr = 1; 102 } 103 // Note: The `Decl::isFlexibleArrayMemberLike` check earlier on means 104 // only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable 105 // when `FieldTy->isArrayType()`. 106 bool ShouldWarn = false; 107 if (PointeeTy->isAlwaysIncompleteType() && !CountInBytes) { 108 // In general using `counted_by` or `counted_by_or_null` on 109 // pointers where the pointee is an incomplete type are problematic. This is 110 // because it isn't possible to compute the pointer's bounds without knowing 111 // the pointee type size. At the same time it is common to forward declare 112 // types in header files. 113 // 114 // E.g.: 115 // 116 // struct Handle; 117 // struct Wrapper { 118 // size_t size; 119 // struct Handle* __counted_by(count) handles; 120 // } 121 // 122 // To allow the above code pattern but still prevent the pointee type from 123 // being incomplete in places where bounds checks are needed the following 124 // scheme is used: 125 // 126 // * When the pointee type might not always be an incomplete type (i.e. 127 // a type that is currently incomplete but might be completed later 128 // on in the translation unit) the attribute is allowed by this method 129 // but later uses of the FieldDecl are checked that the pointee type 130 // is complete see `BoundsSafetyCheckAssignmentToCountAttrPtr`, 131 // `BoundsSafetyCheckInitialization`, and 132 // `BoundsSafetyCheckUseOfCountAttrPtr` 133 // 134 // * When the pointee type is always an incomplete type (e.g. 135 // `void`) the attribute is disallowed by this method because we know the 136 // type can never be completed so there's no reason to allow it. 137 InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE; 138 } else if (PointeeTy->isSizelessType()) { 139 InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS; 140 } else if (PointeeTy->isFunctionType()) { 141 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION; 142 } else if (PointeeTy->isStructureTypeWithFlexibleArrayMember()) { 143 if (FieldTy->isArrayType() && !getLangOpts().BoundsSafety) { 144 // This is a workaround for the Linux kernel that has already adopted 145 // `counted_by` on a FAM where the pointee is a struct with a FAM. This 146 // should be an error because computing the bounds of the array cannot be 147 // done correctly without manually traversing every struct object in the 148 // array at runtime. To allow the code to be built this error is 149 // downgraded to a warning. 150 ShouldWarn = true; 151 } 152 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER; 153 } 154 155 if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) { 156 unsigned DiagID = ShouldWarn 157 ? diag::warn_counted_by_attr_elt_type_unknown_size 158 : diag::err_counted_by_attr_pointee_unknown_size; 159 Diag(FD->getBeginLoc(), DiagID) 160 << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind 161 << (ShouldWarn ? 1 : 0) << Kind << FD->getSourceRange(); 162 return true; 163 } 164 165 // Check the expression 166 167 if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) { 168 Diag(E->getBeginLoc(), diag::err_count_attr_argument_not_integer) 169 << Kind << E->getSourceRange(); 170 return true; 171 } 172 173 auto *DRE = dyn_cast<DeclRefExpr>(E); 174 if (!DRE) { 175 Diag(E->getBeginLoc(), 176 diag::err_count_attr_only_support_simple_decl_reference) 177 << Kind << E->getSourceRange(); 178 return true; 179 } 180 181 auto *CountDecl = DRE->getDecl(); 182 FieldDecl *CountFD = dyn_cast<FieldDecl>(CountDecl); 183 if (auto *IFD = dyn_cast<IndirectFieldDecl>(CountDecl)) { 184 CountFD = IFD->getAnonField(); 185 } 186 if (!CountFD) { 187 Diag(E->getBeginLoc(), diag::err_count_attr_must_be_in_structure) 188 << CountDecl << Kind << E->getSourceRange(); 189 190 Diag(CountDecl->getBeginLoc(), 191 diag::note_flexible_array_counted_by_attr_field) 192 << CountDecl << CountDecl->getSourceRange(); 193 return true; 194 } 195 196 if (FD->getParent() != CountFD->getParent()) { 197 if (CountFD->getParent()->isUnion()) { 198 Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union) 199 << Kind << CountFD->getSourceRange(); 200 return true; 201 } 202 // Whether CountRD is an anonymous struct is not determined at this 203 // point. Thus, an additional diagnostic in case it's not anonymous struct 204 // is done later in `Parser::ParseStructDeclaration`. 205 auto *RD = GetEnclosingNamedOrTopAnonRecord(FD); 206 auto *CountRD = GetEnclosingNamedOrTopAnonRecord(CountFD); 207 208 if (RD != CountRD) { 209 Diag(E->getBeginLoc(), diag::err_count_attr_param_not_in_same_struct) 210 << CountFD << Kind << FieldTy->isArrayType() << E->getSourceRange(); 211 Diag(CountFD->getBeginLoc(), 212 diag::note_flexible_array_counted_by_attr_field) 213 << CountFD << CountFD->getSourceRange(); 214 return true; 215 } 216 } 217 return false; 218 } 219 220 static void EmitIncompleteCountedByPointeeNotes(Sema &S, 221 const CountAttributedType *CATy, 222 NamedDecl *IncompleteTyDecl) { 223 assert(IncompleteTyDecl == nullptr || isa<TypeDecl>(IncompleteTyDecl)); 224 225 if (IncompleteTyDecl) { 226 // Suggest completing the pointee type if its a named typed (i.e. 227 // IncompleteTyDecl isn't nullptr). Suggest this first as it is more likely 228 // to be the correct fix. 229 // 230 // Note the `IncompleteTyDecl` type is the underlying type which might not 231 // be the same as `CATy->getPointeeType()` which could be a typedef. 232 // 233 // The diagnostic printed will be at the location of the underlying type but 234 // the diagnostic text will print the type of `CATy->getPointeeType()` which 235 // could be a typedef name rather than the underlying type. This is ok 236 // though because the diagnostic will print the underlying type name too. 237 S.Diag(IncompleteTyDecl->getBeginLoc(), 238 diag::note_counted_by_consider_completing_pointee_ty) 239 << CATy->getPointeeType(); 240 } 241 242 // Suggest using __sized_by(_or_null) instead of __counted_by(_or_null) as 243 // __sized_by(_or_null) doesn't have the complete type restriction. 244 // 245 // We use the source range of the expression on the CountAttributedType as an 246 // approximation for the source range of the attribute. This isn't quite right 247 // but isn't easy to fix right now. 248 // 249 // TODO: Implement logic to find the relevant TypeLoc for the attribute and 250 // get the SourceRange from that (#113582). 251 // 252 // TODO: We should emit a fix-it here. 253 SourceRange AttrSrcRange = CATy->getCountExpr()->getSourceRange(); 254 S.Diag(AttrSrcRange.getBegin(), diag::note_counted_by_consider_using_sized_by) 255 << CATy->isOrNull() << AttrSrcRange; 256 } 257 258 static std::tuple<const CountAttributedType *, QualType> 259 GetCountedByAttrOnIncompletePointee(QualType Ty, NamedDecl **ND) { 260 auto *CATy = Ty->getAs<CountAttributedType>(); 261 // Incomplete pointee type is only a problem for 262 // counted_by/counted_by_or_null 263 if (!CATy || CATy->isCountInBytes()) 264 return {}; 265 266 auto PointeeTy = CATy->getPointeeType(); 267 if (PointeeTy.isNull()) { 268 // Reachable if `CountAttributedType` wraps an IncompleteArrayType 269 return {}; 270 } 271 272 if (!PointeeTy->isIncompleteType(ND)) 273 return {}; 274 275 return {CATy, PointeeTy}; 276 } 277 278 /// Perform Checks for assigning to a `__counted_by` or 279 /// `__counted_by_or_null` pointer type \param LHSTy where the pointee type 280 /// is incomplete which is invalid. 281 /// 282 /// \param S The Sema instance. 283 /// \param LHSTy The type being assigned to. Checks will only be performed if 284 /// the type is a `counted_by` or `counted_by_or_null ` pointer. 285 /// \param RHSExpr The expression being assigned from. 286 /// \param Action The type assignment being performed 287 /// \param Loc The SourceLocation to use for error diagnostics 288 /// \param Assignee The ValueDecl being assigned. This is used to compute 289 /// the name of the assignee. If the assignee isn't known this can 290 /// be set to nullptr. 291 /// \param ShowFullyQualifiedAssigneeName If set to true when using \p 292 /// Assignee to compute the name of the assignee use the fully 293 /// qualified name, otherwise use the unqualified name. 294 /// 295 /// \returns True iff no diagnostic where emitted, false otherwise. 296 static bool CheckAssignmentToCountAttrPtrWithIncompletePointeeTy( 297 Sema &S, QualType LHSTy, Expr *RHSExpr, AssignmentAction Action, 298 SourceLocation Loc, const ValueDecl *Assignee, 299 bool ShowFullyQualifiedAssigneeName) { 300 NamedDecl *IncompleteTyDecl = nullptr; 301 auto [CATy, PointeeTy] = 302 GetCountedByAttrOnIncompletePointee(LHSTy, &IncompleteTyDecl); 303 if (!CATy) 304 return true; 305 306 std::string AssigneeStr; 307 if (Assignee) { 308 if (ShowFullyQualifiedAssigneeName) { 309 AssigneeStr = Assignee->getQualifiedNameAsString(); 310 } else { 311 AssigneeStr = Assignee->getNameAsString(); 312 } 313 } 314 315 S.Diag(Loc, diag::err_counted_by_on_incomplete_type_on_assign) 316 << static_cast<int>(Action) << AssigneeStr << (AssigneeStr.size() > 0) 317 << isa<ImplicitValueInitExpr>(RHSExpr) << LHSTy 318 << CATy->getAttributeName(/*WithMacroPrefix=*/true) << PointeeTy 319 << CATy->isOrNull() << RHSExpr->getSourceRange(); 320 321 EmitIncompleteCountedByPointeeNotes(S, CATy, IncompleteTyDecl); 322 return false; // check failed 323 } 324 325 bool Sema::BoundsSafetyCheckAssignmentToCountAttrPtr( 326 QualType LHSTy, Expr *RHSExpr, AssignmentAction Action, SourceLocation Loc, 327 const ValueDecl *Assignee, bool ShowFullyQualifiedAssigneeName) { 328 return CheckAssignmentToCountAttrPtrWithIncompletePointeeTy( 329 *this, LHSTy, RHSExpr, Action, Loc, Assignee, 330 ShowFullyQualifiedAssigneeName); 331 } 332 333 bool Sema::BoundsSafetyCheckInitialization(const InitializedEntity &Entity, 334 const InitializationKind &Kind, 335 AssignmentAction Action, 336 QualType LHSType, Expr *RHSExpr) { 337 auto SL = Kind.getLocation(); 338 339 // Note: We don't call `BoundsSafetyCheckAssignmentToCountAttrPtr` here 340 // because we need conditionalize what is checked. In downstream 341 // Clang `counted_by` is supported on variable definitions and in that 342 // implementation an error diagnostic will be emitted on the variable 343 // definition if the pointee is an incomplete type. To avoid warning about the 344 // same problem twice (once when the variable is defined, once when Sema 345 // checks the initializer) we skip checking the initializer if it's a 346 // variable. 347 if (Action == AssignmentAction::Initializing && 348 Entity.getKind() != InitializedEntity::EK_Variable) { 349 350 if (!CheckAssignmentToCountAttrPtrWithIncompletePointeeTy( 351 *this, LHSType, RHSExpr, Action, SL, 352 dyn_cast_or_null<ValueDecl>(Entity.getDecl()), 353 /*ShowFullQualifiedAssigneeName=*/true)) { 354 return false; 355 } 356 } 357 358 return true; 359 } 360 361 bool Sema::BoundsSafetyCheckUseOfCountAttrPtr(const Expr *E) { 362 QualType T = E->getType(); 363 if (!T->isPointerType()) 364 return true; 365 366 NamedDecl *IncompleteTyDecl = nullptr; 367 auto [CATy, PointeeTy] = 368 GetCountedByAttrOnIncompletePointee(T, &IncompleteTyDecl); 369 if (!CATy) 370 return true; 371 372 // Generate a string for the diagnostic that describes the "use". 373 // The string is specialized for direct calls to produce a better 374 // diagnostic. 375 SmallString<64> UseStr; 376 bool IsDirectCall = false; 377 if (const auto *CE = dyn_cast<CallExpr>(E->IgnoreParens())) { 378 if (const auto *FD = CE->getDirectCallee()) { 379 UseStr = FD->getName(); 380 IsDirectCall = true; 381 } 382 } 383 384 if (!IsDirectCall) { 385 llvm::raw_svector_ostream SS(UseStr); 386 E->printPretty(SS, nullptr, getPrintingPolicy()); 387 } 388 389 Diag(E->getBeginLoc(), diag::err_counted_by_on_incomplete_type_on_use) 390 << IsDirectCall << UseStr << T << PointeeTy 391 << CATy->getAttributeName(/*WithMacroPrefix=*/true) << CATy->isOrNull() 392 << E->getSourceRange(); 393 394 EmitIncompleteCountedByPointeeNotes(*this, CATy, IncompleteTyDecl); 395 return false; 396 } 397 398 } // namespace clang 399