Skip to content

Commit

Permalink
Make sure we don't leak when an opcode is followed by itself
Browse files Browse the repository at this point in the history
When compiling with GCC it is now possible for an opcode followed by
itself to never leave the scope it is currently in. This leads to a
situation where the dtor of a scope local variable isn't called which in
turn can lead to a memory leak.

By moving the goto outside of the scope of each opcode we guarantee that
all dtors have been called before the next opcode gets dispatched.

this fixes #12401
  • Loading branch information
hpvb committed Nov 9, 2017
1 parent 05fc741 commit 38ae49e
Showing 1 changed file with 80 additions and 50 deletions.
130 changes: 80 additions & 50 deletions modules/gdscript/gd_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ static String _get_var_type(const Variant *p_type) {
return basestr;
}

#if defined(__GNUC__) && !defined(__clang__)
#if defined(__GNUC__)
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
Expand Down Expand Up @@ -427,8 +427,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 5;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_EXTENDS_TEST) {

CHECK_SPACE(4);
Expand Down Expand Up @@ -492,8 +493,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a

*dst = extends_ok;
ip += 4;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_SET) {

CHECK_SPACE(3);
Expand All @@ -518,8 +520,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 4;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_GET) {

CHECK_SPACE(3);
Expand Down Expand Up @@ -550,8 +553,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 4;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_SET_NAMED) {

CHECK_SPACE(3);
Expand All @@ -575,8 +579,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 4;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_GET_NAMED) {

CHECK_SPACE(4);
Expand Down Expand Up @@ -609,8 +614,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 4;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_SET_MEMBER) {

CHECK_SPACE(3);
Expand All @@ -631,8 +637,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 3;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_GET_MEMBER) {

CHECK_SPACE(3);
Expand All @@ -649,8 +656,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 3;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_ASSIGN) {

CHECK_SPACE(3);
Expand All @@ -660,8 +668,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = *src;

ip += 3;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_ASSIGN_TRUE) {

CHECK_SPACE(2);
Expand All @@ -670,8 +679,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = true;

ip += 2;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_ASSIGN_FALSE) {

CHECK_SPACE(2);
Expand All @@ -680,8 +690,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = false;

ip += 2;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CONSTRUCT) {

CHECK_SPACE(2);
Expand All @@ -708,8 +719,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a

ip += 4 + argc;
//construct a basic type
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CONSTRUCT_ARRAY) {

CHECK_SPACE(1);
Expand All @@ -728,8 +740,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = array;

ip += 3 + argc;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {

CHECK_SPACE(1);
Expand All @@ -750,8 +763,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = dict;

ip += 3 + argc * 2;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CALL_RETURN)
OPCODE(OPCODE_CALL) {

Expand Down Expand Up @@ -830,8 +844,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a

//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
ip += argc + 1;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CALL_BUILT_IN) {

CHECK_SPACE(4);
Expand Down Expand Up @@ -869,12 +884,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += argc + 1;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_CALL_SELF) {

OPCODE_BREAK;
}

OPCODE(OPCODE_CALL_SELF_BASE) {

CHECK_SPACE(2);
Expand Down Expand Up @@ -948,8 +965,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}

ip += 4 + argc;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_YIELD)
OPCODE(OPCODE_YIELD_SIGNAL) {

Expand Down Expand Up @@ -1032,6 +1050,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
exit_ok = true;
OPCODE_BREAK;
}

OPCODE(OPCODE_YIELD_RESUME) {

CHECK_SPACE(2);
Expand All @@ -1044,17 +1063,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(result, 1);
*result = p_state->result;
ip += 2;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_JUMP) {

CHECK_SPACE(2);
int to = _code_ptr[ip + 1];

GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_JUMP_IF) {

CHECK_SPACE(3);
Expand All @@ -1067,11 +1088,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
DISPATCH_OPCODE;
} else {
ip += 3;
}
ip += 3;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_JUMP_IF_NOT) {

CHECK_SPACE(3);
Expand All @@ -1084,17 +1106,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
DISPATCH_OPCODE;
} else {
ip += 3;
}
ip += 3;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {

CHECK_SPACE(2);
ip = _default_arg_ptr[defarg];
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_RETURN) {

CHECK_SPACE(2);
Expand All @@ -1103,6 +1127,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
exit_ok = true;
OPCODE_BREAK;
}

OPCODE(OPCODE_ITERATE_BEGIN) {

CHECK_SPACE(8); //space for this a regular iterate
Expand All @@ -1121,20 +1146,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int jumpto = _code_ptr[ip + 3];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
DISPATCH_OPCODE;
}
GET_VARIANT_PTR(iterator, 4);
} else {
GET_VARIANT_PTR(iterator, 4);

*iterator = container->iter_get(*counter, valid);
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
if (!valid) {
err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
#endif
ip += 5; //skip regular iterate which is always next
DISPATCH_OPCODE;
ip += 5; //skip regular iterate which is always next
}
}
DISPATCH_OPCODE;

OPCODE(OPCODE_ITERATE) {

CHECK_SPACE(4);
Expand All @@ -1153,20 +1179,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int jumpto = _code_ptr[ip + 3];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
DISPATCH_OPCODE;
}
GET_VARIANT_PTR(iterator, 4);
} else {
GET_VARIANT_PTR(iterator, 4);

*iterator = container->iter_get(*counter, valid);
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
OPCODE_BREAK;
}
if (!valid) {
err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
OPCODE_BREAK;
}
#endif
ip += 5; //loop again
DISPATCH_OPCODE;
ip += 5; //loop again
}
}
DISPATCH_OPCODE;

OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(2);
GET_VARIANT_PTR(test, 1);
Expand All @@ -1182,17 +1209,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a

#endif
ip += 2;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_BREAKPOINT) {
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
}
#endif
ip += 1;
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_LINE) {
CHECK_SPACE(2);

Expand Down Expand Up @@ -1220,8 +1249,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a

ScriptDebugger::get_singleton()->line_poll();
}
DISPATCH_OPCODE;
}
DISPATCH_OPCODE;

OPCODE(OPCODE_END) {

exit_ok = true;
Expand Down

0 comments on commit 38ae49e

Please sign in to comment.