Skip to content

Commit 775fcf1

Browse files
committed
Add additional nonnull attributes for printf/scanf family functions
Extend nonnull coverage to include not only format string parameters, but also FILE* and char* arguments (e.g. for sscanf, fprintf, etc.).
1 parent c7a6ed9 commit 775fcf1

File tree

5 files changed

+42
-19
lines changed

5 files changed

+42
-19
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,21 +3109,21 @@ def BuiltinPrintf : Builtin {
31093109

31103110
def FPrintf : LibBuiltin<"stdio.h"> {
31113111
let Spellings = ["fprintf"];
3112-
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[1]>];
3112+
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[0, 1]>];
31133113
let Prototype = "int(FILE* restrict, char const* restrict, ...)";
31143114
let AddBuiltinPrefixedAlias = 1;
31153115
}
31163116

31173117
def SnPrintf : LibBuiltin<"stdio.h"> {
31183118
let Spellings = ["snprintf"];
3119-
let Attributes = [NoThrow, PrintfFormat<2>, NonNull<[2]>];
3119+
let Attributes = [NoThrow, PrintfFormat<2>, NonNull<[0, 2]>];
31203120
let Prototype = "int(char* restrict, size_t, char const* restrict, ...)";
31213121
let AddBuiltinPrefixedAlias = 1;
31223122
}
31233123

31243124
def SPrintf : LibBuiltin<"stdio.h"> {
31253125
let Spellings = ["sprintf"];
3126-
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[1]>];
3126+
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[0, 1]>];
31273127
let Prototype = "int(char* restrict, char const* restrict, ...)";
31283128
let AddBuiltinPrefixedAlias = 1;
31293129
}
@@ -3137,21 +3137,21 @@ def VPrintf : LibBuiltin<"stdio.h"> {
31373137

31383138
def VfPrintf : LibBuiltin<"stdio.h"> {
31393139
let Spellings = ["vfprintf"];
3140-
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[1]>];
3140+
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[0, 1]>];
31413141
let Prototype = "int(FILE* restrict, char const* restrict, __builtin_va_list)";
31423142
let AddBuiltinPrefixedAlias = 1;
31433143
}
31443144

31453145
def VsnPrintf : LibBuiltin<"stdio.h"> {
31463146
let Spellings = ["vsnprintf"];
3147-
let Attributes = [NoThrow, VPrintfFormat<2>, NonNull<[2]>];
3147+
let Attributes = [NoThrow, VPrintfFormat<2>, NonNull<[0, 2]>];
31483148
let Prototype = "int(char* restrict, size_t, char const* restrict, __builtin_va_list)";
31493149
let AddBuiltinPrefixedAlias = 1;
31503150
}
31513151

