authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-27 19:40:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-27 19:40:35-04:00
log2e512a0e6e81532b62ddb7fdafdcd28926690eaa
treec20acbfa1e99c7d7edef93ac57a86dbe8eee5666
parent1691074b4b1f080b3a1f7ca7dc7426c6ef4c242a

add compile error for returning local variable address

closes #344

4 files changed, 28 insertions(+), 2 deletions(-)

src/all_types.hpp+7
...@@ -201,6 +201,12 @@ enum RuntimeHintMaybe {...@@ -201,6 +201,12 @@ enum RuntimeHintMaybe {
201 RuntimeHintMaybeNonNull,201 RuntimeHintMaybeNonNull,
202};202};
203203
204enum RuntimeHintPtr {
205 RuntimeHintPtrUnknown,
206 RuntimeHintPtrStack,
207 RuntimeHintPtrNonStack,
208};
209
204struct ConstFn {210struct ConstFn {
205 FnTableEntry *fn_entry;211 FnTableEntry *fn_entry;
206 bool is_inline;212 bool is_inline;
...@@ -233,6 +239,7 @@ struct ConstExprValue {...@@ -233,6 +239,7 @@ struct ConstExprValue {
233 // populated if special == ConstValSpecialRuntime239 // populated if special == ConstValSpecialRuntime
234 RuntimeHintErrorUnion rh_error_union;240 RuntimeHintErrorUnion rh_error_union;
235 RuntimeHintMaybe rh_maybe;241 RuntimeHintMaybe rh_maybe;
242 RuntimeHintPtr rh_ptr;
236 } data;243 } data;
237};244};
238245
src/ir.cpp+11
...@@ -7538,6 +7538,13 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,...@@ -7538,6 +7538,13 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
7538 if (casted_value == ira->codegen->invalid_instruction)7538 if (casted_value == ira->codegen->invalid_instruction)
7539 return ir_unreach_error(ira);7539 return ir_unreach_error(ira);
75407540
7541 if (casted_value->value.special == ConstValSpecialRuntime &&
7542 casted_value->value.type->id == TypeTableEntryIdPointer &&
7543 casted_value->value.data.rh_ptr == RuntimeHintPtrStack)
7544 {
7545 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
7546 return ir_unreach_error(ira);
7547 }
7541 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);7548 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);
7542 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);7549 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
7543}7550}
...@@ -8467,6 +8474,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -8467,6 +8474,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
8467 instruction->scope, instruction->source_node, var, is_const, is_volatile);8474 instruction->scope, instruction->source_node, var, is_const, is_volatile);
8468 var_ptr_instruction->value.type = get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);8475 var_ptr_instruction->value.type = get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
8469 type_ensure_zero_bits_known(ira->codegen, var->value->type);8476 type_ensure_zero_bits_known(ira->codegen, var->value->type);
8477
8478 bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
8479 var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
8480
8470 return var_ptr_instruction;8481 return var_ptr_instruction;
8471 }8482 }
8472}8483}
std/build.zig+2-2
...@@ -887,7 +887,7 @@ pub const LibExeObjStep = struct {...@@ -887,7 +887,7 @@ pub const LibExeObjStep = struct {
887 %%zig_args.append(lib_path);887 %%zig_args.append(lib_path);
888 }888 }
889889
890 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());890 %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
891891
892 if (self.kind == Kind.Lib and !self.static) {892 if (self.kind == Kind.Lib and !self.static) {
893 // sym link for libfoo.so.1 to libfoo.so.1.2.3893 // sym link for libfoo.so.1 to libfoo.so.1.2.3
...@@ -994,7 +994,7 @@ pub const TestStep = struct {...@@ -994,7 +994,7 @@ pub const TestStep = struct {
994 %%zig_args.append(lib_path);994 %%zig_args.append(lib_path);
995 }995 }
996996
997 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());997 %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
998 }998 }
999};999};
10001000
test/compile_errors.zig+8
...@@ -1610,4 +1610,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1610,4 +1610,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1610 ,1610 ,
1611 ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'",1611 ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'",
1612 ".tmp_source.zig:1:8: note: declared here");1612 ".tmp_source.zig:1:8: note: declared here");
1613
1614 cases.add("returning address of local variable",
1615 \\export fn foo() -> &i32 {
1616 \\ var a: i32 = undefined;
1617 \\ return &a;
1618 \\}
1619 ,
1620 ".tmp_source.zig:3:13: error: function returns address of local variable");
1613}1621}