analyzer: stop exploring the path after certain diagnostics [PR108830]
PR analyzer/108830 reports a situation in which there are lots of followup -Wanalyzer-null-dereference warnings after the first access of a NULL pointer, leading to very noisy output from -fanalyzer. The analyzer's logic for stopping emitting multiple warnings from a state machine doesn't quite work for NULL pointers: it attempts to transition the malloc state machine's NULL pointer to the "stop" state, which doesn't seem to make much sense in retrospect, and seems to get confused over types. Similarly, poisoned_value_diagnostic can be very noisy for uninit variables, emitting a warning for every access to an uninitialized variable. In theory, region_model::check_for_poison makes some attempts to suppress followups, but only for the symbolic value itself; if the user's code keeps accessing the same region, we would get a warning on each one. For example, this showed up in Doom's s_sound.c where there were 7 followup uninit warnings after the first uninit warning in "S_ChangeMusic". This patch adds an extra mechanism, giving pending diagnostics the option of stopping the analysis of an execution path if they're saved for emission on it, and turning this on for these warnings: -Wanalyzer-null-dereference -Wanalyzer-null-argument -Wanalyzer-use-after-free -Wanalyzer-use-of-pointer-in-stale-stack-frame -Wanalyzer-use-of-uninitialized-value Doing so should hopefully reduce the cascades of diagnostics that -fanalyzer can sometimes emit. I added a -fno-analyzer-suppress-followups for the cases where you really want the followup warnings (e.g. in some DejaGnu tests, and for microbenchmarks of UB detection, such as PR analyzer/104224). Integration testing shows this patch reduces the number of probable false positives reported by 94, and finds one more true positive: Comparison: 9.34% -> 10.91% GOOD: 66 -> 67 (+1) BAD: 641 -> 547 (-94) where the affected warnings/projects are: -Wanalyzer-null-dereference: 0.00% GOOD: 0 BAD: 269 -> 239 (-30) Unclassified: 257 -> 228 (-29) apr-1.7.0: 12 -> 5 (-7) doom: 1 -> 0 (-1) haproxy-2.7.1: 47 -> 41 (-6) ImageMagick-7.1.0-57: 13 -> 9 (-4) qemu-7.2.0: 165 -> 154 (-11) Known false: 7 -> 6 (-1) xz-5.4.0: 4 -> 3 (-1) -Wanalyzer-use-of-uninitialized-value: 0.00% GOOD: 0 BAD: 143 -> 80 (-63) Known false: 47 -> 16 (-31) doom: 42 -> 11 (-31) Unclassified: 96 -> 64 (-32) coreutils-9.1: 14 -> 10 (-4) haproxy-2.7.1: 29 -> 23 (-6) qemu-7.2.0: 48 -> 26 (-22) -Wanalyzer-null-argument: 0.00% -> 2.33% GOOD: 0 -> 1 (+1) BAD: 43 -> 42 (-1) Unclassified: 39 -> 38 (-1) due to coreutils-9.1: 9 -> 8 (-1) True positive: 0 -> 1 (+1) (in haproxy-2.7.1) gcc/analyzer/ChangeLog: PR analyzer/108830 * analyzer.opt (fanalyzer-suppress-followups): New option. * engine.cc (impl_region_model_context::warn): Terminate the path if the diagnostic's terminate_path_p vfunc returns true and -fanalyzer-suppress-followups is true (the default). (impl_sm_context::warn): Likewise, for both overloads. * pending-diagnostic.h (pending_diagnostic::terminate_path_p): New vfunc. * program-state.cc (program_state::on_edge): Terminate the path if the ctxt requests it during updating the edge. * region-model.cc (poisoned_value_diagnostic::terminate_path_p): New vfunc. * sm-malloc.cc (null_deref::terminate_path_p): New vfunc. (null_arg::terminate_path_p): New vfunc. gcc/ChangeLog: PR analyzer/108830 * doc/invoke.texi: Document -fno-analyzer-suppress-followups. gcc/testsuite/ChangeLog: PR analyzer/108830 * gcc.dg/analyzer/attribute-nonnull.c: Update for -Wanalyzer-use-of-uninitialized-value terminating analysis along a path. * gcc.dg/analyzer/call-summaries-2.c: Likewise. * gcc.dg/analyzer/data-model-1.c: Likewise. * gcc.dg/analyzer/data-model-5.c: Likewise. * gcc.dg/analyzer/doom-s_sound-pr108867.c: New test. * gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Add -fno-analyzer-suppress-followups. * gcc.dg/analyzer/null-deref-pr108830.c: New test. * gcc.dg/analyzer/pipe-1.c: Add -fno-analyzer-suppress-followups. * gcc.dg/analyzer/pipe-void-return.c: Likewise. * gcc.dg/analyzer/pipe2-1.c: Likewise. * gcc.dg/analyzer/pr101547.c: Update for -Wanalyzer-use-of-uninitialized-value terminating analysis along a path. * gcc.dg/analyzer/pr101875.c: Likewise. * gcc.dg/analyzer/pr104224-split.c: New test, based on... * gcc.dg/analyzer/pr104224.c: Add -fno-analyzer-suppress-followups. * gcc.dg/analyzer/realloc-2.c: Add -fno-analyzer-suppress-followups. * gcc.dg/analyzer/realloc-3.c: Likewise. * gcc.dg/analyzer/realloc-5.c: Likewise. * gcc.dg/analyzer/stdarg-1-ms_abi.c: Likewise. * gcc.dg/analyzer/stdarg-1-sysv_abi.c: Likewise. * gcc.dg/analyzer/stdarg-1.c: Likewise. * gcc.dg/analyzer/symbolic-1.c: Likewise. * gcc.dg/analyzer/symbolic-7.c: Update for -Wanalyzer-use-of-uninitialized-value terminating analysis along a path. * gcc.dg/analyzer/uninit-4.c: Likewise. * gcc.dg/analyzer/uninit-8.c: New test. * gcc.dg/analyzer/uninit-pr94713.c: Update for -Wanalyzer-use-of-uninitialized-value terminating analysis along a path. * gcc.dg/analyzer/zlib-6a.c: Add -fno-analyzer-suppress-followups. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
b2ef02e8cb
commit
8f63691579
33 changed files with 1159 additions and 48 deletions
|
@ -262,6 +262,10 @@ fanalyzer-state-merge
|
|||
Common Var(flag_analyzer_state_merge) Init(1)
|
||||
Merge similar-enough states during analysis.
|
||||
|
||||
fanalyzer-suppress-followups
|
||||
Common Var(flag_analyzer_suppress_followups) Init(1)
|
||||
Stop exploring an execution path after certain diagnostics.
|
||||
|
||||
fanalyzer-transitivity
|
||||
Common Var(flag_analyzer_transitivity) Init(0)
|
||||
Enable transitivity of constraints during analysis.
|
||||
|
|
|
@ -125,11 +125,20 @@ impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d)
|
|||
return false;
|
||||
}
|
||||
if (m_eg)
|
||||
return m_eg->get_diagnostic_manager ().add_diagnostic
|
||||
(m_enode_for_diag, m_enode_for_diag->get_supernode (),
|
||||
m_stmt, m_stmt_finder, std::move (d));
|
||||
else
|
||||
return false;
|
||||
{
|
||||
bool terminate_path = d->terminate_path_p ();
|
||||
if (m_eg->get_diagnostic_manager ().add_diagnostic
|
||||
(m_enode_for_diag, m_enode_for_diag->get_supernode (),
|
||||
m_stmt, m_stmt_finder, std::move (d)))
|
||||
{
|
||||
if (m_path_ctxt
|
||||
&& terminate_path
|
||||
&& flag_analyzer_suppress_followups)
|
||||
m_path_ctxt->terminate_path ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -378,9 +387,14 @@ public:
|
|||
= (var
|
||||
? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
|
||||
: m_old_smap->get_global_state ());
|
||||
bool terminate_path = d->terminate_path_p ();
|
||||
m_eg.get_diagnostic_manager ().add_diagnostic
|
||||
(&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
|
||||
var, var_old_sval, current, std::move (d));
|
||||
if (m_path_ctxt
|
||||
&& terminate_path
|
||||
&& flag_analyzer_suppress_followups)
|
||||
m_path_ctxt->terminate_path ();
|
||||
}
|
||||
|
||||
void warn (const supernode *snode, const gimple *stmt,
|
||||
|
@ -393,9 +407,14 @@ public:
|
|||
= (sval
|
||||
? m_old_smap->get_state (sval, m_eg.get_ext_state ())
|
||||
: m_old_smap->get_global_state ());
|
||||
bool terminate_path = d->terminate_path_p ();
|
||||
m_eg.get_diagnostic_manager ().add_diagnostic
|
||||
(&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
|
||||
NULL_TREE, sval, current, std::move (d));
|
||||
if (m_path_ctxt
|
||||
&& terminate_path
|
||||
&& flag_analyzer_suppress_followups)
|
||||
m_path_ctxt->terminate_path ();
|
||||
}
|
||||
|
||||
/* Hook for picking more readable trees for SSA names of temporaries,
|
||||
|
|
|
@ -173,6 +173,10 @@ class pending_diagnostic
|
|||
having to generate feasible execution paths for them). */
|
||||
virtual int get_controlling_option () const = 0;
|
||||
|
||||
/* Vfunc to give the diagnostic the chance to terminate the execution
|
||||
path being explored. By default, don't terminate the path. */
|
||||
virtual bool terminate_path_p () const { return false; }
|
||||
|
||||
/* Vfunc for emitting the diagnostic. The rich_location will have been
|
||||
populated with a diagnostic_path.
|
||||
Return true if a diagnostic is actually emitted. */
|
||||
|
|
|
@ -1105,6 +1105,27 @@ program_state::on_edge (exploded_graph &eg,
|
|||
const superedge *succ,
|
||||
uncertainty_t *uncertainty)
|
||||
{
|
||||
class my_path_context : public path_context
|
||||
{
|
||||
public:
|
||||
my_path_context (bool &terminated) : m_terminated (terminated) {}
|
||||
void bifurcate (std::unique_ptr<custom_edge_info>) final override
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void terminate_path () final override
|
||||
{
|
||||
m_terminated = true;
|
||||
}
|
||||
|
||||
bool terminate_path_p () const final override
|
||||
{
|
||||
return m_terminated;
|
||||
}
|
||||
bool &m_terminated;
|
||||
};
|
||||
|
||||
/* Update state. */
|
||||
const program_point &point = enode->get_point ();
|
||||
const gimple *last_stmt = point.get_supernode ()->get_last_stmt ();
|
||||
|
@ -1117,11 +1138,12 @@ program_state::on_edge (exploded_graph &eg,
|
|||
Adding the relevant conditions for the edge could also trigger
|
||||
sm-state transitions (e.g. transitions due to ptrs becoming known
|
||||
to be NULL or non-NULL) */
|
||||
|
||||
bool terminated = false;
|
||||
my_path_context path_ctxt (terminated);
|
||||
impl_region_model_context ctxt (eg, enode,
|
||||
&enode->get_state (),
|
||||
this,
|
||||
uncertainty, NULL,
|
||||
uncertainty, &path_ctxt,
|
||||
last_stmt);
|
||||
if (!m_region_model->maybe_update_for_edge (*succ,
|
||||
last_stmt,
|
||||
|
@ -1134,6 +1156,8 @@ program_state::on_edge (exploded_graph &eg,
|
|||
succ->m_dest->m_index);
|
||||
return false;
|
||||
}
|
||||
if (terminated)
|
||||
return false;
|
||||
|
||||
program_state::detect_leaks (enode->get_state (), *this,
|
||||
NULL, eg.get_ext_state (),
|
||||
|
|
|
@ -505,6 +505,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool terminate_path_p () const final override { return true; }
|
||||
|
||||
bool emit (rich_location *rich_loc) final override
|
||||
{
|
||||
switch (m_pkind)
|
||||
|
|
|
@ -1150,6 +1150,8 @@ public:
|
|||
return OPT_Wanalyzer_null_dereference;
|
||||
}
|
||||
|
||||
bool terminate_path_p () const final override { return true; }
|
||||
|
||||
bool emit (rich_location *rich_loc) final override
|
||||
{
|
||||
/* CWE-476: NULL Pointer Dereference. */
|
||||
|
@ -1203,6 +1205,8 @@ public:
|
|||
return OPT_Wanalyzer_null_argument;
|
||||
}
|
||||
|
||||
bool terminate_path_p () const final override { return true; }
|
||||
|
||||
bool emit (rich_location *rich_loc) final override
|
||||
{
|
||||
/* CWE-476: NULL Pointer Dereference. */
|
||||
|
|
|
@ -428,6 +428,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-fanalyzer-fine-grained @gol
|
||||
-fno-analyzer-state-merge @gol
|
||||
-fno-analyzer-state-purge @gol
|
||||
-fno-analyzer-suppress-followups @gol
|
||||
-fanalyzer-transitivity @gol
|
||||
-fno-analyzer-undo-inlining @gol
|
||||
-fanalyzer-verbose-edges @gol
|
||||
|
@ -11012,6 +11013,30 @@ and which aren't relevant to leak analysis.
|
|||
With @option{-fno-analyzer-state-purge} this purging of state can
|
||||
be suppressed, for debugging state-handling issues.
|
||||
|
||||
@item -fno-analyzer-suppress-followups
|
||||
@opindex fanalyzer-suppress-followups
|
||||
@opindex fno-analyzer-suppress-followups
|
||||
This option is intended for analyzer developers.
|
||||
|
||||
By default the analyzer will stop exploring an execution path after
|
||||
encountering certain diagnostics, in order to avoid potentially issuing a
|
||||
cascade of follow-up diagnostics.
|
||||
|
||||
The diagnostics that terminate analysis along a path are:
|
||||
|
||||
@itemize
|
||||
@item @option{-Wanalyzer-null-argument}
|
||||
@item @option{-Wanalyzer-null-dereference}
|
||||
@item @option{-Wanalyzer-use-after-free}
|
||||
@item @option{-Wanalyzer-use-of-pointer-in-stale-stack-frame}
|
||||
@item @option{-Wanalyzer-use-of-uninitialized-value}
|
||||
@end itemize
|
||||
|
||||
With @option{-fno-analyzer-suppress-followups} the analyzer will
|
||||
continue to explore such paths even after such diagnostics, which may
|
||||
be helpful for debugging issues in the analyzer, or for microbenchmarks
|
||||
for detecting undefined behavior.
|
||||
|
||||
@item -fanalyzer-transitivity
|
||||
@opindex fanalyzer-transitivity
|
||||
@opindex fno-analyzer-transitivity
|
||||
|
|
|
@ -16,8 +16,6 @@ void test_1 (void *p, void *q, void *r)
|
|||
foo(p, q, r);
|
||||
foo(NULL, q, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
|
||||
/* { dg-message "argument 1 NULL where non-null expected" "note" { target *-*-* } .-1 } */
|
||||
foo(p, NULL, r);
|
||||
foo(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" } */
|
||||
}
|
||||
|
||||
void test_1a (void *q, void *r)
|
||||
|
@ -27,12 +25,29 @@ void test_1a (void *q, void *r)
|
|||
/* { dg-message "argument 1 \\('p'\\) NULL where non-null expected" "note" { target *-*-* } .-1 } */
|
||||
}
|
||||
|
||||
void test_2 (void *p, void *q, void *r)
|
||||
void test_1b (void *p, void *r)
|
||||
{
|
||||
foo(p, NULL, r);
|
||||
}
|
||||
|
||||
void test_1c (void *p, void *q, void *r)
|
||||
{
|
||||
foo(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" } */
|
||||
}
|
||||
|
||||
void test_2a (void *p, void *q, void *r)
|
||||
{
|
||||
bar(p, q, r);
|
||||
bar(NULL, q, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
|
||||
}
|
||||
|
||||
void test_2b (void *p, void *q, void *r)
|
||||
{
|
||||
bar(p, NULL, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
|
||||
/* { dg-message "argument 2 NULL where non-null expected" "note" { target *-*-* } .-1 } */
|
||||
}
|
||||
|
||||
void test_2c (void *p, void *q, void *r)
|
||||
{
|
||||
bar(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" "warning" } */
|
||||
}
|
||||
|
||||
|
|
|
@ -607,17 +607,22 @@ void partially_inits (int *p, int v)
|
|||
p[1] = v;
|
||||
}
|
||||
|
||||
void test_partially_inits (int x)
|
||||
void test_partially_inits_0 (int x)
|
||||
{
|
||||
int arr[2];
|
||||
partially_inits (arr, x);
|
||||
partially_inits (arr, x);
|
||||
|
||||
__analyzer_eval (arr[0]); /* { dg-warning "UNKNOWN" "eval" } */
|
||||
/* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" "uninit" { target *-*-* } .-1 } */
|
||||
__analyzer_eval (arr[0]); /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" } */
|
||||
}
|
||||
|
||||
__analyzer_eval (arr[1] == x); /* { dg-warning "UNKNOWN" "eval" } */
|
||||
/* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } .-1 } */
|
||||
void test_partially_inits_1 (int x)
|
||||
{
|
||||
int arr[2];
|
||||
partially_inits (arr, x);
|
||||
partially_inits (arr, x);
|
||||
|
||||
__analyzer_eval (arr[1] == x); /* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } } */
|
||||
// TODO(xfail), and eval should be "TRUE"
|
||||
}
|
||||
|
||||
|
|
|
@ -351,9 +351,8 @@ void test_19 (void)
|
|||
{
|
||||
int i, j; /* { dg-message "region created on stack here" } */
|
||||
/* Compare two uninitialized locals. */
|
||||
__analyzer_eval (i == j); /* { dg-warning "UNKNOWN" "unknown " } */
|
||||
/* { dg-warning "use of uninitialized value 'i'" "uninit i" { target *-*-* } .-1 } */
|
||||
/* { dg-warning "use of uninitialized value 'j'" "uninit j" { target *-*-* } .-2 } */
|
||||
__analyzer_eval (i == j); /* { dg-warning "use of uninitialized value 'i'" "uninit i" } */
|
||||
/* { dg-warning "use of uninitialized value 'j'" "uninit j" { target *-*-* } .-1 } */
|
||||
}
|
||||
|
||||
void test_20 (int i, int j)
|
||||
|
@ -653,11 +652,6 @@ void test_29b (void)
|
|||
__analyzer_eval (p[9].x == 109024); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (p[9].y == 109025); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p[10].x == 0); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value 'p\\\[10\\\].x'" "uninit" { target *-*-* } .-1 } */
|
||||
__analyzer_eval (p[10].y == 0); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value 'p\\\[10\\\].y'" "uninit" { target *-*-* } .-1 } */
|
||||
|
||||
q = &p[7];
|
||||
|
||||
__analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
|
||||
|
@ -679,6 +673,8 @@ void test_29b (void)
|
|||
|
||||
__analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (q->y == 107025); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p[10].x == 0); /* { dg-warning "use of uninitialized value 'p\\\[10\\\].x'" } */
|
||||
}
|
||||
|
||||
void test_29c (int len)
|
||||
|
@ -704,11 +700,6 @@ void test_29c (int len)
|
|||
__analyzer_eval (p[9].x == 109024); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (p[9].y == 109025); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p[10].x == 0); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].x'" "uninit" { target *-*-* } .-1 } */
|
||||
__analyzer_eval (p[10].y == 0); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].y'" "uninit" { target *-*-* } .-1 } */
|
||||
|
||||
q = &p[7];
|
||||
|
||||
__analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
|
||||
|
@ -730,6 +721,8 @@ void test_29c (int len)
|
|||
|
||||
__analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (q->y == 107025); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p[10].x == 0); /* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].x'" } */
|
||||
}
|
||||
|
||||
void test_30 (void *ptr)
|
||||
|
|
|
@ -90,10 +90,6 @@ void unref (base_obj *obj)
|
|||
{
|
||||
if (--obj->ob_refcnt == 0) /* { dg-bogus "dereference of uninitialized pointer 'obj'" } */
|
||||
obj->ob_type->tp_dealloc (obj);
|
||||
/* { dg-warning "dereference of NULL 'obj'" "deref of NULL" { target *-*-* } .-2 } */
|
||||
/* FIXME: ideally we wouldn't issue this, as we've already issued a
|
||||
warning about str_obj which is now in the "stop" state; the cast
|
||||
confuses things. */
|
||||
}
|
||||
|
||||
void test_1 (const char *str)
|
||||
|
|
653
gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
Normal file
653
gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
Normal file
|
@ -0,0 +1,653 @@
|
|||
/* Reduced from Doom's linuxdoom-1.10/s_sound.c, which is GPLv2 or later. */
|
||||
|
||||
/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
|
||||
|
||||
typedef struct _IO_FILE FILE;
|
||||
extern FILE* stderr;
|
||||
extern int
|
||||
fprintf(FILE* __restrict __stream, const char* __restrict __format, ...);
|
||||
extern int
|
||||
sprintf(char* __restrict __s, const char* __restrict __format, ...)
|
||||
__attribute__((__nothrow__));
|
||||
extern int
|
||||
abs(int __x) __attribute__((__nothrow__, __leaf__)) __attribute__((__const__));
|
||||
|
||||
typedef enum
|
||||
{
|
||||
false,
|
||||
true
|
||||
} boolean;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
void
|
||||
I_Error(char* error, ...);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
shareware,
|
||||
registered,
|
||||
commercial,
|
||||
/* [...snip...] */
|
||||
} GameMode_t;
|
||||
|
||||
typedef int fixed_t;
|
||||
|
||||
fixed_t
|
||||
FixedMul(fixed_t a, fixed_t b);
|
||||
|
||||
extern fixed_t finesine[5 * 8192 / 4];
|
||||
typedef unsigned angle_t;
|
||||
|
||||
typedef struct mobj_s
|
||||
{
|
||||
/* [...snip...] */
|
||||
fixed_t x;
|
||||
fixed_t y;
|
||||
fixed_t z;
|
||||
/* [...snip...] */
|
||||
angle_t angle;
|
||||
/* [...snip...] */
|
||||
} mobj_t;
|
||||
|
||||
typedef struct player_s
|
||||
{
|
||||
mobj_t* mo;
|
||||
/* [...snip...] */
|
||||
} player_t;
|
||||
|
||||
extern GameMode_t gamemode;
|
||||
extern int gameepisode;
|
||||
extern int gamemap;
|
||||
extern int consoleplayer;
|
||||
extern player_t players[4];
|
||||
|
||||
typedef struct sfxinfo_struct sfxinfo_t;
|
||||
|
||||
struct sfxinfo_struct
|
||||
{
|
||||
/* [...snip...] */
|
||||
int priority;
|
||||
sfxinfo_t* link;
|
||||
int pitch;
|
||||
int volume;
|
||||
void* data;
|
||||
int usefulness;
|
||||
int lumpnum;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
int lumpnum;
|
||||
void* data;
|
||||
int handle;
|
||||
} musicinfo_t;
|
||||
|
||||
extern sfxinfo_t S_sfx[];
|
||||
|
||||
extern musicinfo_t S_music[];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
mus_None,
|
||||
mus_e1m1,
|
||||
/* [...snip...] */
|
||||
mus_e1m5,
|
||||
/* [...snip...] */
|
||||
mus_e1m9,
|
||||
/* [...snip...] */
|
||||
mus_e2m4,
|
||||
mus_e2m5,
|
||||
mus_e2m6,
|
||||
mus_e2m7,
|
||||
/* [...snip...] */
|
||||
mus_e3m2,
|
||||
mus_e3m3,
|
||||
mus_e3m4,
|
||||
/* [...snip...] */
|
||||
mus_runnin,
|
||||
/* [...snip...] */
|
||||
NUMMUSIC
|
||||
} musicenum_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* [...snip...] */
|
||||
sfx_sawup,
|
||||
/* [...snip...] */
|
||||
sfx_sawhit,
|
||||
/* [...snip...] */
|
||||
sfx_itemup,
|
||||
/* [...snip...] */
|
||||
sfx_tink,
|
||||
/* [...snip...] */
|
||||
NUMSFX
|
||||
} sfxenum_t;
|
||||
|
||||
|
||||
void
|
||||
I_SetChannels();
|
||||
|
||||
int
|
||||
I_GetSfxLumpNum(sfxinfo_t* sfxinfo);
|
||||
|
||||
int
|
||||
I_StartSound(int id, int vol, int sep, int pitch, int priority);
|
||||
|
||||
void
|
||||
I_StopSound(int handle);
|
||||
int
|
||||
I_SoundIsPlaying(int handle);
|
||||
void
|
||||
I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
|
||||
|
||||
void
|
||||
I_SetMusicVolume(int volume);
|
||||
|
||||
void
|
||||
I_PauseSong(int handle);
|
||||
void
|
||||
I_ResumeSong(int handle);
|
||||
int
|
||||
I_RegisterSong(void* data);
|
||||
|
||||
void
|
||||
I_PlaySong(int handle, int looping);
|
||||
|
||||
void
|
||||
I_StopSong(int handle);
|
||||
|
||||
void
|
||||
I_UnRegisterSong(int handle);
|
||||
void
|
||||
S_StopSound(void* origin);
|
||||
void
|
||||
S_ChangeMusic(int music_id, int looping);
|
||||
void
|
||||
S_StopMusic(void);
|
||||
|
||||
void
|
||||
S_SetMusicVolume(int volume);
|
||||
void
|
||||
S_SetSfxVolume(int volume);
|
||||
|
||||
void*
|
||||
Z_Malloc(int size, int tag, void* ptr);
|
||||
void
|
||||
Z_ChangeTag2(void* ptr, int tag);
|
||||
|
||||
typedef struct memblock_s
|
||||
{
|
||||
/* [...snip...] */
|
||||
int id;
|
||||
/* [...snip...] */
|
||||
} memblock_t;
|
||||
int
|
||||
M_Random(void);
|
||||
int
|
||||
W_GetNumForName(char* name);
|
||||
void*
|
||||
W_CacheLumpNum(int lump, int tag);
|
||||
angle_t
|
||||
R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sfxinfo_t* sfxinfo;
|
||||
void* origin;
|
||||
int handle;
|
||||
} channel_t;
|
||||
static channel_t* channels;
|
||||
|
||||
int snd_SfxVolume = 15;
|
||||
int snd_MusicVolume = 15;
|
||||
static boolean mus_paused;
|
||||
static musicinfo_t* mus_playing = 0;
|
||||
int numChannels;
|
||||
static int nextcleanup;
|
||||
|
||||
int
|
||||
S_getChannel(void* origin, sfxinfo_t* sfxinfo);
|
||||
|
||||
int
|
||||
S_AdjustSoundParams(mobj_t* listener,
|
||||
mobj_t* source,
|
||||
int* vol,
|
||||
int* sep,
|
||||
int* pitch);
|
||||
void
|
||||
S_StopChannel(int cnum);
|
||||
|
||||
void
|
||||
S_Init(int sfxVolume, int musicVolume)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "S_Init: default sfx volume %d\n", sfxVolume);
|
||||
|
||||
I_SetChannels();
|
||||
|
||||
S_SetSfxVolume(sfxVolume);
|
||||
|
||||
S_SetMusicVolume(musicVolume);
|
||||
|
||||
channels = (channel_t*)Z_Malloc(numChannels * sizeof(channel_t), 1, 0);
|
||||
|
||||
for (i = 0; i < numChannels; i++)
|
||||
channels[i].sfxinfo = 0;
|
||||
|
||||
mus_paused = 0;
|
||||
|
||||
for (i = 1; i < NUMSFX; i++)
|
||||
S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
|
||||
}
|
||||
void
|
||||
S_Start(void)
|
||||
{
|
||||
int cnum;
|
||||
int mnum;
|
||||
|
||||
for (cnum = 0; cnum < numChannels; cnum++)
|
||||
if (channels[cnum].sfxinfo)
|
||||
S_StopChannel(cnum);
|
||||
|
||||
mus_paused = 0;
|
||||
|
||||
if (gamemode == commercial)
|
||||
mnum = mus_runnin + gamemap - 1;
|
||||
else {
|
||||
int spmus[] = {
|
||||
|
||||
mus_e3m4, mus_e3m2, mus_e3m3, mus_e1m5, mus_e2m7,
|
||||
mus_e2m4, mus_e2m6, mus_e2m5, mus_e1m9
|
||||
};
|
||||
|
||||
if (gameepisode < 4)
|
||||
mnum = mus_e1m1 + (gameepisode - 1) * 9 + gamemap - 1;
|
||||
else
|
||||
mnum = spmus[gamemap - 1];
|
||||
}
|
||||
|
||||
S_ChangeMusic(mnum, true);
|
||||
|
||||
nextcleanup = 15;
|
||||
}
|
||||
|
||||
void
|
||||
S_StartSoundAtVolume(void* origin_p, int sfx_id, int volume)
|
||||
{
|
||||
|
||||
int rc;
|
||||
int sep;
|
||||
int pitch;
|
||||
int priority;
|
||||
sfxinfo_t* sfx;
|
||||
int cnum;
|
||||
|
||||
mobj_t* origin = (mobj_t*)origin_p;
|
||||
if (sfx_id < 1 || sfx_id > NUMSFX)
|
||||
I_Error("Bad sfx #: %d", sfx_id);
|
||||
|
||||
sfx = &S_sfx[sfx_id];
|
||||
|
||||
if (sfx->link) {
|
||||
pitch = sfx->pitch;
|
||||
priority = sfx->priority;
|
||||
volume += sfx->volume;
|
||||
|
||||
if (volume < 1)
|
||||
return;
|
||||
|
||||
if (volume > snd_SfxVolume)
|
||||
volume = snd_SfxVolume;
|
||||
} else {
|
||||
pitch = 128;
|
||||
priority = 64;
|
||||
}
|
||||
|
||||
if (origin && origin != players[consoleplayer].mo) {
|
||||
rc = S_AdjustSoundParams(
|
||||
players[consoleplayer].mo, origin, &volume, &sep, &pitch);
|
||||
|
||||
if (origin->x == players[consoleplayer].mo->x &&
|
||||
origin->y == players[consoleplayer].mo->y) {
|
||||
sep = 128;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
return;
|
||||
} else {
|
||||
sep = 128;
|
||||
}
|
||||
|
||||
if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) {
|
||||
pitch += 8 - (M_Random() & 15);
|
||||
|
||||
if (pitch < 0)
|
||||
pitch = 0;
|
||||
else if (pitch > 255)
|
||||
pitch = 255;
|
||||
} else if (sfx_id != sfx_itemup && sfx_id != sfx_tink) {
|
||||
pitch += 16 - (M_Random() & 31);
|
||||
|
||||
if (pitch < 0)
|
||||
pitch = 0;
|
||||
else if (pitch > 255)
|
||||
pitch = 255;
|
||||
}
|
||||
|
||||
S_StopSound(origin);
|
||||
|
||||
cnum = S_getChannel(origin, sfx);
|
||||
|
||||
if (cnum < 0)
|
||||
return;
|
||||
if (sfx->lumpnum < 0)
|
||||
sfx->lumpnum = I_GetSfxLumpNum(sfx);
|
||||
|
||||
if (!sfx->data) {
|
||||
fprintf(stderr, "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n");
|
||||
}
|
||||
|
||||
if (sfx->usefulness++ < 0)
|
||||
sfx->usefulness = 1;
|
||||
|
||||
channels[cnum].handle = I_StartSound(sfx_id,
|
||||
|
||||
volume,
|
||||
sep,
|
||||
pitch,
|
||||
priority);
|
||||
}
|
||||
|
||||
void
|
||||
S_StartSound(void* origin, int sfx_id)
|
||||
{
|
||||
|
||||
S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
|
||||
}
|
||||
|
||||
void
|
||||
S_StopSound(void* origin)
|
||||
{
|
||||
|
||||
int cnum;
|
||||
|
||||
for (cnum = 0; cnum < numChannels; cnum++) {
|
||||
if (channels[cnum].sfxinfo && channels[cnum].origin == origin) {
|
||||
S_StopChannel(cnum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
S_PauseSound(void)
|
||||
{
|
||||
if (mus_playing && !mus_paused) {
|
||||
I_PauseSong(mus_playing->handle);
|
||||
mus_paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
S_ResumeSound(void)
|
||||
{
|
||||
if (mus_playing && mus_paused) {
|
||||
I_ResumeSong(mus_playing->handle);
|
||||
mus_paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
S_UpdateSounds(void* listener_p)
|
||||
{
|
||||
int audible;
|
||||
int cnum;
|
||||
int volume;
|
||||
int sep;
|
||||
int pitch;
|
||||
sfxinfo_t* sfx;
|
||||
channel_t* c;
|
||||
|
||||
mobj_t* listener = (mobj_t*)listener_p;
|
||||
for (cnum = 0; cnum < numChannels; cnum++) {
|
||||
c = &channels[cnum];
|
||||
sfx = c->sfxinfo;
|
||||
|
||||
if (c->sfxinfo) {
|
||||
if (I_SoundIsPlaying(c->handle)) {
|
||||
|
||||
volume = snd_SfxVolume;
|
||||
pitch = 128;
|
||||
sep = 128;
|
||||
|
||||
if (sfx->link) {
|
||||
pitch = sfx->pitch;
|
||||
volume += sfx->volume;
|
||||
if (volume < 1) {
|
||||
S_StopChannel(cnum);
|
||||
continue;
|
||||
} else if (volume > snd_SfxVolume) {
|
||||
volume = snd_SfxVolume;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->origin && listener_p != c->origin) {
|
||||
audible =
|
||||
S_AdjustSoundParams(listener, c->origin, &volume, &sep, &pitch);
|
||||
|
||||
if (!audible) {
|
||||
S_StopChannel(cnum);
|
||||
} else
|
||||
I_UpdateSoundParams(c->handle, volume, sep, pitch);
|
||||
}
|
||||
} else {
|
||||
|
||||
S_StopChannel(cnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
S_SetMusicVolume(int volume)
|
||||
{
|
||||
if (volume < 0 || volume > 127) {
|
||||
I_Error("Attempt to set music volume at %d", volume);
|
||||
}
|
||||
|
||||
I_SetMusicVolume(127);
|
||||
I_SetMusicVolume(volume);
|
||||
snd_MusicVolume = volume;
|
||||
}
|
||||
|
||||
void
|
||||
S_SetSfxVolume(int volume)
|
||||
{
|
||||
|
||||
if (volume < 0 || volume > 127)
|
||||
I_Error("Attempt to set sfx volume at %d", volume);
|
||||
|
||||
snd_SfxVolume = volume;
|
||||
}
|
||||
|
||||
void
|
||||
S_StartMusic(int m_id)
|
||||
{
|
||||
S_ChangeMusic(m_id, false);
|
||||
}
|
||||
|
||||
void
|
||||
S_ChangeMusic(int musicnum, int looping)
|
||||
{
|
||||
musicinfo_t* music;
|
||||
char namebuf[9];
|
||||
|
||||
if ((musicnum <= mus_None) || (musicnum >= NUMMUSIC)) {
|
||||
I_Error("Bad music number %d", musicnum);
|
||||
} else
|
||||
music = &S_music[musicnum];
|
||||
|
||||
/* We don't know that I_Error exits, so actually a false positive;
|
||||
see PR analyzer/108867. */
|
||||
|
||||
if (mus_playing == music) /* { dg-warning "use of uninitialized value 'music'" } */
|
||||
return;
|
||||
|
||||
S_StopMusic();
|
||||
|
||||
/* We shouldn't issue further warnings about 'music' being
|
||||
uninitialized. */
|
||||
|
||||
if (!music->lumpnum) { /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
sprintf(namebuf, "d_%s", music->name); /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
music->lumpnum = W_GetNumForName(namebuf); /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
}
|
||||
|
||||
music->data = (void*)W_CacheLumpNum(music->lumpnum, 3); /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
music->handle = I_RegisterSong(music->data); /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
|
||||
I_PlaySong(music->handle, looping); /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
|
||||
mus_playing = music; /* { dg-bogus "use of uninitialized value 'music'" } */
|
||||
}
|
||||
|
||||
void
|
||||
S_StopMusic(void)
|
||||
{
|
||||
if (mus_playing) {
|
||||
if (mus_paused)
|
||||
I_ResumeSong(mus_playing->handle);
|
||||
|
||||
I_StopSong(mus_playing->handle);
|
||||
I_UnRegisterSong(mus_playing->handle);
|
||||
{
|
||||
if (((memblock_t*)((byte*)(mus_playing->data) - sizeof(memblock_t)))
|
||||
->id != 0x1d4a11)
|
||||
I_Error("Z_CT at "
|
||||
"s_sound.c"
|
||||
":%i",
|
||||
699);
|
||||
Z_ChangeTag2(mus_playing->data, 101);
|
||||
};
|
||||
;
|
||||
|
||||
mus_playing->data = 0;
|
||||
mus_playing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
S_StopChannel(int cnum)
|
||||
{
|
||||
|
||||
int i;
|
||||
channel_t* c = &channels[cnum];
|
||||
|
||||
if (c->sfxinfo) {
|
||||
|
||||
if (I_SoundIsPlaying(c->handle)) {
|
||||
|
||||
I_StopSound(c->handle);
|
||||
}
|
||||
|
||||
for (i = 0; i < numChannels; i++) {
|
||||
if (cnum != i && c->sfxinfo == channels[i].sfxinfo) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->sfxinfo->usefulness--;
|
||||
|
||||
c->sfxinfo = 0;
|
||||
}
|
||||
}
|
||||
int
|
||||
S_AdjustSoundParams(mobj_t* listener,
|
||||
mobj_t* source,
|
||||
int* vol,
|
||||
int* sep,
|
||||
int* pitch)
|
||||
{
|
||||
fixed_t approx_dist;
|
||||
fixed_t adx;
|
||||
fixed_t ady;
|
||||
angle_t angle;
|
||||
|
||||
adx = abs(listener->x - source->x);
|
||||
ady = abs(listener->y - source->y);
|
||||
|
||||
approx_dist = adx + ady - ((adx < ady ? adx : ady) >> 1);
|
||||
|
||||
if (gamemap != 8 && approx_dist > (1200 * 0x10000)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y);
|
||||
|
||||
if (angle > listener->angle)
|
||||
angle = angle - listener->angle;
|
||||
else
|
||||
angle = angle + (0xffffffff - listener->angle);
|
||||
|
||||
angle >>= 19;
|
||||
|
||||
*sep = 128 - (FixedMul((96 * 0x10000), finesine[angle]) >> 16);
|
||||
|
||||
if (approx_dist < (160 * 0x10000)) {
|
||||
*vol = snd_SfxVolume;
|
||||
} else if (gamemap == 8) {
|
||||
if (approx_dist > (1200 * 0x10000))
|
||||
approx_dist = (1200 * 0x10000);
|
||||
|
||||
*vol =
|
||||
15 + ((snd_SfxVolume - 15) * (((1200 * 0x10000) - approx_dist) >> 16)) /
|
||||
(((1200 * 0x10000) - (160 * 0x10000)) >> 16);
|
||||
} else {
|
||||
|
||||
*vol = (snd_SfxVolume * (((1200 * 0x10000) - approx_dist) >> 16)) /
|
||||
(((1200 * 0x10000) - (160 * 0x10000)) >> 16);
|
||||
}
|
||||
|
||||
return (*vol > 0);
|
||||
}
|
||||
int
|
||||
S_getChannel(void* origin, sfxinfo_t* sfxinfo)
|
||||
{
|
||||
|
||||
int cnum;
|
||||
|
||||
channel_t* c;
|
||||
|
||||
for (cnum = 0; cnum < numChannels; cnum++) {
|
||||
if (!channels[cnum].sfxinfo)
|
||||
break;
|
||||
else if (origin && channels[cnum].origin == origin) {
|
||||
S_StopChannel(cnum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnum == numChannels) {
|
||||
|
||||
for (cnum = 0; cnum < numChannels; cnum++)
|
||||
if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) /* { dg-warning "dereference of NULL" } */
|
||||
break;
|
||||
|
||||
if (cnum == numChannels) {
|
||||
|
||||
return -1;
|
||||
} else {
|
||||
|
||||
S_StopChannel(cnum);
|
||||
}
|
||||
}
|
||||
|
||||
c = &channels[cnum];
|
||||
|
||||
c->sfxinfo = sfxinfo;
|
||||
c->origin = origin;
|
||||
|
||||
return cnum;
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
It was fixed by e.g. 342ffc26693b528648bdc9377e51e4f2450b4860 on linux-4.13.y
|
||||
in linux-stable. */
|
||||
|
||||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
#include <string.h>
|
||||
|
||||
|
|
94
gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c
Normal file
94
gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* Reduced from apr-1.7.0/tables/apr_hash.c: 'apr_hash_merge' */
|
||||
|
||||
/* { dg-additional-options "-Wno-analyzer-too-complex" } */
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
extern void*
|
||||
memset(void* __s, int __c, size_t __n)
|
||||
__attribute__((__nothrow__, __leaf__, __nonnull__(1)));
|
||||
|
||||
typedef struct apr_pool_t apr_pool_t;
|
||||
|
||||
void*
|
||||
apr_palloc(apr_pool_t* p, size_t size)
|
||||
__attribute__((alloc_size(2), nonnull(1)));
|
||||
|
||||
typedef struct apr_hash_t apr_hash_t;
|
||||
typedef struct apr_hash_index_t apr_hash_index_t;
|
||||
typedef unsigned int (*apr_hashfunc_t)(const char* key, size_t* klen);
|
||||
typedef struct apr_hash_entry_t apr_hash_entry_t;
|
||||
|
||||
struct apr_hash_entry_t
|
||||
{
|
||||
apr_hash_entry_t* next;
|
||||
unsigned int hash;
|
||||
const void* key;
|
||||
size_t klen;
|
||||
const void* val;
|
||||
};
|
||||
|
||||
struct apr_hash_t
|
||||
{
|
||||
apr_pool_t* pool;
|
||||
apr_hash_entry_t** array;
|
||||
/* [...snip.../ */
|
||||
unsigned int count, max, seed;
|
||||
apr_hashfunc_t hash_func;
|
||||
apr_hash_entry_t* free;
|
||||
};
|
||||
|
||||
static apr_hash_entry_t**
|
||||
alloc_array(apr_hash_t* ht, unsigned int max)
|
||||
{
|
||||
return memset(apr_palloc(ht->pool, sizeof(*ht->array) * (max + 1)),
|
||||
0,
|
||||
sizeof(*ht->array) * (max + 1));
|
||||
}
|
||||
|
||||
apr_hash_t*
|
||||
apr_hash_merge(apr_pool_t* p,
|
||||
const apr_hash_t* overlay,
|
||||
const apr_hash_t* base)
|
||||
{
|
||||
apr_hash_t* res;
|
||||
apr_hash_entry_t* new_vals = NULL;
|
||||
apr_hash_entry_t* iter;
|
||||
unsigned int i, j, k;
|
||||
res = apr_palloc(p, sizeof(apr_hash_t));
|
||||
res->pool = p;
|
||||
res->free = NULL;
|
||||
res->hash_func = base->hash_func;
|
||||
res->count = base->count;
|
||||
res->max = (overlay->max > base->max) ? overlay->max : base->max;
|
||||
if (base->count + overlay->count > res->max) {
|
||||
res->max = res->max * 2 + 1;
|
||||
}
|
||||
res->seed = base->seed;
|
||||
res->array = alloc_array(res, res->max);
|
||||
if (base->count + overlay->count) {
|
||||
new_vals =
|
||||
apr_palloc(p, sizeof(apr_hash_entry_t) * (base->count + overlay->count));
|
||||
}
|
||||
j = 0;
|
||||
for (k = 0; k <= base->max; k++) {
|
||||
for (iter = base->array[k]; iter; iter = iter->next) {
|
||||
i = iter->hash & res->max;
|
||||
/* We should only warn for the first of these
|
||||
(it's actually a false positive, but we don't have the
|
||||
invariante to know that). */
|
||||
new_vals[j].klen = iter->klen; /* { dg-warning "dereference of NULL 'new_vals'" } */
|
||||
/* ...but not for subsequent ones: */
|
||||
new_vals[j].key = iter->key; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
|
||||
new_vals[j].val = iter->val; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
|
||||
new_vals[j].hash = iter->hash; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
|
||||
new_vals[j].next = res->array[i]; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
|
||||
res->array[i] = &new_vals[j]; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
|
||||
j++;
|
||||
}
|
||||
}
|
||||
/* [...snip...] */
|
||||
return res;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
extern int pipe(int pipefd[2]);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
extern void pipe(int pipefd[2]);
|
||||
extern int close(int fd);
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
extern int pipe2(int pipefd[2], int flags);
|
||||
|
|
|
@ -2,10 +2,18 @@ char *
|
|||
fopen (const char *restrict, const char *restrict);
|
||||
|
||||
void
|
||||
k2 (void)
|
||||
k2_uninit (void)
|
||||
{
|
||||
char *setfiles[1];
|
||||
int i; /* { dg-message "region created on stack here" } */
|
||||
|
||||
setfiles[i] = fopen ("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
|
||||
}
|
||||
|
||||
void
|
||||
k2_leak (int i)
|
||||
{
|
||||
char *setfiles[1];
|
||||
|
||||
setfiles[i] = fopen ("", "");
|
||||
} /* { dg-warning "leak of FILE" } */
|
||||
|
|
|
@ -5,12 +5,22 @@ void
|
|||
err (void);
|
||||
|
||||
void
|
||||
k2 (void)
|
||||
k2_uninit (void)
|
||||
{
|
||||
char *setfiles[1];
|
||||
int i; /* { dg-message "region created on stack here" } */
|
||||
|
||||
setfiles[i] = fopen("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
|
||||
if (!setfiles[i]) /* { dg-warning "use of uninitialized value 'i'" } */
|
||||
if (!setfiles[i])
|
||||
err ();
|
||||
}
|
||||
|
||||
void
|
||||
k2_leak (int i)
|
||||
{
|
||||
char *setfiles[1];
|
||||
|
||||
setfiles[i] = fopen("", "");
|
||||
if (!setfiles[i])
|
||||
err ();
|
||||
} /* { dg-warning "leak of FILE" } */
|
||||
|
|
136
gcc/testsuite/gcc.dg/analyzer/pr104224-split.c
Normal file
136
gcc/testsuite/gcc.dg/analyzer/pr104224-split.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
#include <stdio.h>
|
||||
|
||||
struct test {
|
||||
int one;
|
||||
int two;
|
||||
};
|
||||
|
||||
void func2(const struct test *t)
|
||||
{
|
||||
if (t->one == 0)
|
||||
printf("init func2\n");
|
||||
|
||||
if (t->two == 0) /* { dg-warning "uninitialized" } */
|
||||
printf("uninit func2\n");
|
||||
}
|
||||
|
||||
void func1(struct test *t)
|
||||
{
|
||||
t->one = 1;
|
||||
func2(t);
|
||||
}
|
||||
|
||||
int func3(int num)
|
||||
{
|
||||
if (num)
|
||||
return num;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void func4(int *a, int max)
|
||||
{
|
||||
int i;
|
||||
// skip the first
|
||||
for (i=1; i<max; i++)
|
||||
a[i] = 0;
|
||||
}
|
||||
|
||||
void func5(const int *a, int max)
|
||||
{
|
||||
/* a[0] is uninitialized, but the rest of the array is initialized. */
|
||||
int i;
|
||||
for (i=0; i<max; i++) {
|
||||
if (a[i]) /* { dg-warning "uninitialized" "" { xfail *-*-* } } */
|
||||
printf("func5: %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
int func6(const int *num)
|
||||
{
|
||||
if (*num) /* { dg-warning "uninitialized" } */
|
||||
return *num;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int j;
|
||||
int func7(void)
|
||||
{
|
||||
return j; /* { dg-bogus "uninitialized" } */
|
||||
}
|
||||
|
||||
void func8(const int *a, int max)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<max; i++) {
|
||||
if (a[i]) /* { dg-warning "uninitialized" } */
|
||||
printf("func8: %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
enum {RED, AMBER, GREEN, BLACK};
|
||||
|
||||
int test_1 (void)
|
||||
{
|
||||
struct test t; /* { dg-message "region created on stack here" } */
|
||||
|
||||
func1(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_2 (void)
|
||||
{
|
||||
int num; /* { dg-message "region created on stack here" } */
|
||||
|
||||
func3(num); /* { dg-warning "use of uninitialized value 'num'" } */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_3 (void)
|
||||
{
|
||||
int arry[10];
|
||||
|
||||
func4(arry, 10);
|
||||
func5(arry, 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_4 (void)
|
||||
{
|
||||
int num; /* { dg-message "region created on stack here" } */
|
||||
|
||||
func6(&num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_5 (void)
|
||||
{
|
||||
int arry_2[10]; /* { dg-message "region created on stack here" } */
|
||||
|
||||
printf("func7: %d\n", func7());
|
||||
func8(arry_2, 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_6 (void)
|
||||
{
|
||||
int go; /* { dg-message "region created on stack here" } */
|
||||
int color = BLACK;
|
||||
|
||||
switch (color) {
|
||||
case RED:
|
||||
case AMBER:
|
||||
go = 0;
|
||||
break;
|
||||
case GREEN:
|
||||
go = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
printf("go :%d\n", go); /* { dg-warning "use of uninitialized value 'go'" } */
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct test {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* As per stdarg-1.c, but using the ms_abi versions of the builtins. */
|
||||
|
||||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
/* { dg-do compile { target { x86_64-*-* && lp64 } } } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* As per stdarg-1.c, but using the sysv_abi versions of the builtins. */
|
||||
|
||||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
/* { dg-do compile { target { x86_64-*-* && lp64 } } } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
/* Unpacking a va_list. */
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
/* The example from store.h */
|
||||
|
|
|
@ -31,16 +31,20 @@ void test_2 (int i)
|
|||
__analyzer_eval (arr[i] == 42); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
void test_3 (int i)
|
||||
void test_3_concrete_read (int i)
|
||||
{
|
||||
/* An array that can't have been touched. */
|
||||
int arr[2];
|
||||
|
||||
/* Concrete reads. */
|
||||
__analyzer_eval (arr[0] == 42); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" "uninit" { target *-*-* } .-1 } */
|
||||
|
||||
/* Symbolic read. */
|
||||
__analyzer_eval (arr[i] == 42); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" "uninit" { target *-*-* } .-1 } */
|
||||
__analyzer_eval (arr[0] == 42); /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" } */
|
||||
}
|
||||
|
||||
void test_3_symbolic_read (int i)
|
||||
{
|
||||
/* An array that can't have been touched. */
|
||||
int arr[2];
|
||||
|
||||
/* Symbolic read. */
|
||||
__analyzer_eval (arr[i] == 42); /* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" } */
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ alloc_foo (int a, int b)
|
|||
return p;
|
||||
}
|
||||
|
||||
void test (int x, int y, int z)
|
||||
void test_access_inited_fields (int x, int y, int z)
|
||||
{
|
||||
struct foo *p = alloc_foo (x, z);
|
||||
if (!p)
|
||||
|
@ -30,10 +30,20 @@ void test (int x, int y, int z)
|
|||
|
||||
__analyzer_eval (p->i == x); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p->j == y); /* { dg-warning "UNKNOWN" "unknown" } */
|
||||
/* { dg-warning "use of uninitialized value '\\*p\\.j'" "uninit" { target *-*-* } .-1 } */
|
||||
|
||||
__analyzer_eval (p->k == z); /* { dg-warning "TRUE" } */
|
||||
|
||||
free (p);
|
||||
}
|
||||
|
||||
void test_stop_after_accessing_uninit (int x, int y, int z)
|
||||
{
|
||||
struct foo *p = alloc_foo (x, z);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
__analyzer_eval (p->i == x); /* { dg-warning "TRUE" } */
|
||||
|
||||
__analyzer_eval (p->j == y); /* { dg-warning "use of uninitialized value '\\*p\\.j'" } */
|
||||
|
||||
__analyzer_dump_path (); /* { dg-bogus "path" } */
|
||||
}
|
||||
|
|
73
gcc/testsuite/gcc.dg/analyzer/uninit-8.c
Normal file
73
gcc/testsuite/gcc.dg/analyzer/uninit-8.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
struct st
|
||||
{
|
||||
int a, b, c, d, e;
|
||||
};
|
||||
|
||||
int
|
||||
test_1 (int flag, struct st *p)
|
||||
{
|
||||
struct st *q;
|
||||
int result = 0;
|
||||
if (flag)
|
||||
q = p;
|
||||
/* We should only warn about the first use of uninit for 'q': */
|
||||
result += q->a; /* { dg-warning "use of uninitialized value 'q'" } */
|
||||
/* ...and not for these: */
|
||||
result += q->b; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->c; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->d; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->e; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
test_2 (int flag, struct st *p, struct st *r)
|
||||
{
|
||||
struct st *q;
|
||||
int result = 0;
|
||||
if (flag)
|
||||
q = p;
|
||||
/* We should only warn about the first use of uninit for 'q': */
|
||||
if (q == r) /* { dg-warning "use of uninitialized value 'q'" } */
|
||||
result += 1;
|
||||
/* ...and not for these, after a conditional: */
|
||||
result += q->b; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->c; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->d; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
result += q->e; /* { dg-bogus "use of uninitialized value 'q'" } */
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
test_3 (int flag, int val)
|
||||
{
|
||||
int result = 0;
|
||||
int idx;
|
||||
if (flag)
|
||||
idx = val;
|
||||
switch (idx) /* { dg-warning "use of uninitialized value 'idx'" } */
|
||||
{
|
||||
case 0:
|
||||
result = 3;
|
||||
break;
|
||||
case 1:
|
||||
result = 4;
|
||||
break;
|
||||
default:
|
||||
result = 5;
|
||||
break;
|
||||
}
|
||||
switch (idx) /* { dg-bogus "use of uninitialized value 'idx'" } */
|
||||
{
|
||||
case 0:
|
||||
result += 3;
|
||||
break;
|
||||
case 1:
|
||||
result += 4;
|
||||
break;
|
||||
default:
|
||||
result += 5;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,11 +1,19 @@
|
|||
void f1 (int *);
|
||||
void f2 (int);
|
||||
|
||||
int foo (void)
|
||||
int test_1 (void)
|
||||
{
|
||||
int *p; /* { dg-message "region created on stack here" } */
|
||||
|
||||
f1 (p); /* { dg-warning "use of uninitialized value 'p'" } */
|
||||
f1 (p); /* { dg-bogus "use of uninitialized value 'p'" "no followup warnings" } */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_2 (void)
|
||||
{
|
||||
int *p; /* { dg-message "region created on stack here" } */
|
||||
|
||||
f2 (p[0]); /* { dg-warning "use of uninitialized value 'p'" } */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef unsigned int uInt;
|
||||
typedef unsigned long uLong;
|
||||
|
|
Loading…
Add table
Reference in a new issue