}
};
- // Represents a buffer argument with an additional size argument.
- // E.g. the first two arguments here:
+ // Represents a buffer argument with an additional size constraint. The
+ // constraint may be a concrete value, or a symbolic value in an argument.
+ // Example 1. Concrete value as the minimum buffer size.
+ // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
+ // // `buf` size must be at least 26 bytes according the POSIX standard.
+ // Example 2. Argument as a buffer size.
// ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
- // Another example:
+ // Example 3. The size is computed as a multiplication of other args.
// size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
// // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
class BufferSizeConstraint : public ValueConstraint {
+ // The concrete value which is the minimum size for the buffer.
+ llvm::Optional<llvm::APSInt> ConcreteSize;
// The argument which holds the size of the buffer.
- ArgNo SizeArgN;
+ llvm::Optional<ArgNo> SizeArgN;
// The argument which is a multiplier to size. This is set in case of
// `fread` like functions where the size is computed as a multiplication of
// two arguments.
BinaryOperator::Opcode Op = BO_LE;
public:
+ BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
+ : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
: ValueConstraint(Buffer), SizeArgN(BufSize) {}
-
BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
: ValueConstraint(Buffer), SizeArgN(BufSize),
SizeMultiplierArgN(BufSizeMultiplier) {}
SValBuilder &SvalBuilder = C.getSValBuilder();
// The buffer argument.
SVal BufV = getArgSVal(Call, getArgNo());
- // The size argument.
- SVal SizeV = getArgSVal(Call, SizeArgN);
- // Multiply with another argument if given.
- if (SizeMultiplierArgN) {
- SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
- SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
- Summary.getArgType(SizeArgN));
- }
+
+ // Get the size constraint.
+ const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
+ if (ConcreteSize) {
+ return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
+ } else if (SizeArgN) {
+ // The size argument.
+ SVal SizeV = getArgSVal(Call, *SizeArgN);
+ // Multiply with another argument if given.
+ if (SizeMultiplierArgN) {
+ SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
+ SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
+ Summary.getArgType(*SizeArgN));
+ }
+ return SizeV;
+ } else {
+ llvm_unreachable("The constraint must be either a concrete value or "
+ "encoded in an arguement.");
+ }
+ }();
+
// The dynamic size of the buffer argument, got from the analyzer engine.
SVal BufDynSize = getDynamicSizeWithOffset(State, BufV);
BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
.ArgConstraint(
ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
+
+ Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
+ Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
+
+ // int utime(const char *filename, struct utimbuf *buf);
+ addToFunctionSummaryMap(
+ "utime", Summary(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ Optional<QualType> StructTimespecTy = lookupTy("timespec");
+ Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
+ Optional<QualType> ConstStructTimespecPtrTy =
+ getPointerTy(getConstTy(StructTimespecTy));
+
+ // int futimens(int fd, const struct timespec times[2]);
+ addToFunctionSummaryMap(
+ "futimens", Summary(ArgTypes{IntTy, ConstStructTimespecPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(ArgumentCondition(0, WithinRange,
+ Range(0, IntMax))));
+
+ // int utimensat(int dirfd, const char *pathname,
+ // const struct timespec times[2], int flags);
+ addToFunctionSummaryMap("utimensat",
+ Summary(ArgTypes{IntTy, ConstCharPtrTy,
+ ConstStructTimespecPtrTy, IntTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ Optional<QualType> StructTimevalTy = lookupTy("timeval");
+ Optional<QualType> ConstStructTimevalPtrTy =
+ getPointerTy(getConstTy(StructTimevalTy));
+
+ // int utimes(const char *filename, const struct timeval times[2]);
+ addToFunctionSummaryMap(
+ "utimes", Summary(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+ addToFunctionSummaryMap(
+ "nanosleep",
+ Summary(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ Optional<QualType> Time_tTy = lookupTy("time_t");
+ Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
+ Optional<QualType> ConstTime_tPtrRestrictTy =
+ getRestrictTy(ConstTime_tPtrTy);
+
+ Optional<QualType> StructTmTy = lookupTy("tm");
+ Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
+ Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
+ Optional<QualType> ConstStructTmPtrTy =
+ getPointerTy(getConstTy(StructTmTy));
+ Optional<QualType> ConstStructTmPtrRestrictTy =
+ getRestrictTy(ConstStructTmPtrTy);
+
+ // struct tm * localtime(const time_t *tp);
+ addToFunctionSummaryMap(
+ "localtime",
+ Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // struct tm *localtime_r(const time_t *restrict timer,
+ // struct tm *restrict result);
+ addToFunctionSummaryMap(
+ "localtime_r",
+ Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
+ RetType{StructTmPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
+ addToFunctionSummaryMap(
+ "asctime_r",
+ Summary(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
+ RetType{CharPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1)))
+ .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
+ /*MinBufSize=*/BVF.getValue(26, IntTy))));
+
+ // char *ctime_r(const time_t *timep, char *buf);
+ addToFunctionSummaryMap("ctime_r",
+ Summary(ArgTypes{ConstTime_tPtrTy, CharPtrTy},
+ RetType{CharPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1)))
+ .ArgConstraint(BufferSize(
+ /*Buffer=*/ArgNo(1),
+ /*MinBufSize=*/BVF.getValue(26, IntTy))));
+
+ // struct tm *gmtime_r(const time_t *restrict timer,
+ // struct tm *restrict result);
+ addToFunctionSummaryMap(
+ "gmtime_r",
+ Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
+ RetType{StructTmPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // struct tm * gmtime(const time_t *tp);
+ addToFunctionSummaryMap(
+ "gmtime",
+ Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
+
+ // int clock_gettime(clockid_t clock_id, struct timespec *tp);
+ addToFunctionSummaryMap("clock_gettime",
+ Summary(ArgTypes{Clockid_tTy, StructTimespecPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ Optional<QualType> StructItimervalTy = lookupTy("itimerval");
+ Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
+
+ // int getitimer(int which, struct itimerval *curr_value);
+ addToFunctionSummaryMap("getitimer",
+ Summary(ArgTypes{IntTy, StructItimervalPtrTy},
+ RetType{IntTy}, NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(1))));
}
// Functions for testing.
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
/*BufSizeMultiplier=*/ArgNo(2))));
addToFunctionSummaryMap(
+ "__buf_size_arg_constraint_concrete",
+ Summary(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}, EvalCallAsPure)
+ .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
+ /*BufSize=*/BVF.getValue(10, IntTy))));
+ addToFunctionSummaryMap(
{"__test_restrict_param_0", "__test_restrict_param_1",
"__test_restrict_param_2"},
Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
// CHECK: Loaded summary for: ssize_t send(int sockfd, const void *buf, size_t len, int flags)
// CHECK: Loaded summary for: int socketpair(int domain, int type, int protocol, int sv[2])
// CHECK: Loaded summary for: int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags)
+// CHECK: Loaded summary for: int utime(const char *filename, struct utimbuf *buf)
+// CHECK: Loaded summary for: int futimens(int fd, const struct timespec times[2])
+// CHECK: Loaded summary for: int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
+// CHECK: Loaded summary for: int utimes(const char *filename, const struct timeval times[2])
+// CHECK: Loaded summary for: int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+// CHECK: Loaded summary for: struct tm *localtime(const time_t *tp)
+// CHECK: Loaded summary for: struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result)
+// CHECK: Loaded summary for: char *asctime_r(const struct tm *restrict tm, char *restrict buf)
+// CHECK: Loaded summary for: char *ctime_r(const time_t *timep, char *buf)
+// CHECK: Loaded summary for: struct tm *gmtime_r(const time_t *restrict timer, struct tm *restrict result)
+// CHECK: Loaded summary for: struct tm *gmtime(const time_t *tp)
+// CHECK: Loaded summary for: int clock_gettime(clockid_t clock_id, struct timespec *tp)
+// CHECK: Loaded summary for: int getitimer(int which, struct itimerval *curr_value)
long a64l(const char *str64);
char *l64a(long value);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
int socketpair(int domain, int type, int protocol, int sv[2]);
int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags);
+struct utimbuf;
+struct timespec { int x; };
+struct timeval { int x; };
+int utime(const char *filename, struct utimbuf *buf);
+int futimens(int fd, const struct timespec times[2]);
+int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);
+int utimes(const char *filename, const struct timeval times[2]);
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+typedef unsigned long time_t;
+struct tm *localtime(const time_t *tp);
+struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result);
+char *asctime_r(const struct tm *restrict tm, char *restrict buf);
+char *ctime_r(const time_t *timep, char *buf);
+struct tm *gmtime_r(const time_t *restrict timer, struct tm *restrict result);
+struct tm *gmtime(const time_t *tp);
+typedef unsigned long clockid_t;
+int clock_gettime(clockid_t clock_id, struct timespec *tp);
+struct itimerval;
+int getitimer(int which, struct itimerval *curr_value);
// Must have at least one call expression to initialize the summary map.
int bar(void);