llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-libcxx @llvm/pr-subscribers-compiler-rt-sanitizer Author: Denys Fedoryshchenko (nuclearcat) <details> <summary>Changes</summary> Based on and partially rewritten from PR#<!-- -->161737 by @<!-- -->ColinKinloch. This adds Clang fortify diagnostics for several `unistd.h` functions and extends the static analyzer coverage for related POSIX I/O calls. The Sema changes: * define builtins for `read`, `write`, `getcwd`, `readlink`, and `readlinkat` * add fortify checks for destination overflow and source over-read cases * introduce min/max operation-size handling so existing fortify checks can model both lower and upper bounds * recognize `pread`/`pread64`/`pwrite`/`pwrite64` in the fortify checker without declaring them as builtins, since their `off_t` argument width depends on platform/header configuration The analyzer changes: * add `SSIZE_MAX` size constraints for `read`, `write`, `readlink`, and `readlinkat` * add summaries for `pread`, `pread64`, `pwrite`, and `pwrite64` * tighten tests for over-large sizes, including cases such as passing `-1` to `size_t` parameters This may produce new `-Wfortify-source` diagnostics for code that passes buffer sizes larger than the known object size or larger than `SSIZE_MAX`. Related to/Part of PR#<!-- -->142230. Tested: * `ninja check-clang-sema` * `ninja check-clang-analysis` --- Patch is 46.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196499.diff 19 Files Affected: - (modified) clang/include/clang/Basic/Builtins.td (+43) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+8) - (modified) clang/lib/AST/ASTContext.cpp (+6-3) - (modified) clang/lib/Sema/SemaChecking.cpp (+154-44) - (modified) clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (+39-7) - (modified) clang/test/Analysis/Inputs/std-c-library-functions-POSIX.h (+4) - (modified) clang/test/Analysis/array-struct.c (+2-2) - (modified) clang/test/Analysis/bstring.c (+19-2) - (modified) clang/test/Analysis/malloc.c (+1-1) - (modified) clang/test/Analysis/pr22954.c (+2-1) - (modified) clang/test/Analysis/std-c-library-functions-POSIX.c (+6-2) - (modified) clang/test/Analysis/std-c-library-functions-arg-constraints.c (+58) - (modified) clang/test/Analysis/std-c-library-functions.c (+2-2) - (modified) clang/test/Sema/asm-label.c (+3-3) - (modified) clang/test/Sema/builtin-memcpy.c (+2-1) - (modified) clang/test/Sema/warn-fortify-source.c (+97-3) - (modified) clang/utils/TableGen/ClangBuiltinsEmitter.cpp (+1) - (modified) compiler-rt/test/asan/TestCases/Windows/issue64990.cpp (+1-1) - (modified) libcxx/test/libcxx/strings/c.strings/constexpr.cwchar.compile.pass.cpp (+1-1) ``````````diff diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 4a7eaeb3d353e..c1677cf2f5acc 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -3832,6 +3832,8 @@ def StrnCaseCmp : GNULibBuiltin<"strings.h"> { let RequiresUndef = 1; } +// POSIX unistd.h + def GNU_Exit : GNULibBuiltin<"unistd.h"> { let Spellings = ["_exit"]; let Attributes = [NoReturn]; @@ -3844,6 +3846,47 @@ def VFork : LibBuiltin<"unistd.h"> { let Prototype = "pid_t()"; } +def Read : LibBuiltin<"unistd.h"> { + let Spellings = ["read"]; + let Attributes = [NoThrow]; + let Prototype = "ssize_t(int, void*, size_t)"; + let AddBuiltinPrefixedAlias = 1; +} + +def Write : LibBuiltin<"unistd.h"> { + let Spellings = ["write"]; + let Attributes = [NoThrow]; + let Prototype = "ssize_t(int, void const*, size_t)"; + let AddBuiltinPrefixedAlias = 1; +} + +// pread/pread64/pwrite/pwrite64 are intentionally not declared as builtins. +// Their prototypes use off_t, whose width is platform- and macro-dependent +// (notably _FILE_OFFSET_BITS), so a fixed builtin signature would clash with +// the system header on some targets. Fortify checks for these functions are +// dispatched by name in Sema::checkFortifiedBuiltinMemoryFunction instead. + +def GetCWD : LibBuiltin<"unistd.h"> { + let Spellings = ["getcwd"]; + let Attributes = [NoThrow]; + let Prototype = "char*(char*, size_t)"; + let AddBuiltinPrefixedAlias = 1; +} + +def ReadLink : LibBuiltin<"unistd.h"> { + let Spellings = ["readlink"]; + let Attributes = [NoThrow]; + let Prototype = "ssize_t(char const* restrict, char* restrict, size_t)"; + let AddBuiltinPrefixedAlias = 1; +} + +def ReadLinkAt : LibBuiltin<"unistd.h"> { + let Spellings = ["readlinkat"]; + let Attributes = [NoThrow]; + let Prototype = "ssize_t(int, char const* restrict, char* restrict, size_t)"; + let AddBuiltinPrefixedAlias = 1; +} + // POSIX pthread.h def PthreadCreate : GNULibBuiltin<"pthread.h"> { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c69b2ce3648f8..38d328b120f5d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -962,9 +962,17 @@ def warn_builtin_chk_overflow : Warning< def warn_fortify_source_overflow : Warning<warn_builtin_chk_overflow.Summary>, InGroup<FortifySource>; +def warn_fortify_destination_over_read + : Warning<"'%0' will always over-read; source buffer has size %1," + " but size argument is %2">, + InGroup<FortifySource>; def warn_fortify_source_size_mismatch : Warning< "'%0' size argument is too large; destination buffer has size %1," " but size argument is %2">, InGroup<FortifySource>; +def warn_fortify_destination_size_mismatch + : Warning<"'%0' size argument is too large; source buffer has size %1," + " but size argument is %2">, + InGroup<FortifySource>; def warn_fortify_strlen_overflow: Warning< "'%0' will always overflow; destination buffer has size %1," diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a0894318dbd53..ec7eb82b8e76e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12696,9 +12696,12 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); Type = Context.BoolTy; break; - case 'z': // size_t. - assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!"); - Type = Context.getSizeType(); + case 'z': // size_t and ssize_t. + assert(HowLong == 0 && "Bad modifiers for 'z'!"); + if (Signed) + Type = Context.getSignedSizeType(); + else + Type = Context.getSizeType(); break; case 'w': // wchar_t. assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'w'!"); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4706fa5d3cde0..dfb898d94b1fb 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1165,7 +1165,26 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, unsigned BuiltinID = UseDecl->getBuiltinID(/*ConsiderWrappers=*/true); - if (!BuiltinID) + // Some libc I/O functions are intentionally not Clang builtins because their + // prototypes use off_t, whose width is platform- and macro-dependent + // (notably _FILE_OFFSET_BITS). Recognize them by name so fortify checks + // work regardless of the platform's off_t encoding. + enum class LibCDispatch { None, PRead, PWrite }; + LibCDispatch LibC = LibCDispatch::None; + StringRef LibCName; + if (!BuiltinID && FD->isExternC() && FD->getIdentifier() && + TheCall->getNumArgs() == 4) { + StringRef Name = FD->getIdentifier()->getName(); + if (Name == "pread" || Name == "pread64") { + LibC = LibCDispatch::PRead; + LibCName = Name; + } else if (Name == "pwrite" || Name == "pwrite64") { + LibC = LibCDispatch::PWrite; + LibCName = Name; + } + } + + if (!BuiltinID && LibC == LibCDispatch::None) return; const TargetInfo &TI = getASTContext().getTargetInfo(); @@ -1249,12 +1268,25 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, return std::nullopt; }; + // Size of the memory read from std::optional<llvm::APSInt> SourceSize; + // Size of the memory written to std::optional<llvm::APSInt> DestinationSize; - unsigned DiagID = 0; + // Maximum operation size for detecting possible out of bounds access + std::optional<llvm::APSInt> MaxOperationSize; + // Minimum operation size for detecting definite out of bounds access + std::optional<llvm::APSInt> MinOperationSize; + + unsigned DiagOverflowID = diag::warn_fortify_source_overflow; + unsigned DiagMayOverflowID = diag::warn_fortify_source_size_mismatch; + unsigned DiagOverReadID = diag::warn_fortify_destination_over_read; + unsigned DiagMayOverReadID = diag::warn_fortify_destination_size_mismatch; bool IsChkVariant = false; - auto GetFunctionName = [&]() { + auto GetFunctionName = [&]() -> std::string { + if (LibC != LibCDispatch::None) + return LibCName.str(); + std::string FunctionNameStr = getASTContext().BuiltinInfo.getName(BuiltinID); llvm::StringRef FunctionName = FunctionNameStr; @@ -1270,6 +1302,17 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, return FunctionName.str(); }; + if (LibC == LibCDispatch::PRead) { + // pread/pread64: ssize_t(int fd, void buf[.count], size_t count, off_t); + // Up to count(2) bytes are written into buf(1). + DestinationSize = ComputeSizeArgument(1); + MaxOperationSize = ComputeExplicitObjectSizeArgument(2); + } else if (LibC == LibCDispatch::PWrite) { + // pwrite/pwrite64: ssize_t(int, const void buf[.count], size_t count, off_t); + // Up to count(2) bytes are read from buf(1). + SourceSize = ComputeSizeArgument(1); + MaxOperationSize = ComputeExplicitObjectSizeArgument(2); + } else switch (BuiltinID) { default: return; @@ -1279,8 +1322,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BIstpcpy: case Builtin::BI__builtin_strcpy: case Builtin::BIstrcpy: { - DiagID = diag::warn_fortify_strlen_overflow; - SourceSize = ComputeStrLenArgument(1); + DiagOverflowID = diag::warn_fortify_strlen_overflow; + MinOperationSize = ComputeStrLenArgument(1); DestinationSize = ComputeSizeArgument(0); break; } @@ -1288,8 +1331,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___strcat_chk: case Builtin::BI__builtin___stpcpy_chk: case Builtin::BI__builtin___strcpy_chk: { - DiagID = diag::warn_fortify_strlen_overflow; - SourceSize = ComputeStrLenArgument(1); + DiagOverflowID = diag::warn_fortify_strlen_overflow; + MinOperationSize = ComputeStrLenArgument(1); DestinationSize = ComputeExplicitObjectSizeArgument(2); IsChkVariant = true; break; @@ -1315,12 +1358,12 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize, unsigned SourceSize) { - DiagID = diag::warn_fortify_scanf_overflow; unsigned Index = ArgIndex + DataIndex; std::string FunctionName = GetFunctionName(); DiagRuntimeBehavior(TheCall->getArg(Index)->getBeginLoc(), TheCall, - PDiag(DiagID) << FunctionName << (Index + 1) - << DestSize << SourceSize); + PDiag(diag::warn_fortify_scanf_overflow) + << FunctionName << (Index + 1) << DestSize + << SourceSize); }; auto ShiftedComputeSizeArgument = [&](unsigned Index) { @@ -1351,11 +1394,11 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (!analyze_format_string::ParsePrintfString( H, FormatBytes, FormatBytes + StrLen, getLangOpts(), Context.getTargetInfo(), false)) { - DiagID = H.isKernelCompatible() - ? diag::warn_format_overflow - : diag::warn_format_overflow_non_kprintf; - SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) - .extOrTrunc(SizeTypeWidth); + DiagOverflowID = H.isKernelCompatible() + ? diag::warn_format_overflow + : diag::warn_format_overflow_non_kprintf; + MinOperationSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) + .extOrTrunc(SizeTypeWidth); if (BuiltinID == Builtin::BI__builtin___sprintf_chk) { DestinationSize = ComputeExplicitObjectSizeArgument(2); IsChkVariant = true; @@ -1367,6 +1410,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, } return; } + case Builtin::BI__builtin___memcpy_chk: case Builtin::BI__builtin___memmove_chk: case Builtin::BI__builtin___memset_chk: @@ -1377,8 +1421,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___stpncpy_chk: case Builtin::BI__builtin___memccpy_chk: case Builtin::BI__builtin___mempcpy_chk: { - DiagID = diag::warn_builtin_chk_overflow; - SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2); + DiagOverflowID = diag::warn_builtin_chk_overflow; + MinOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2); DestinationSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); IsChkVariant = true; @@ -1387,8 +1432,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___snprintf_chk: case Builtin::BI__builtin___vsnprintf_chk: { - DiagID = diag::warn_builtin_chk_overflow; - SourceSize = ComputeExplicitObjectSizeArgument(1); + DiagOverflowID = diag::warn_builtin_chk_overflow; + MinOperationSize = ComputeExplicitObjectSizeArgument(1); DestinationSize = ComputeExplicitObjectSizeArgument(3); IsChkVariant = true; break; @@ -1405,44 +1450,74 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, // diagnostic isn't quite right. We should still diagnose passing a buffer // size larger than the destination buffer though; this is a runtime abort // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise. - DiagID = diag::warn_fortify_source_size_mismatch; - SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); DestinationSize = ComputeSizeArgument(0); break; } + case Builtin::BImemset: + case Builtin::BI__builtin_memset: case Builtin::BIbzero: - case Builtin::BI__builtin_bzero: + case Builtin::BI__builtin_bzero: { + MinOperationSize = MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + DestinationSize = ComputeSizeArgument(0); + break; + } + case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: case Builtin::BImemmove: case Builtin::BI__builtin_memmove: - case Builtin::BImemset: - case Builtin::BI__builtin_memset: case Builtin::BImempcpy: case Builtin::BI__builtin_mempcpy: { - DiagID = diag::warn_fortify_source_overflow; - SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + MinOperationSize = MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); DestinationSize = ComputeSizeArgument(0); + SourceSize = ComputeSizeArgument(1); break; } case Builtin::BIbcopy: case Builtin::BI__builtin_bcopy: { - DiagID = diag::warn_fortify_source_overflow; - SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + MinOperationSize = MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + SourceSize = ComputeSizeArgument(0); DestinationSize = ComputeSizeArgument(1); break; } + + case Builtin::BIread: + case Builtin::BI__builtin_read: + case Builtin::BIreadlink: + case Builtin::BI__builtin_readlink: + case Builtin::BIreadlinkat: + case Builtin::BI__builtin_readlinkat: + case Builtin::BIgetcwd: + case Builtin::BI__builtin_getcwd: { + DestinationSize = ComputeSizeArgument(TheCall->getNumArgs() - 2); + MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + break; + } + + case Builtin::BIwrite: + case Builtin::BI__builtin_write: { + SourceSize = ComputeSizeArgument(TheCall->getNumArgs() - 2); + MaxOperationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + break; + } + case Builtin::BIsnprintf: case Builtin::BI__builtin_snprintf: case Builtin::BIvsnprintf: case Builtin::BI__builtin_vsnprintf: { - DiagID = diag::warn_fortify_source_size_mismatch; - SourceSize = ComputeExplicitObjectSizeArgument(1); + MaxOperationSize = ComputeExplicitObjectSizeArgument(1); const auto *FormatExpr = TheCall->getArg(2)->IgnoreParenImpCasts(); StringRef FormatStrRef; size_t StrLen; - if (SourceSize && + if (MaxOperationSize && ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) { EstimateSizeFormatHandler H(FormatStrRef); const char *FormatBytes = FormatStrRef.data(); @@ -1452,13 +1527,13 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, llvm::APSInt FormatSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) .extOrTrunc(SizeTypeWidth); - if (FormatSize > *SourceSize && *SourceSize != 0) { + if (FormatSize > *MaxOperationSize && *MaxOperationSize != 0) { unsigned TruncationDiagID = H.isKernelCompatible() ? diag::warn_format_truncation : diag::warn_format_truncation_non_kprintf; SmallString<16> SpecifiedSizeStr; SmallString<16> FormatSizeStr; - SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10); + MaxOperationSize->toString(SpecifiedSizeStr, /*Radix=*/10); FormatSize.toString(FormatSizeStr, /*Radix=*/10); DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, PDiag(TruncationDiagID) @@ -1472,22 +1547,57 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, const Expr *Dest = TheCall->getArg(0)->IgnoreCasts(); IdentifierInfo *FnInfo = FD->getIdentifier(); CheckSizeofMemaccessArgument(LenArg, Dest, FnInfo); + break; } } - if (!SourceSize || !DestinationSize || - llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0) - return; - std::string FunctionName = GetFunctionName(); + SmallString<16> MaxOpStr; + SmallString<16> MinOpStr; + + if (MinOperationSize) + MinOperationSize->toString(MinOpStr, /*Radix=*/10); + if (MaxOperationSize) + MaxOperationSize->toString(MaxOpStr, /*Radix=*/10); + + if (DestinationSize) { + SmallString<16> DestinationStr; + DestinationSize->toString(DestinationStr, /*Radix=*/10); + // Check for definite overflow + if (MinOperationSize && + llvm::APSInt::compareValues(*MinOperationSize, *DestinationSize) > 0) { + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagOverflowID) + << FunctionName << DestinationStr << MinOpStr); + } + // Check for possible overflow + else if (MaxOperationSize && llvm::APSInt::compareValues( + *MaxOperationSize, *DestinationSize) > 0) { + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagMayOverflowID) + << FunctionName << DestinationStr << MaxOpStr); + } + } + + if (SourceSize) { + SmallString<16> SourceStr; + SourceSize->toString(SourceStr, /*Radix=*/10); + // Check for definite over-read + if (MinOperationSize && + llvm::APSInt::compareValues(*MinOperationSize, *SourceSize) > 0) { + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagOverReadID) + << FunctionName << SourceStr << MinOpStr); - SmallString<16> DestinationStr; - SmallString<16> SourceStr; - DestinationSize->toString(DestinationStr, /*Radix=*/10); - SourceSize->toString(SourceStr, /*Radix=*/10); - DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, - PDiag(DiagID) - << FunctionName << DestinationStr << SourceStr); + } + // Check for possible over-read + else if (MaxOperationSize && + llvm::APSInt::compareValues(*MaxOperationSize, *SourceSize) > 0) { + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagMayOverReadID) + << FunctionName << SourceStr << MaxOpStr); + } + } } static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 8a3ee4443eb16..b579255892084 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2073,12 +2073,17 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( std::optional<QualType> Ssize_tTy = lookupTy("ssize_t"); std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy); + auto ValidSsize_tSize = [&](ArgNo ArgN) { + return ArgumentCondition(ArgN, WithinRange, Range(0, Ssize_tMax), + "a value not greater than SSIZE_MAX"); + }; auto ReadSummary = Summary(NoEvalCall) .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)), ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))}, - ErrnoIrrelevant); + ErrnoIrrelevant) + .ArgConstraint(ValidSsize_tSize(ArgNo(2))); // FIXME these are actually defined by POSIX and not by the C standard, we // should handle them together with the rest of the POSIX functions. @@ -3004,6 +3009,35 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, IntMax)))); + // ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset); + addToFunctionSummaryMap( + "pread", + Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy, Off_tTy}, + RetType{Ssize_tTy}), + ReadSummary); + + // ssize_t pread64(int fildes, void *buf, size_t nbyte, off64_t offset); + addToFunctionSummaryMap( + "pread64", + Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy, Off64_tTy}, + RetType{Ssize_tTy}), + ReadSummary); + + // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset); + addToFunctionSummaryMap( + "pwrite"... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/196499 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
