diff options
-rw-r--r-- | gcc/analyzer/region-model.cc | 15 | ||||
-rw-r--r-- | gcc/analyzer/region-model.h | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/setjmp-pr109094.c | 38 |
3 files changed, 52 insertions, 4 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 56beaa8..fb81d43 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -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); diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 197b535..fe3db0b 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -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; diff --git a/gcc/testsuite/gcc.dg/analyzer/setjmp-pr109094.c b/gcc/testsuite/gcc.dg/analyzer/setjmp-pr109094.c new file mode 100644 index 0000000..10591ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/setjmp-pr109094.c @@ -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); +} |