2017-03-04 02:02:02 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.SimpleStream -verify %s
|
2012-10-30 06:51:50 +08:00
|
|
|
|
2012-11-06 12:20:57 +08:00
|
|
|
#include "Inputs/system-header-simulator-for-simple-stream.h"
|
2012-10-30 06:51:50 +08:00
|
|
|
|
|
|
|
void checkDoubleFClose(int *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
if (F != 0) {
|
|
|
|
fputs ("fopen example", F);
|
|
|
|
if (!Data)
|
|
|
|
fclose(F);
|
|
|
|
else
|
|
|
|
fputc(*Data, F);
|
|
|
|
fclose(F); // expected-warning {{Closing a previously closed file stream}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int checkLeak(int *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
if (F != 0) {
|
|
|
|
fputs ("fopen example", F);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Data) // expected-warning {{Opened file is never closed; potential resource leak}}
|
|
|
|
return *Data;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkLeakFollowedByAssert(int *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
if (F != 0) {
|
|
|
|
fputs ("fopen example", F);
|
|
|
|
if (!Data)
|
|
|
|
exit(0);
|
|
|
|
fclose(F);
|
|
|
|
}
|
|
|
|
}
|
2012-10-31 10:32:41 +08:00
|
|
|
|
|
|
|
void CloseOnlyOnValidFileHandle() {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
if (F)
|
|
|
|
fclose(F);
|
|
|
|
int x = 0; // no warning
|
|
|
|
}
|
2012-11-03 10:54:20 +08:00
|
|
|
|
|
|
|
void leakOnEnfOfPath1(int *Data) {
|
2012-11-16 03:11:43 +08:00
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
} // expected-warning {{Opened file is never closed; potential resource leak}}
|
2012-11-03 10:54:20 +08:00
|
|
|
|
|
|
|
void leakOnEnfOfPath2(int *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
return; // expected-warning {{Opened file is never closed; potential resource leak}}
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *leakOnEnfOfPath3(int *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
return F;
|
|
|
|
}
|
2012-11-06 12:20:57 +08:00
|
|
|
|
|
|
|
void myfclose(FILE *F);
|
|
|
|
void SymbolEscapedThroughFunctionCall() {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
myfclose(F);
|
|
|
|
return; // no warning
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *GlobalF;
|
2017-03-31 02:11:20 +08:00
|
|
|
void SymbolEscapedThroughAssignmentToGlobal() {
|
2012-11-06 12:20:57 +08:00
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
GlobalF = F;
|
|
|
|
return; // no warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void SymbolDoesNotEscapeThoughStringAPIs(char *Data) {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
fputc(*Data, F);
|
|
|
|
return; // expected-warning {{Opened file is never closed; potential resource leak}}
|
|
|
|
}
|
2013-02-08 07:05:43 +08:00
|
|
|
|
|
|
|
void passConstPointer(const FILE * F);
|
|
|
|
void testPassConstPointer() {
|
|
|
|
FILE *F = fopen("myfile.txt", "w");
|
|
|
|
passConstPointer(F);
|
|
|
|
return; // expected-warning {{Opened file is never closed; potential resource leak}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testPassToSystemHeaderFunctionIndirectly() {
|
|
|
|
FileStruct fs;
|
|
|
|
fs.p = fopen("myfile.txt", "w");
|
[analyzer] Indirect invalidation counts as an escape for leak checkers.
Consider this example:
char *p = malloc(sizeof(char));
systemFunction(&p);
free(p);
In this case, when we call systemFunction, we know (because it's a system
function) that it won't free 'p'. However, we /don't/ know whether or not
it will /change/ 'p', so the analyzer is forced to invalidate 'p', wiping
out any bindings it contains. But now the malloc'd region looks like a
leak, since there are no more bindings pointing to it, and we'll get a
spurious leak warning.
The fix for this is to notice when something is becoming inaccessible due
to invalidation (i.e. an imperfect model, as opposed to being explicitly
overwritten) and stop tracking it at that point. Currently, the best way
to determine this for a call is the "indirect escape" pointer-escape kind.
In practice, all the patch does is take the "system functions don't free
memory" special case and limit it to direct parameters, i.e. just the
arguments to a call and not other regions accessible to them. This is a
conservative change that should only cause us to escape regions more
eagerly, which means fewer leak warnings.
This isn't perfect for several reasons, the main one being that this
example is treated the same as the one above:
char **p = malloc(sizeof(char *));
systemFunction(p + 1);
// leak
Currently, "addresses accessible by offsets of the starting region" and
"addresses accessible through bindings of the starting region" are both
considered "indirect" regions, hence this uniform treatment.
Another issue is our longstanding problem of not distinguishing const and
non-const bindings; if in the first example systemFunction's parameter were
a char * const *, we should know that the function will not overwrite 'p',
and thus we can safely report the leak.
<rdar://problem/13758386>
llvm-svn: 181607
2013-05-11 01:07:16 +08:00
|
|
|
fakeSystemHeaderCall(&fs); // invalidates fs, making fs.p unreachable
|
|
|
|
} // no-warning
|
2018-11-30 11:27:50 +08:00
|
|
|
|
|
|
|
void testOverwrite() {
|
|
|
|
FILE *fp = fopen("myfile.txt", "w");
|
|
|
|
fp = 0;
|
|
|
|
} // expected-warning {{Opened file is never closed; potential resource leak}}
|