[pushed] analyzer: fix ICE on certain longjmp calls [PR109094]
Checks
Commit Message
PR analyzer/109094 reports an ICE in the analyzer seen on qemu's
target/i386/tcg/translate.c
The issue turned out to be that when handling a longjmp, the code
to pop the frames was generating an svalue for the result_decl of any
popped frame that had a non-void return type (and discarding it) leading
to "uninit" poisoned_svalue_diagnostic instances being saved since the
result_decl is only set by the greturn stmt. Later, when checking the
feasibility of the path to these diagnostics, m_check_expr was evaluated
in the context of the frame of the longjmp, leading to an attempt to
evaluate the result_decl of each intervening frames whilst in the
context of the topmost frame, leading to an assertion failure in
frame_region::get_region_for_local here:
919 case RESULT_DECL:
920 gcc_assert (DECL_CONTEXT (expr) == m_fun->decl);
921 break;
This patch updates the analyzer's longjmp implementation so that it
doesn't attempt to generate svalues for the result_decls when popping
frames, fixing the assertion failure (and presumably fixing "uninit"
false positives in a release build).
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Analyzer integration tests shows no regressions.
Pushed to trunk as r13-6749-g430d7d88c1a123.
gcc/analyzer/ChangeLog:
PR analyzer/109094
* region-model.cc (region_model::on_longjmp): Pass false for
new "eval_return_svalue" param of pop_frame.
(region_model::pop_frame): Add new "eval_return_svalue" param and
use it to suppress the call to get_rvalue on the result when
needed by on_longjmp.
* region-model.h (region_model::pop_frame): Add new
"eval_return_svalue" param.
gcc/testsuite/ChangeLog:
PR analyzer/109094
* gcc.dg/analyzer/setjmp-pr109094.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
gcc/analyzer/region-model.cc | 15 ++++++--
gcc/analyzer/region-model.h | 3 +-
.../gcc.dg/analyzer/setjmp-pr109094.c | 38 +++++++++++++++++++
3 files changed, 52 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/analyzer/setjmp-pr109094.c
@@ -1952,7 +1952,7 @@ region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
setjmp was called. */
gcc_assert (get_stack_depth () >= setjmp_stack_depth);
while (get_stack_depth () > setjmp_stack_depth)
- pop_frame (NULL, NULL, ctxt);
+ pop_frame (NULL, NULL, ctxt, false);
gcc_assert (get_stack_depth () == setjmp_stack_depth);
@@ -4679,6 +4679,10 @@ region_model::get_current_function () const
If OUT_RESULT is non-null, copy any return value from the frame
into *OUT_RESULT.
+ If EVAL_RETURN_SVALUE is false, then don't evaluate the return value.
+ This is for use when unwinding frames e.g. due to longjmp, to suppress
+ erroneously reporting uninitialized return values.
+
Purge the frame region and all its descendent regions.
Convert any pointers that point into such regions into
POISON_KIND_POPPED_STACK svalues. */
@@ -4686,7 +4690,8 @@ region_model::get_current_function () const
void
region_model::pop_frame (tree result_lvalue,
const svalue **out_result,
- region_model_context *ctxt)
+ region_model_context *ctxt,
+ bool eval_return_svalue)
{
gcc_assert (m_current_frame);
@@ -4700,7 +4705,9 @@ region_model::pop_frame (tree result_lvalue,
tree fndecl = m_current_frame->get_function ()->decl;
tree result = DECL_RESULT (fndecl);
const svalue *retval = NULL;
- if (result && TREE_TYPE (result) != void_type_node)
+ if (result
+ && TREE_TYPE (result) != void_type_node
+ && eval_return_svalue)
{
retval = get_rvalue (result, ctxt);
if (out_result)
@@ -4712,6 +4719,8 @@ region_model::pop_frame (tree result_lvalue,
if (result_lvalue && retval)
{
+ gcc_assert (eval_return_svalue);
+
/* Compute result_dst_reg using RESULT_LVALUE *after* popping
the frame, but before poisoning pointers into the old frame. */
const region *result_dst_reg = get_lvalue (result_lvalue, ctxt);
@@ -341,7 +341,8 @@ class region_model
function * get_current_function () const;
void pop_frame (tree result_lvalue,
const svalue **out_result,
- region_model_context *ctxt);
+ region_model_context *ctxt,
+ bool eval_return_svalue = true);
int get_stack_depth () const;
const frame_region *get_frame_at_index (int index) const;
new file mode 100644
@@ -0,0 +1,38 @@
+/* Reduced from an ICE seen in qemu's target/i386/tcg/translate.c */
+
+typedef long int __jmp_buf[8];
+struct __jmp_buf_tag {
+ __jmp_buf __jmpbuf;
+};
+typedef struct __jmp_buf_tag sigjmp_buf[1];
+
+extern int __sigsetjmp(sigjmp_buf env, int savesigs);
+extern void siglongjmp(sigjmp_buf env, int val);
+
+typedef struct DisasContextBase {
+ int num_insns;
+} DisasContextBase;
+
+typedef struct DisasContext {
+ DisasContextBase base;
+ sigjmp_buf jmpbuf;
+} DisasContext;
+
+extern int translator_ldub(DisasContextBase *base, int);
+
+int advance_pc(DisasContext *s, int num_bytes) {
+ if (s->base.num_insns > 1) {
+ siglongjmp(s->jmpbuf, 2);
+ }
+ return 0;
+}
+
+static inline int x86_ldub_code(DisasContext *s) {
+ return translator_ldub(&s->base, advance_pc(s, 1));
+}
+
+static void disas_insn(DisasContext *s) {
+ int b;
+ __sigsetjmp(s->jmpbuf, 0);
+ b = x86_ldub_code(s);
+}