Skip to content

Commit 3e21de2

Browse files
author
Erlang/OTP
committed
Merge branch 'sverker/erts/trace-call-mem-validate-stack/OTP-19761' into maint-28
* sverker/erts/trace-call-mem-validate-stack/OTP-19761: erts: Add asserts to verify trace stack frames erts: Fix crash in erts_validate_stack()
2 parents bacf779 + d0678bf commit 3e21de2

File tree

12 files changed

+97
-27
lines changed

12 files changed

+97
-27
lines changed

erts/emulator/beam/beam_bp.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,27 @@ do_session_breakpoint(Process *c_p, ErtsCodeInfo *info, Eterm *reg,
11011101
return bp_flags;
11021102
}
11031103

1104+
#ifdef DEBUG
1105+
void assert_return_trace_frame(const Eterm *frame)
1106+
{
1107+
ASSERT_MFA((ErtsCodeMFA*)cp_val(frame[0]));
1108+
ASSERT(IS_TRACER_VALID(frame[1]));
1109+
ASSERT(erts_is_trace_session_weak_id(frame[2]));
1110+
}
1111+
1112+
void assert_return_to_trace_frame(const Eterm *frame)
1113+
{
1114+
ASSERT(erts_is_trace_session_weak_id(frame[0]));
1115+
}
1116+
1117+
void assert_return_call_acc_trace_frame(const Eterm *frame)
1118+
{
1119+
ASSERT(is_CP(frame[0]) || is_nil(frame[0])); // prev_info
1120+
ASSERT((unsigned_val(frame[1]) & ~ERTS_BPF_ALL) == 0); // bp_flags
1121+
ASSERT(erts_is_trace_session_weak_id(frame[2]));
1122+
}
1123+
#endif
1124+
11041125
static ErtsTracer
11051126
do_call_trace(Process* c_p, ErtsCodeInfo* info, Eterm* reg,
11061127
int local, Binary* ms,

erts/emulator/beam/beam_bp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ Uint erts_line_breakpoint_hit__cleanup(Eterm *regs, UWord *stk);
208208

209209
const ErtsCodeInfo *erts_find_local_func(const ErtsCodeMFA *mfa);
210210

211+
#ifdef DEBUG
212+
void assert_return_trace_frame(const Eterm *frame);
213+
void assert_return_to_trace_frame(const Eterm *frame);
214+
void assert_return_call_acc_trace_frame(const Eterm *frame);
215+
#endif
216+
211217
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
212218

213219
ERTS_GLB_INLINE ErtsBpIndex erts_active_bp_ix(void)

erts/emulator/beam/erl_gc.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,7 +3839,7 @@ erts_max_heap_size(Eterm arg, Uint *max_heap_size, Uint *max_heap_flags)
38393839
return 1;
38403840
}
38413841

