Commit d686113bd2

Andrew Kelley <superjoe30@gmail.com>
2017-12-20 04:38:02
fix crash when implicitly casting array of len 0 to slice
closes #660
1 parent 1cc450e
Changed files (3)
src/codegen.cpp
@@ -2722,6 +2722,9 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru
 }
 
 static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) {
+    if (!type_has_bits(instruction->base.value.type)) {
+        return nullptr;
+    }
     LLVMValueRef value = ir_llvm_value(g, instruction->value);
     if (handle_is_ptr(instruction->value->value.type)) {
         return value;
@@ -3013,6 +3016,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
                 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
             }
         }
+        if (!type_has_bits(array_type)) {
+            LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
+
+            // TODO if debug safety is on, store 0xaaaaaaa in ptr field
+            LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
+            gen_store_untyped(g, len_value, len_field_ptr, 0, false);
+            return tmp_struct_ptr;
+        }
+
 
         LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
         LLVMValueRef indices[] = {
src/ir.cpp
@@ -7748,8 +7748,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
 static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) {
     if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) {
         FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
-        assert(fn_entry);
-        fn_entry->alloca_list.append(instruction);
+        if (fn_entry != nullptr) {
+            fn_entry->alloca_list.append(instruction);
+        }
     }
 }
 
@@ -7851,9 +7852,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
         IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
         result->value.type = wanted_type;
         if (need_alloca) {
-            FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
-            if (fn_entry)
-                fn_entry->alloca_list.append(result);
+            ir_add_alloca(ira, result, wanted_type);
         }
         return result;
     }
@@ -8287,6 +8286,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
             assert(fn_entry);
             fn_entry->alloca_list.append(new_instruction);
         }
+        ir_add_alloca(ira, new_instruction, child_type);
         return new_instruction;
     }
 }
@@ -8330,13 +8330,15 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
 
     TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
             is_const, is_volatile, get_abi_alignment(ira->codegen, value->value.type), 0, 0);
-    FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
-    assert(fn_entry);
     IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
             source_instruction->source_node, value, is_const, is_volatile);
     new_instruction->value.type = ptr_type;
     new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
-    fn_entry->alloca_list.append(new_instruction);
+    if (type_has_bits(ptr_type)) {
+        FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
+        assert(fn_entry);
+        fn_entry->alloca_list.append(new_instruction);
+    }
     return new_instruction;
 }
 
test/cases/slice.zig
@@ -25,3 +25,12 @@ test "debug safety lets us slice from len..len" {
 fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) -> []u8 {
     return a_slice[start..end];
 }
+
+test "implicitly cast array of size 0 to slice" {
+    var msg = []u8 {};
+    assertLenIsZero(msg);
+}
+
+fn assertLenIsZero(msg: []const u8) {
+    assert(msg.len == 0);
+}