@@ -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\\\]'" } */
+}
+
+void test_partially_inits_1 (int x)
+{
+ int arr[2];
+ partially_inits (arr, x);
+ partially_inits (arr, x);
- __analyzer_eval (arr[1] == x); /* { dg-warning "UNKNOWN" "eval" } */
- /* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } .-1 } */
+ __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)
new file mode 100644
@@ -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>
new file mode 100644
@@ -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" } */
new file mode 100644
@@ -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 } */
+ __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 "UNKNOWN" "unknown" } */
- /* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" "uninit" { target *-*-* } .-1 } */
+ __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" } */
+}
new file mode 100644
@@ -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;