3842-
#ifdef DEBUG
3842+
#if defined(DEBUG) && defined(ERLANG_FRAME_POINTERS)
38433843
void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top) {
38443844
Eterm *stack_bottom = HEAP_END(p);
38453845
Eterm *next_fp = frame_ptr;
@@ -3853,20 +3853,24 @@ void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top) {
38533853
ASSERT((next_fp != NULL) ^ (stack_top == stack_bottom));
38543854

38553855
/* If the GC happens when we are about to execute a trace we
3856-
need to skip the trace instructions */
3856+
need to skip the trace instructions.
3857+
Note: It's not safe in general to assume p->i is up-to-date in GC.
3858+
However the return trace intructions do update p->i after returning.
3859+
*/
38573860
if (BeamIsReturnTrace(p->i)) {
3858-
/* Skip MFA and tracer. */
3859-
ASSERT_MFA((ErtsCodeMFA*)cp_val(scanner[0]));
3860-
ASSERT(IS_TRACER_VALID(scanner[1]));
3861+
assert_return_trace_frame(scanner);
38613862
scanner += BEAM_RETURN_TRACE_FRAME_SZ;
38623863
} else if (BeamIsReturnCallAccTrace(p->i)) {
3863-
/* Skip prev_info. */
3864+
assert_return_call_acc_trace_frame(scanner);
38643865
scanner += BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ;
38653866
} else if (BeamIsReturnToTrace(p->i)) {
3867+
assert_return_to_trace_frame(scanner);
38663868
scanner += BEAM_RETURN_TO_TRACE_FRAME_SZ;
38673869
}
38683870

38693871
while (next_fp) {
3872+
ErtsCodePtr cp;
3873+
38703874
ASSERT(next_fp >= stack_top && next_fp <= stack_bottom);
38713875

38723876
/* We may not skip any frames. */
@@ -3876,24 +3880,24 @@ void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top) {
38763880
}
38773881

38783882
/* {Next frame, Return address} or vice versa */
3879-
ASSERT(is_CP(scanner[0]) && is_CP(scanner[1]));
38803883
next_fp = (Eterm*)cp_val(scanner[0]);
3884+
cp = cp_val(scanner[1]);
3885+
3886+
scanner += CP_SIZE;
38813887

38823888
/* Call tracing may store raw pointers on the stack. This is explicitly
38833889
* handled in all routines that deal with the stack. */
3884-
if (BeamIsReturnTrace((ErtsCodePtr)scanner[1])) {
3885-
/* Skip MFA and tracer. */
3886-
ASSERT_MFA((ErtsCodeMFA*)cp_val(scanner[2]));
3887-
ASSERT(IS_TRACER_VALID(scanner[3]));
3890+
if (BeamIsReturnTrace(cp)) {
3891+
assert_return_trace_frame(scanner);
38883892
scanner += BEAM_RETURN_TRACE_FRAME_SZ;
3889-
} else if (BeamIsReturnCallAccTrace((ErtsCodePtr)scanner[1])) {
3890-
/* Skip prev_info. */
3893+
} else if (BeamIsReturnCallAccTrace(cp)) {
3894+
assert_return_call_acc_trace_frame(scanner);
38913895
scanner += BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ;
3892-
} else if (BeamIsReturnToTrace((ErtsCodePtr)scanner[1])) {
3896+
} else if (BeamIsReturnToTrace(cp)) {
3897+
assert_return_to_trace_frame(scanner);
38933898
scanner += BEAM_RETURN_TO_TRACE_FRAME_SZ;
38943899
}
38953900

3896-
scanner += CP_SIZE;
38973901
}
38983902
}
38993903
#endif

erts/emulator/beam/erl_gc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,13 @@ int erts_dbg_within_proc(Eterm *ptr, Process *p, Eterm* real_htop);
195195
#endif
196196