31523152
def VsPrintf : LibBuiltin<"stdio.h"> {
31533153
let Spellings = ["vsprintf"];
3154-
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[1]>];
3154+
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[0, 1]>];
31553155
let Prototype = "int(char* restrict, char const* restrict, __builtin_va_list)";
31563156
let AddBuiltinPrefixedAlias = 1;
31573157
}
@@ -3165,14 +3165,14 @@ def Scanf : LibBuiltin<"stdio.h"> {
31653165

31663166
def FScanf : LibBuiltin<"stdio.h"> {
31673167
let Spellings = ["fscanf"];
3168-
let Attributes = [ScanfFormat<1>, NonNull<[1]>];
3168+
let Attributes = [ScanfFormat<1>, NonNull<[0, 1]>];
31693169
let Prototype = "int(FILE* restrict, char const* restrict, ...)";
31703170
let AddBuiltinPrefixedAlias = 1;
31713171
}
31723172

31733173
def SScanf : LibBuiltin<"stdio.h"> {
31743174
let Spellings = ["sscanf"];
3175-
let Attributes = [ScanfFormat<1>, NonNull<[1]>];
3175+
let Attributes = [ScanfFormat<1>, NonNull<[0, 1]>];
31763176
let Prototype = "int(char const* restrict, char const* restrict, ...)";
31773177
let AddBuiltinPrefixedAlias = 1;
31783178
}
@@ -3186,14 +3186,14 @@ def VScanf : LibBuiltin<"stdio.h"> {
31863186

31873187
def VFScanf : LibBuiltin<"stdio.h"> {
31883188
let Spellings = ["vfscanf"];
3189-
let Attributes = [VScanfFormat<1>, NonNull<[1]>];
3189+
let Attributes = [VScanfFormat<1>, NonNull<[0, 1]>];
31903190
let Prototype = "int(FILE* restrict, char const* restrict, __builtin_va_list)";
31913191
let AddBuiltinPrefixedAlias = 1;
31923192
}
31933193

31943194
def VSScanf : LibBuiltin<"stdio.h"> {
31953195
let Spellings = ["vsscanf"];
3196-
let Attributes = [VScanfFormat<1>, NonNull<[1]>];
3196+
let Attributes = [VScanfFormat<1>, NonNull<[0, 1]>];
31973197
let Prototype = "int(char const* restrict, char const* restrict, __builtin_va_list)";
31983198
let AddBuiltinPrefixedAlias = 1;
31993199
}

clang/test/Analysis/stream.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ void check_fputs(void) {
5252

5353
void check_fprintf(void) {
5454
FILE *fp = tmpfile();
55-
fprintf(fp, "ABC"); // expected-warning {{Stream pointer might be NULL}}
55+
fprintf(fp, "ABC"); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
5656
fclose(fp);
5757
}
5858

5959
void check_fscanf(void) {
6060
FILE *fp = tmpfile();
61-
fscanf(fp, "ABC"); // expected-warning {{Stream pointer might be NULL}}
61+
fscanf(fp, "ABC"); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
6262
fclose(fp);
6363
}
6464

@@ -152,13 +152,13 @@ void f_dopen(int fd) {
152152

153153
void f_vfprintf(int fd, va_list args) {
154154
FILE *F = fdopen(fd, "r");
155-
vfprintf(F, "%d", args); // expected-warning {{Stream pointer might be NULL}}
155+
vfprintf(F, "%d", args); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
156156
fclose(F);
157157
}
158158

159159
void f_vfscanf(int fd, va_list args) {
160160
FILE *F = fdopen(fd, "r");
161-
vfscanf(F, "%u", args); // expected-warning {{Stream pointer might be NULL}}
161+
vfscanf(F, "%u", args); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
162162
fclose(F);
163163
}
164164

clang/test/Sema/format-strings-nonnull.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ int vsscanf(char const* restrict, char const* restrict, __builtin_va_list);
2525

2626
void check_format_string(FILE *fp, va_list ap) {
2727
char buf[256];
28+
int num;
2829
char* const fmt = NULL;
2930

3031
printf(fmt);
@@ -36,11 +37,13 @@ void check_format_string(FILE *fp, va_list ap) {
3637
fprintf(fp, NULL, 25);
3738
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
3839

39-
sprintf(buf, NULL, 42);
40+
sprintf(NULL, NULL, 42);
4041
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
42+
// expected-warning@-2{{null passed to a callee that requires a non-null argument}}
4143

42-
snprintf(buf, 10, 0, 42);
44+
snprintf(NULL, 10, 0, 42);
4345
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
46+
// expected-warning@-2{{null passed to a callee that requires a non-null argument}}
4447

4548
vprintf(fmt, ap);
4649
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
@@ -51,15 +54,19 @@ void check_format_string(FILE *fp, va_list ap) {
5154
vsprintf(buf, nullptr, ap);
5255
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
5356

54-
vsnprintf(buf, 10, fmt, ap);
57+
vsnprintf(NULL, 10, fmt, ap);
5558
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
59+
// expected-warning@-2{{null passed to a callee that requires a non-null argument}}
5660

5761
scanf(NULL);
5862
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
5963

60-
fscanf(fp, nullptr);
64+
fscanf(nullptr, nullptr);
6165
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
66+
// expected-warning@-2{{null passed to a callee that requires a non-null argument}}
6267

68+
sscanf(NULL, "%d %s", &num, buf);
69+
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
6370
sscanf(buf, fmt);
6471
// expected-warning@-1{{null passed to a callee that requires a non-null argument}}
6572

clang/test/Sema/format-strings-nonnull.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ typedef __builtin_va_list va_list;
1313
EXTERN_C int printf(const char *, ...);
1414
EXTERN_C int fprintf(FILE *, const char *restrict, ...);
1515
EXTERN_C int sprintf(char* restrict, char const* res, ...);
16+
EXTERN_C int vfprintf(FILE* restrict, char const* res, __builtin_va_list);
1617

1718
EXTERN_C int scanf(char const *restrict, ...);
1819
EXTERN_C int fscanf(FILE* restrict, char const* res, ...);
20+
EXTERN_C int sscanf(char const* restrict, char const* res, ...);
1921

20-
void test(FILE *fp) {
22+
void test(FILE *fp, va_list ap) {
2123
char buf[256];
24+
int num;
2225

2326
__builtin_printf(__null, "x");
2427
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
@@ -37,4 +40,10 @@ void test(FILE *fp) {
3740

3841
fscanf(fp, __null);
3942
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
43+
44+
vfprintf(__null, "xxd", ap);
45+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
46+
47+
sscanf(__null, "%d", &num);
48+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
4049
}

clang/test/Sema/warn-fortify-scanf.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,17 @@ void call_fscanf(void) {
5959
char buf20[20];
6060
char buf30[30];
6161
fscanf(0, "%4s %5s %10s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 5 has size 10, but the corresponding specifier may require size 11}}
62+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6263
fscanf(0, "%4s %5s %11s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 5 has size 10, but the corresponding specifier may require size 12}}
64+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6365
fscanf(0, "%4s %5s %9s", buf20, buf30, buf10);
66+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6467
fscanf(0, "%20s %5s %9s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 3 has size 20, but the corresponding specifier may require size 21}}
68+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6569
fscanf(0, "%21s %5s %9s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 3 has size 20, but the corresponding specifier may require size 22}}
70+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6671
fscanf(0, "%19s %5s %9s", buf20, buf30, buf10);
72+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6773
fscanf(0, "%19s %29s %9s", buf20, buf30, buf10);
74+
// expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
6875
}

0 commit comments

Comments
 (0)