Skip to content

Commit 61924da

Browse files
committed
[analyzer] Propagate taint for wchar variants of some APIs (#66074)
Functions like `fgets`, `strlen`, `strcat` propagate taint. However, their `wchar_t` variants don't. This patch fixes that. Notice, that there could be many more APIs missing. This patch intends to fix those that so far surfaced, instead of exhaustively fixing this issue. #66074
1 parent 8243bc4 commit 61924da

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
628628
{{{"fgetc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
629629
{{{"fgetln"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
630630
{{{"fgets"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
631+
{{{"fgetws"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
631632
{{{"fscanf"}}, TR::Prop({{0}}, {{}, 2})},
632633
{{{"fscanf_s"}}, TR::Prop({{0}}, {{}, {2}})},
633634
{{{"sscanf"}}, TR::Prop({{0}}, {{}, 2})},
@@ -695,6 +696,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
695696
{{{"strndup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
696697
{{{"strndupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
697698
{{{"strlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
699+
{{{"wcslen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
698700
{{{"strnlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
699701
{{{"strtol"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
700702
{{{"strtoll"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
@@ -731,6 +733,8 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
731733
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
732734
{{CDF_MaybeBuiltin, {{"strcat"}}},
733735
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
736+
{{CDF_MaybeBuiltin, {{"wcsncat"}}},
737+
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
734738
{{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
735739
{{CDF_MaybeBuiltin, {{"strdupa"}}},
736740
TR::Prop({{0}}, {{ReturnValueIndex}})},

clang/test/Analysis/taint-generic.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@
5656
// CHECK-INVALID-ARG-SAME: rules greater or equal to -1
5757

5858
typedef long long rsize_t;
59+
typedef typeof(sizeof(int)) size_t;
60+
typedef __WCHAR_TYPE__ wchar_t;
5961
void clang_analyzer_isTainted_char(char);
62+
void clang_analyzer_isTainted_wchar(wchar_t);
6063
void clang_analyzer_isTainted_charp(char*);
6164
void clang_analyzer_isTainted_int(int);
6265

@@ -75,6 +78,17 @@ extern FILE *stdin;
7578
#define bool _Bool
7679
#define NULL (void*)0
7780

81+
wchar_t *fgetws(wchar_t *ws, int n, FILE *stream);
82+
wchar_t *wmemset(wchar_t *wcs, wchar_t wc, unsigned long n);
83+
wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n);
84+
wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n);
85+
size_t wcslen(const wchar_t *s);
86+
wchar_t *wcscpy(wchar_t * dest, const wchar_t * src);
87+
wchar_t *wcsncpy(wchar_t *dest, const wchar_t *src, size_t n);
88+
wchar_t *wcscat(wchar_t *dest, const wchar_t *src);
89+
wchar_t *wcsncat(wchar_t *dest,const wchar_t *src, size_t n);
90+
int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);
91+
7892
char *getenv(const char *name);
7993

8094
FILE *fopen(const char *name, const char *mode);
@@ -430,6 +444,24 @@ int testSprintf_propagates_taint(char *buf, char *msg) {
430444
return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
431445
}
432446

447+
void test_wchar_apis_propagate(const char *path) {
448+
FILE *f = fopen(path, "r");
449+
clang_analyzer_isTainted_charp((char*)f); // expected-warning {{YES}}
450+
wchar_t wbuf[10];
451+
fgetws(wbuf, sizeof(wbuf)/sizeof(*wbuf), f);
452+
clang_analyzer_isTainted_wchar(*wbuf); // expected-warning {{YES}}
453+
int n = wcslen(wbuf);
454+
clang_analyzer_isTainted_int(n); // expected-warning {{YES}}
455+
456+
wchar_t dst[100] = L"ABC";
457+
clang_analyzer_isTainted_wchar(*dst); // expected-warning {{NO}}
458+
wcsncat(dst, wbuf, sizeof(wbuf)/sizeof(*wbuf));
459+
clang_analyzer_isTainted_wchar(*dst); // expected-warning {{YES}}
460+
461+
int m = wcslen(dst);
462+
clang_analyzer_isTainted_int(m); // expected-warning {{YES}}
463+
}
464+
433465
int scanf_s(const char *format, ...);
434466
int testScanf_s_(int *out) {
435467
scanf_s("%d", out);
@@ -644,7 +676,6 @@ void testRawmemchr(int c) {
644676
clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}
645677
}
646678

647-
typedef char wchar_t;
648679
int mbtowc(wchar_t *pwc, const char *s, size_t n);
649680
void testMbtowc(wchar_t *pwc, size_t n) {
650681
char buf[10];
@@ -657,8 +688,7 @@ void testMbtowc(wchar_t *pwc, size_t n) {
657688

658689
int wctomb(char *s, wchar_t wc);
659690
void testWctomb(char *buf) {
660-
wchar_t wc;
661-
scanf("%c", &wc);
691+
wchar_t wc = getchar();
662692

663693
int result = wctomb(buf, wc);
664694
clang_analyzer_isTainted_char(*buf); // expected-warning {{YES}}
@@ -667,8 +697,7 @@ void testWctomb(char *buf) {
667697

668698
int wcwidth(wchar_t c);
669699
void testWcwidth() {
670-
wchar_t wc;
671-
scanf("%c", &wc);
700+
wchar_t wc = getchar();
672701

673702
int width = wcwidth(wc);
674703
clang_analyzer_isTainted_int(width); // expected-warning {{YES}}

0 commit comments

Comments
 (0)