197197
#ifdef DEBUG
198+
199+
# ifdef ERLANG_FRAME_POINTERS
198200
/* Validates the frame chain, ensuring that it always points within the stack
199201
* and that no frames are skipped. */
200202
void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top);
203+
# endif
204+
201205
int
202206
erts_dbg_check_heap_terms(int (*check_eterm)(Eterm),
203207
Process *p,

erts/emulator/beam/erl_trace.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3822,6 +3822,11 @@ void erts_change_proc_trace_session_flags(Process* p, ErtsTraceSession* session,
38223822
}
38233823

38243824
#ifdef DEBUG
3825+
bool erts_is_trace_session_weak_id(Eterm term)
3826+
{
3827+
return is_small(term) || term == am_default;
3828+
}
3829+
38253830
void erts_assert_tracer_refs(ErtsPTabElementCommon* t_p)
38263831
{
38273832
ErtsTracerRef *ref, *other;

erts/emulator/beam/erl_trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Uint32 erts_sum_all_trace_flags(ErtsPTabElementCommon* t_p);
152152
void erts_change_proc_trace_session_flags(Process*, ErtsTraceSession*,
153153
Uint32 clear_flags, Uint32 set_flags);
154154
#ifdef DEBUG
155+
bool erts_is_trace_session_weak_id(Eterm);
155156
void erts_assert_tracer_refs(ErtsPTabElementCommon* t_p);
156157
# define ERTS_ASSERT_TRACER_REFS(TP) erts_assert_tracer_refs(TP)
157158
#else

erts/emulator/beam/jit/arm/beam_asm.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,8 @@ class BeamModuleAssembler : public BeamAssembler,
13741374
void emit_tuple_assertion(const ArgSource &Src, a64::Gp tuple_reg);
13751375
#endif
13761376

1377-
void emit_dispatch_return();
1377+
void emit_return_do(bool set_I);
1378+
void emit_dispatch_return(bool set_I);
13781379

13791380
#include "beamasm_protos.h"
13801381

erts/emulator/beam/jit/arm/instr_call.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ void BeamGlobalAssembler::emit_dispatch_return() {
3535
a.b(labels[context_switch_simplified]);
3636
}
3737

38-
void BeamModuleAssembler::emit_dispatch_return() {
38+
void BeamModuleAssembler::emit_dispatch_return(bool set_I) {
3939
#ifdef JIT_HARD_DEBUG
4040
/* Validate return address and {x,0} */
4141
emit_validate(ArgVal(ArgVal::Type::Word, 1));
4242
#endif
4343

44-
if (erts_alcu_enable_code_atags) {
44+
if (erts_alcu_enable_code_atags || set_I) {
4545
/* See emit_i_test_yield. */
4646
a.str(a64::x30, arm::Mem(c_p, offsetof(Process, i)));
4747
}
@@ -57,13 +57,17 @@ void BeamModuleAssembler::emit_dispatch_return() {
5757
}
5858

5959
void BeamModuleAssembler::emit_return() {
60+
emit_return_do(false);
61+
}
62+
63+
void BeamModuleAssembler::emit_return_do(bool set_I) {
6064
emit_leave_erlang_frame();
61-
emit_dispatch_return();
65+
emit_dispatch_return(set_I);
6266
}
6367

6468
void BeamModuleAssembler::emit_move_deallocate_return() {
6569
a.ldp(XREG0, a64::x30, arm::Mem(E).post(16));
66-
emit_dispatch_return();
70+
emit_dispatch_return(false);
6771
}
6872

6973
void BeamModuleAssembler::emit_i_call(const ArgLabel &CallTarget) {

erts/emulator/beam/jit/arm/instr_trace.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,10 @@ void BeamModuleAssembler::emit_return_trace() {
164164
emit_leave_runtime<Update::eHeapAlloc>(1);
165165

166166
emit_deallocate(ArgVal(ArgVal::Type::Word, BEAM_RETURN_TRACE_FRAME_SZ));
167-
emit_return();
167+
168+
/* Return and set c_p->i to avoid calls to BeamIsReturnTrace(c_p->i)
169+
to assume there is still a trace frame on the stack. */
170+
emit_return_do(true);
168171
}
169172

170173
void BeamModuleAssembler::emit_i_call_trace_return() {
@@ -189,7 +192,10 @@ void BeamModuleAssembler::emit_i_call_trace_return() {
189192

190193
emit_deallocate(
191194
ArgVal(ArgVal::Type::Word, BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ));
192-
emit_return();
195+
196+
/* Return and set c_p->i to avoid calls to BeamIsReturnCallAccTrace(c_p->i)
197+
to assume there is still a trace frame on the stack. */
198+
emit_return_do(true);
193199
}
194200

195201
void BeamModuleAssembler::emit_i_return_to_trace() {
@@ -207,7 +213,10 @@ void BeamModuleAssembler::emit_i_return_to_trace() {
207213
emit_leave_runtime<Update::eHeapAlloc>(1);
208214

209215
emit_deallocate(ArgVal(ArgVal::Type::Word, BEAM_RETURN_TO_TRACE_FRAME_SZ));
210-
emit_return();
216+
217+
/* Return and set c_p->i to avoid calls to BeamIsReturnToTrace(c_p->i)
218+
to assume there is still a trace frame on the stack. */
219+
emit_return_do(true);
211220
}
212221

213222
void BeamModuleAssembler::emit_i_hibernate() {

erts/emulator/beam/jit/x86/beam_asm.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,8 @@ class BeamModuleAssembler : public BeamAssembler,
15201520
void emit_tuple_assertion(const ArgSource &Src, x86::Gp tuple_reg);
15211521
#endif
15221522

1523+
void emit_return_do(bool set_I);
1524+
15231525
#include "beamasm_protos.h"
15241526

15251527
const Label &resolve_beam_label(const ArgLabel &Lbl) const {

0 commit comments

Comments
 (0)