SValBuilder &SVB = C.getSValBuilder();
BasicValueFactory &BVF = SVB.getBasicValueFactory();
const ASTContext &ACtx = BVF.getContext();
+ Preprocessor &PP = C.getPreprocessor();
// Helper class to lookup a type by its name.
class LookupType {
const RangeInt UCharRangeMax =
std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
- // The platform dependent value of EOF.
- // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
- const auto EOFv = [&C]() -> RangeInt {
- if (const std::optional<int> OptInt =
- tryExpandAsInteger("EOF", C.getPreprocessor()))
- return *OptInt;
- return -1;
- }();
+ // Get platform dependent values of some macros.
+ // Try our best to parse this from the Preprocessor, otherwise fallback to a
+ // default value (what is found in a library header).
+ const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
+ const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
// Auxiliary class to aid adding summaries to the summary map.
struct AddToFunctionSummaryMap {
ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
+ auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
+ return std::make_shared<RangeConstraint>(
+ ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
+ "a valid file descriptor or AT_FDCWD");
+ };
+
// FILE *fopen(const char *restrict pathname, const char *restrict mode);
addToFunctionSummaryMap(
"fopen",
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
// int dup(int fildes);
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2))));
// int lockf(int fd, int cmd, off_t len);
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
std::optional<QualType> Dev_tTy = lookupTy("dev_t");
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
// int chmod(const char *path, mode_t mode);
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
// int fchmod(int fildes, mode_t mode);
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
// int chown(const char *path, uid_t owner, gid_t group);
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
.ArgConstraint(NotNull(ArgNo(3))));
// int unlink(const char *pathname);
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
std::optional<QualType> StructStatTy = lookupTy("stat");
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2))));
ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2)))
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
+ .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
.ArgConstraint(NotNull(ArgNo(3))));
// char *realpath(const char *restrict file_name,
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
// RUN: -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \
+// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true \
// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -triple x86_64-unknown-linux-gnu \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
// RUN: -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \
+// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true \
// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -triple x86_64-unknown-linux-gnu \
// bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10}} \
// bugpath-note{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10}}
}
+
+void test_file_fd_at_functions() {
+ (void)linkat(-22, "from", AT_FDCWD, "to", 0); // \
+ // report-warning{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}} \
+ // bugpath-warning{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}} \
+ // bugpath-note{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}}
+
+ // no warning for these functions if the AT_FDCWD value is used
+ (void)linkat(AT_FDCWD, "from", AT_FDCWD, "to", 0);
+ (void)faccessat(AT_FDCWD, "path", 0, 0);
+ (void)symlinkat("oldpath", AT_FDCWD, "newpath");
+ (void)mkdirat(AT_FDCWD, "path", 0);
+ (void)mknodat(AT_FDCWD, "path", 0, 0);
+ (void)fchmodat(AT_FDCWD, "path", 0, 0);
+ (void)fchownat(AT_FDCWD, "path", 0, 0, 0);
+ (void)linkat(AT_FDCWD, "oldpath", AT_FDCWD, "newpath", 0);
+ (void)unlinkat(AT_FDCWD, "newpath", 0);
+ struct stat St;
+ (void)fstatat(AT_FDCWD, "newpath", &St, 0);
+ char Buf[10];
+ (void)readlinkat(AT_FDCWD, "newpath", Buf, 10);
+ (void)renameat(AT_FDCWD, "oldpath", AT_FDCWD, "newpath");
+}