-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] Implement -Walloc-size diagnostic option #150028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1f03a09
c483fd3
c790ac1
aa57034
4be5615
83892e3
06eee5e
a3697e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3533,6 +3533,56 @@ bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const { | |
Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal; | ||
} | ||
|
||
const AllocSizeAttr *CallExpr::getCalleeAllocSizeAttr() const { | ||
if (const FunctionDecl *DirectCallee = getDirectCallee()) | ||
return DirectCallee->getAttr<AllocSizeAttr>(); | ||
if (const Decl *IndirectCallee = getCalleeDecl()) | ||
return IndirectCallee->getAttr<AllocSizeAttr>(); | ||
return nullptr; | ||
erichkeane marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
std::optional<llvm::APInt> | ||
CallExpr::getBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const { | ||
const AllocSizeAttr *AllocSize = getCalleeAllocSizeAttr(); | ||
|
||
assert(AllocSize && AllocSize->getElemSizeParam().isValid()); | ||
unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); | ||
unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); | ||
if (getNumArgs() <= SizeArgNo) | ||
return {}; | ||
|
||
auto EvaluateAsSizeT = [&](const Expr *E, llvm::APSInt &Into) { | ||
Expr::EvalResult ExprResult; | ||
if (E->isValueDependent() || | ||
!E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects)) | ||
return false; | ||
Into = ExprResult.Val.getInt(); | ||
if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be BitsInSizeT-1? In the case where the That would make the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand, isn't Also, this code isn't new, it was just moved here. |
||
return false; | ||
Into = Into.zext(BitsInSizeT); | ||
return true; | ||
}; | ||
|
||
llvm::APSInt SizeOfElem; | ||
if (!EvaluateAsSizeT(getArg(SizeArgNo), SizeOfElem)) | ||
return {}; | ||
|
||
if (!AllocSize->getNumElemsParam().isValid()) | ||
return SizeOfElem; | ||
|
||
llvm::APSInt NumberOfElems; | ||
unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); | ||
if (!EvaluateAsSizeT(getArg(NumArgNo), NumberOfElems)) | ||
return {}; | ||
|
||
bool Overflow; | ||
llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow); | ||
if (Overflow) | ||
return {}; | ||
|
||
return BytesAvailable; | ||
} | ||
|
||
bool CallExpr::isCallToStdMove() const { | ||
return getBuiltinCallee() == Builtin::BImove; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
#include "clang/AST/ASTDiagnostic.h" | ||
#include "clang/AST/ASTLambda.h" | ||
#include "clang/AST/ASTMutationListener.h" | ||
#include "clang/AST/Attrs.inc" | ||
#include "clang/AST/CXXInheritance.h" | ||
#include "clang/AST/Decl.h" | ||
#include "clang/AST/DeclObjC.h" | ||
|
@@ -7818,6 +7819,39 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, | |
return prepareVectorSplat(DestTy, CastExpr); | ||
} | ||
|
||
/// Check that a call to alloc_size function specifies sufficient space for the | ||
/// destination type. | ||
static void CheckSufficientAllocSize(Sema &S, QualType DestType, | ||
const Expr *E) { | ||
QualType SourceType = E->getType(); | ||
if (!DestType->isPointerType() || !SourceType->isPointerType() || | ||
DestType == SourceType) | ||
return; | ||
|
||
const auto *CE = dyn_cast<CallExpr>(E->IgnoreParenCasts()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then there's one more test I'd like to see added:
|
||
if (!CE) | ||
return; | ||
|
||
// Find the total size allocated by the function call. | ||
if (!CE->getCalleeAllocSizeAttr()) | ||
return; | ||
std::optional<llvm::APInt> AllocSize = | ||
CE->getBytesReturnedByAllocSizeCall(S.Context); | ||
if (!AllocSize) | ||
return; | ||
auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue()); | ||
|
||
QualType TargetType = DestType->getPointeeType(); | ||
// Find the destination size. As a special case function types have size of | ||
// one byte to match the sizeof operator behavior. | ||
auto LhsSize = TargetType->isFunctionType() | ||
? CharUnits::One() | ||
: S.Context.getTypeSizeInCharsIfKnown(TargetType); | ||
if (LhsSize && Size < LhsSize) | ||
S.Diag(E->getExprLoc(), diag::warn_alloc_size) | ||
<< Size.getQuantity() << TargetType << LhsSize->getQuantity(); | ||
} | ||
|
||
ExprResult | ||
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, | ||
Declarator &D, ParsedType &Ty, | ||
|
@@ -7883,6 +7917,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, | |
|
||
DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); | ||
|
||
CheckSufficientAllocSize(*this, castType, CastExpr); | ||
|
||
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); | ||
} | ||
|
||
|
@@ -9893,6 +9929,12 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, | |
AssignConvertType result = | ||
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); | ||
|
||
// If assigning a void * created by an allocation function call to some other | ||
// type, check that the allocated size is sufficient for that type. | ||
if (result != AssignConvertType::Incompatible && | ||
RHS.get()->getType()->isVoidPointerType()) | ||
CheckSufficientAllocSize(*this, LHSType, RHS.get()); | ||
|
||
// C99 6.5.16.1p2: The value of the right operand is converted to the | ||
// type of the assignment expression. | ||
// CheckAssignmentConstraints allows the left-hand side to be a reference, | ||
|
Uh oh!
There was an error while loading. Please reload this page.