diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 285 |
1 files changed, 60 insertions, 225 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 5e8be3c1f05..fd8e19876b9 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1065,12 +1065,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIget_kernel_preferred_work_group_size_multiple: if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); - case Builtin::BI__builtin_os_log_format: - case Builtin::BI__builtin_os_log_format_buffer_size: - if (SemaBuiltinOSLogFormat(TheCall)) { - return ExprError(); - } - break; } // Since the target specific builtins for each arch overlap, only check those @@ -3484,31 +3478,6 @@ bool Sema::CheckObjCString(Expr *Arg) { return false; } -/// CheckObjCString - Checks that the format string argument to the os_log() -/// and os_trace() functions is correct, and converts it to const char *. -ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { - Arg = Arg->IgnoreParenCasts(); - auto *Literal = dyn_cast<StringLiteral>(Arg); - if (!Literal) { - if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) { - Literal = ObjcLiteral->getString(); - } - } - - if (!Literal || (!Literal->isAscii() && !Literal->isUTF8())) { - return ExprError( - Diag(Arg->getLocStart(), diag::err_os_log_format_not_string_constant) - << Arg->getSourceRange()); - } - - ExprResult Result(Literal); - QualType ResultTy = Context.getPointerType(Context.CharTy.withConst()); - InitializedEntity Entity = - InitializedEntity::InitializeParameter(Context, ResultTy, false); - Result = PerformCopyInitialization(Entity, SourceLocation(), Result); - return Result; -} - /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. @@ -3970,86 +3939,6 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { - unsigned BuiltinID = - cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID(); - bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; - - unsigned NumArgs = TheCall->getNumArgs(); - unsigned NumRequiredArgs = IsSizeCall ? 1 : 2; - if (NumArgs < NumRequiredArgs) { - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /* function call */ << NumRequiredArgs << NumArgs - << TheCall->getSourceRange(); - } - if (NumArgs >= NumRequiredArgs + 0x100) { - return Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_many_args_at_most) - << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs - << TheCall->getSourceRange(); - } - unsigned i = 0; - - // For formatting call, check buffer arg. - if (!IsSizeCall) { - ExprResult Arg(TheCall->getArg(i)); - InitializedEntity Entity = InitializedEntity::InitializeParameter( - Context, Context.VoidPtrTy, false); - Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); - if (Arg.isInvalid()) - return true; - TheCall->setArg(i, Arg.get()); - i++; - } - - // Check string literal arg. - unsigned FormatIdx = i; - { - ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i)); - if (Arg.isInvalid()) - return true; - TheCall->setArg(i, Arg.get()); - i++; - } - - // Make sure variadic args are scalar. - unsigned FirstDataArg = i; - while (i < NumArgs) { - ExprResult Arg = DefaultVariadicArgumentPromotion( - TheCall->getArg(i), VariadicFunction, nullptr); - if (Arg.isInvalid()) - return true; - CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType()); - if (ArgSize.getQuantity() >= 0x100) { - return Diag(Arg.get()->getLocEnd(), diag::err_os_log_argument_too_big) - << i << (int)ArgSize.getQuantity() << 0xff - << TheCall->getSourceRange(); - } - TheCall->setArg(i, Arg.get()); - i++; - } - - // Check formatting specifiers. NOTE: We're only doing this for the non-size - // call to avoid duplicate diagnostics. - if (!IsSizeCall) { - llvm::SmallBitVector CheckedVarArgs(NumArgs, false); - ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs()); - bool Success = CheckFormatArguments( - Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog, - VariadicFunction, TheCall->getLocStart(), SourceRange(), - CheckedVarArgs); - if (!Success) - return true; - } - - if (IsSizeCall) { - TheCall->setType(Context.getSizeType()); - } else { - TheCall->setType(Context.VoidPtrTy); - } - return false; -} - /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, @@ -4680,16 +4569,15 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch<FormatStringType>(Format->getType()->getName()) - .Case("scanf", FST_Scanf) - .Cases("printf", "printf0", FST_Printf) - .Cases("NSString", "CFString", FST_NSString) - .Case("strftime", FST_Strftime) - .Case("strfmon", FST_Strfmon) - .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) - .Case("freebsd_kprintf", FST_FreeBSDKPrintf) - .Case("os_trace", FST_OSLog) - .Case("os_log", FST_OSLog) - .Default(FST_Unknown); + .Case("scanf", FST_Scanf) + .Cases("printf", "printf0", FST_Printf) + .Cases("NSString", "CFString", FST_NSString) + .Case("strftime", FST_Strftime) + .Case("strfmon", FST_Strfmon) + .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) + .Case("freebsd_kprintf", FST_FreeBSDKPrintf) + .Case("os_trace", FST_OSTrace) + .Default(FST_Unknown); } /// CheckFormatArguments - Check calls to printf and scanf (and similar @@ -4799,7 +4687,6 @@ protected: Sema &S; const FormatStringLiteral *FExpr; const Expr *OrigFormatExpr; - const Sema::FormatStringType FSType; const unsigned FirstDataArg; const unsigned NumDataArgs; const char *Beg; // Start of format string. @@ -4816,19 +4703,20 @@ protected: public: CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr, - const Expr *origFormatExpr, - const Sema::FormatStringType type, unsigned firstDataArg, + const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, unsigned formatIdx, - bool inFunctionCall, Sema::VariadicCallType callType, + ArrayRef<const Expr *> Args, + unsigned formatIdx, bool inFunctionCall, + Sema::VariadicCallType callType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), - FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), - HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), - usesPositionalArgs(false), atFirstArg(true), - inFunctionCall(inFunctionCall), CallType(callType), - CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { + : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), + FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), + Beg(beg), HasVAListArg(hasVAListArg), + Args(Args), FormatIdx(formatIdx), + usesPositionalArgs(false), atFirstArg(true), + inFunctionCall(inFunctionCall), CallType(callType), + CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } @@ -5251,28 +5139,24 @@ void CheckFormatHandler::EmitFormatDiagnostic( namespace { class CheckPrintfHandler : public CheckFormatHandler { + bool ObjCContext; + public: CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, - const Expr *origFormatExpr, - const Sema::FormatStringType type, unsigned firstDataArg, - unsigned numDataArgs, bool isObjC, const char *beg, - bool hasVAListArg, ArrayRef<const Expr *> Args, + const Expr *origFormatExpr, unsigned firstDataArg, + unsigned numDataArgs, bool isObjC, + const char *beg, bool hasVAListArg, + ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, formatIdx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg) {} - - bool isObjCContext() const { return FSType == Sema::FST_NSString; } - - /// Returns true if '%@' specifiers are allowed in the format string. - bool allowsObjCArg() const { - return FSType == Sema::FST_NSString || FSType == Sema::FST_OSLog || - FSType == Sema::FST_OSTrace; - } + : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, + numDataArgs, beg, hasVAListArg, Args, + formatIdx, inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg), + ObjCContext(isObjC) + {} bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -5626,54 +5510,11 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier // Check for using an Objective-C specific conversion specifier // in a non-ObjC literal. - if (!allowsObjCArg() && CS.isObjCArg()) { - return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, - specifierLen); - } - - // %P can only be used with os_log. - if (FSType != Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::PArg) { + if (!ObjCContext && CS.isObjCArg()) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, specifierLen); } - // %n is not allowed with os_log. - if (FSType == Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::nArg) { - EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg), - getLocationOfByte(CS.getStart()), - /*IsStringLocation*/ false, - getSpecifierRange(startSpecifier, specifierLen)); - - return true; - } - - // Only scalars are allowed for os_trace. - if (FSType == Sema::FST_OSTrace && - (CS.getKind() == ConversionSpecifier::PArg || - CS.getKind() == ConversionSpecifier::sArg || - CS.getKind() == ConversionSpecifier::ObjCObjArg)) { - return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, - specifierLen); - } - - // Check for use of public/private annotation outside of os_log(). - if (FSType != Sema::FST_OSLog) { - if (FS.isPublic().isSet()) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) - << "public", - getLocationOfByte(FS.isPublic().getPosition()), - /*IsStringLocation*/ false, - getSpecifierRange(startSpecifier, specifierLen)); - } - if (FS.isPrivate().isSet()) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) - << "private", - getLocationOfByte(FS.isPrivate().getPosition()), - /*IsStringLocation*/ false, - getSpecifierRange(startSpecifier, specifierLen)); - } - } - // Check for invalid use of field width if (!FS.hasValidFieldWidth()) { HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, @@ -5686,15 +5527,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); } - // Precision is mandatory for %P specifier. - if (CS.getKind() == ConversionSpecifier::PArg && - FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision), - getLocationOfByte(startSpecifier), - /*IsStringLocation*/ false, - getSpecifierRange(startSpecifier, specifierLen)); - } - // Check each flag does not conflict with any other component. if (!FS.hasValidThousandsGroupingPrefix()) HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); @@ -5844,7 +5676,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, using namespace analyze_printf; // Now type check the data expression that matches the // format specifier. - const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext()); + const analyze_printf::ArgType &AT = FS.getArgType(S.Context, + ObjCContext); if (!AT.isValid()) return true; @@ -5899,7 +5732,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. QualType IntendedTy = ExprTy; - if (isObjCContext() && + if (ObjCContext && FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { if (ExprTy->isIntegralOrUnscopedEnumerationType() && !ExprTy->isCharType()) { @@ -5940,8 +5773,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = - fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); + bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(), + S.Context, ObjCContext); if (success) { // Get the fix string from the fixed format specifier @@ -6097,18 +5930,19 @@ namespace { class CheckScanfHandler : public CheckFormatHandler { public: CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, - const Expr *origFormatExpr, Sema::FormatStringType type, - unsigned firstDataArg, unsigned numDataArgs, - const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, unsigned formatIdx, - bool inFunctionCall, Sema::VariadicCallType CallType, + const Expr *origFormatExpr, unsigned firstDataArg, + unsigned numDataArgs, const char *beg, bool hasVAListArg, + ArrayRef<const Expr *> Args, + unsigned formatIdx, bool inFunctionCall, + Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, formatIdx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg) {} - + : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, + numDataArgs, beg, hasVAListArg, + Args, formatIdx, inFunctionCall, CallType, + CheckedVarArgs, UncoveredArg) + {} + bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; @@ -6318,13 +6152,13 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, } if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || - Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog || - Type == Sema::FST_OSTrace) { - CheckPrintfHandler H( - S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs, - (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, - HasVAListArg, Args, format_idx, inFunctionCall, CallType, - CheckedVarArgs, UncoveredArg); + Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) { + CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, + numDataArgs, (Type == Sema::FST_NSString || + Type == Sema::FST_OSTrace), + Str, HasVAListArg, Args, format_idx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, S.getLangOpts(), @@ -6332,9 +6166,10 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { - CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, - numDataArgs, Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); + CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, + Str, HasVAListArg, Args, format_idx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, S.getLangOpts(), |