authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-07 14:51:25-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-04-07 14:51:25-04:00
log22dbeab29dab9e349122a539acdf7e32561109dd
treed60ba06808ed7805ad92c5b378625d7a1b823762
parentcc0fca9d83f5a62cf0e109dde3a323c01ea71301
parent0a936c1d766e3f0b81d86bffee95d15b50fc6d58
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4857 from LemonBoy/fix-4777

Rewrite the bound checks in slice operator

4 files changed, 209 insertions(+), 99 deletions(-)

lib/std/debug.zig+1-1
...@@ -1213,7 +1213,7 @@ pub const DebugInfo = struct {...@@ -1213,7 +1213,7 @@ pub const DebugInfo = struct {
1213 const obj_di = try self.allocator.create(ModuleDebugInfo);1213 const obj_di = try self.allocator.create(ModuleDebugInfo);
1214 errdefer self.allocator.destroy(obj_di);1214 errdefer self.allocator.destroy(obj_di);
12151215
1216 obj_di.* = openCoffDebugInfo(self.allocator, name_buffer[0..:0]) catch |err| switch (err) {1216 obj_di.* = openCoffDebugInfo(self.allocator, name_buffer[0 .. len + 4 :0]) catch |err| switch (err) {
1217 error.FileNotFound => return error.MissingDebugInfo,1217 error.FileNotFound => return error.MissingDebugInfo,
1218 else => return err,1218 else => return err,
1219 };1219 };
lib/std/fs.zig+1-1
...@@ -1522,7 +1522,7 @@ pub fn openSelfExe() OpenSelfExeError!File {...@@ -1522,7 +1522,7 @@ pub fn openSelfExe() OpenSelfExeError!File {
1522 var buf: [MAX_PATH_BYTES]u8 = undefined;1522 var buf: [MAX_PATH_BYTES]u8 = undefined;
1523 const self_exe_path = try selfExePath(&buf);1523 const self_exe_path = try selfExePath(&buf);
1524 buf[self_exe_path.len] = 0;1524 buf[self_exe_path.len] = 0;
1525 return openFileAbsoluteZ(self_exe_path[0..self_exe_path.len :0].ptr, .{});1525 return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, .{});
1526}1526}
15271527
1528test "openSelfExe" {1528test "openSelfExe" {
src/codegen.cpp+138-97
...@@ -5498,6 +5498,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5498,6 +5498,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutableGen *executable, Ir
5498}5498}
54995499
5500static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {5500static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrInstGenSlice *instruction) {
5501 Error err;
5502
5501 LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);5503 LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
5502 ZigType *array_ptr_type = instruction->ptr->value->type;5504 ZigType *array_ptr_type = instruction->ptr->value->type;
5503 assert(array_ptr_type->id == ZigTypeIdPointer);5505 assert(array_ptr_type->id == ZigTypeIdPointer);
...@@ -5506,15 +5508,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5506,15 +5508,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
55065508
5507 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);5509 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
55085510
5511 // The result is either a slice or a pointer to an array
5509 ZigType *result_type = instruction->base.value->type;5512 ZigType *result_type = instruction->base.value->type;
5510 if (!type_has_bits(g, result_type)) {
5511 return nullptr;
5512 }
55135513
5514 // This is not whether the result type has a sentinel, but whether there should be a sentinel check,5514 // This is not whether the result type has a sentinel, but whether there should be a sentinel check,
5515 // e.g. if they used [a..b :s] syntax.5515 // e.g. if they used [a..b :s] syntax.
5516 ZigValue *sentinel = instruction->sentinel;5516 ZigValue *sentinel = instruction->sentinel;
55175517
5518 LLVMValueRef slice_start_ptr = nullptr;
5519 LLVMValueRef len_value = nullptr;
5520
5518 if (array_type->id == ZigTypeIdArray ||5521 if (array_type->id == ZigTypeIdArray ||
5519 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))5522 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
5520 {5523 {
...@@ -5528,111 +5531,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5528,111 +5531,86 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5528 } else {5531 } else {
5529 end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false);5532 end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false);
5530 }5533 }
5534
5531 if (want_runtime_safety) {5535 if (want_runtime_safety) {
5536 // Safety check: start <= end
5532 if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) {5537 if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) {
5533 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);5538 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
5534 }5539 }
5535 if (instruction->end) {
5536 LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
5537 array_type->data.array.len, false);
5538 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
55395540
5540 if (sentinel != nullptr) {5541 // Safety check: the last element of the slice (the sentinel if
5541 LLVMValueRef indices[] = {5542 // requested) must be inside the array
5542 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),5543 // XXX: Overflow is not checked here...
5543 end_val,5544 const size_t full_len = array_type->data.array.len +
5544 };5545 (array_type->data.array.sentinel != nullptr);
5545 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");5546 LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
5546 add_sentinel_check(g, sentinel_elem_ptr, sentinel);5547 full_len, false);
5547 }
5548 }
5549 }
5550 if (!type_has_bits(g, array_type)) {
5551 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
55525548
5553 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5549 LLVMValueRef check_end_val = end_val;
55545550 if (sentinel != nullptr) {
5555 // TODO if runtime safety is on, store 0xaaaaaaa in ptr field5551 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
5556 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5552 check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, "");
5557 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5553 }
5558 return tmp_struct_ptr;5554 add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
5559 }5555 }
55605556
5561 LLVMValueRef indices[] = {5557 bool value_has_bits;
5562 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),5558 if ((err = type_has_bits2(g, array_type, &value_has_bits)))
5563 start_val,5559 codegen_report_errors_and_exit(g);
5564 };
5565 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
5566 if (result_type->id == ZigTypeIdPointer) {
5567 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5568 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5569 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5570 } else {
5571 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5572 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
5573 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
55745560
5575 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5561 if (value_has_bits) {
5576 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5562 if (want_runtime_safety && sentinel != nullptr) {
5577 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5563 LLVMValueRef indices[] = {
5564 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
5565 end_val,
5566 };
5567 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
5568 add_sentinel_check(g, sentinel_elem_ptr, sentinel);
5569 }
55785570
5579 return tmp_struct_ptr;5571 LLVMValueRef indices[] = {
5572 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
5573 start_val,
5574 };
5575 slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
5580 }5576 }
5577
5578 len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, "");
5581 } else if (array_type->id == ZigTypeIdPointer) {5579 } else if (array_type->id == ZigTypeIdPointer) {
5582 assert(array_type->data.pointer.ptr_len != PtrLenSingle);5580 assert(array_type->data.pointer.ptr_len != PtrLenSingle);
5583 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);5581 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
5584 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);5582 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
55855583
5586 if (want_runtime_safety) {5584 if (want_runtime_safety) {
5585 // Safety check: start <= end
5587 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);5586 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
5588 if (sentinel != nullptr) {5587 }
5588
5589 bool value_has_bits;
5590 if ((err = type_has_bits2(g, array_type, &value_has_bits)))
5591 codegen_report_errors_and_exit(g);
5592
5593 if (value_has_bits) {
5594 if (want_runtime_safety && sentinel != nullptr) {
5589 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, "");5595 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &end_val, 1, "");
5590 add_sentinel_check(g, sentinel_elem_ptr, sentinel);5596 add_sentinel_check(g, sentinel_elem_ptr, sentinel);
5591 }5597 }
5592 }
55935598
5594 if (!type_has_bits(g, array_type)) {5599 slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
5595 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5596 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5597 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5598 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5599 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
5600 return tmp_struct_ptr;
5601 }5600 }
56025601
5603 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");5602 len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, "");
5604 if (result_type->id == ZigTypeIdPointer) {
5605 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5606 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5607 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5608 }
5609
5610 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5611
5612 size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index;
5613 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
5614 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
5615
5616 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5617 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5618 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5619 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
5620
5621 return tmp_struct_ptr;
5622
5623 } else if (array_type->id == ZigTypeIdStruct) {5603 } else if (array_type->id == ZigTypeIdStruct) {
5624 assert(array_type->data.structure.special == StructSpecialSlice);5604 assert(array_type->data.structure.special == StructSpecialSlice);
5625 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);5605 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
5626 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);5606 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
56275607
5628 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;5608 const size_t gen_len_index = array_type->data.structure.fields[slice_len_index]->gen_index;
5629 assert(ptr_index != SIZE_MAX);5609 assert(gen_len_index != SIZE_MAX);
5630 size_t len_index = array_type->data.structure.fields[slice_len_index]->gen_index;
5631 assert(len_index != SIZE_MAX);
56325610
5633 LLVMValueRef prev_end = nullptr;5611 LLVMValueRef prev_end = nullptr;
5634 if (!instruction->end || want_runtime_safety) {5612 if (!instruction->end || want_runtime_safety) {
5635 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, "");5613 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_len_index, "");
5636 prev_end = gen_load_untyped(g, src_len_ptr, 0, false, "");5614 prev_end = gen_load_untyped(g, src_len_ptr, 0, false, "");
5637 }5615 }
56385616
...@@ -5644,41 +5622,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5644,41 +5622,104 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5644 end_val = prev_end;5622 end_val = prev_end;
5645 }5623 }
56465624
5647 LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, "");5625 ZigType *ptr_field_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
5648 LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
56495626
5650 if (want_runtime_safety) {5627 if (want_runtime_safety) {
5651 assert(prev_end);5628 assert(prev_end);
5629 // Safety check: start <= end
5652 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);5630 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
5653 if (instruction->end) {
5654 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
56555631
5656 if (sentinel != nullptr) {5632 // Safety check: the sentinel counts as one more element
5657 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, "");5633 // XXX: Overflow is not checked here...
5658 add_sentinel_check(g, sentinel_elem_ptr, sentinel);5634 LLVMValueRef check_prev_end = prev_end;
5659 }5635 if (ptr_field_type->data.pointer.sentinel != nullptr) {
5636 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
5637 check_prev_end = LLVMBuildNUWAdd(g->builder, prev_end, usize_one, "");
5638 }
5639 LLVMValueRef check_end_val = end_val;
5640 if (sentinel != nullptr) {
5641 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
5642 check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, "");
5660 }5643 }
5644
5645 add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, check_prev_end);
5661 }5646 }
56625647
5663 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");5648 bool ptr_has_bits;
5664 if (result_type->id == ZigTypeIdPointer) {5649 if ((err = type_has_bits2(g, ptr_field_type, &ptr_has_bits)))
5665 ir_assert(instruction->result_loc == nullptr, &instruction->base);5650 codegen_report_errors_and_exit(g);
5666 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);5651
5667 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");5652 if (ptr_has_bits) {
5668 } else {5653 const size_t gen_ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
5669 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);5654 assert(gen_ptr_index != SIZE_MAX);
5670 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
5671 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
56725655
5673 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");5656 LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, gen_ptr_index, "");
5674 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5657 LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
5675 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
56765658
5677 return tmp_struct_ptr;5659 if (sentinel != nullptr) {
5660 LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &end_val, 1, "");
5661 add_sentinel_check(g, sentinel_elem_ptr, sentinel);
5662 }
5663
5664 slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");
5678 }5665 }
5666
5667 len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, "");
5679 } else {5668 } else {
5680 zig_unreachable();5669 zig_unreachable();
5681 }5670 }
5671
5672 bool result_has_bits;
5673 if ((err = type_has_bits2(g, result_type, &result_has_bits)))
5674 codegen_report_errors_and_exit(g);
5675
5676 // Nothing to do, we're only interested in the bound checks emitted above
5677 if (!result_has_bits)
5678 return nullptr;
5679
5680 // The starting pointer for the slice may be null in case of zero-sized
5681 // arrays, the length value is always defined.
5682 assert(len_value != nullptr);
5683
5684 // The slice decays into a pointer to an array, the size is tracked in the
5685 // type itself
5686 if (result_type->id == ZigTypeIdPointer) {
5687 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5688 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5689
5690 if (slice_start_ptr != nullptr) {
5691 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5692 }
5693
5694 return LLVMGetUndef(result_ptr_type);
5695 }
5696
5697 ir_assert(instruction->result_loc != nullptr, &instruction->base);
5698 // Create a new slice
5699 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5700
5701 ZigType *slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry;
5702
5703 // The slice may not have a pointer at all if it points to a zero-sized type
5704 const size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index;
5705 if (gen_ptr_index != SIZE_MAX) {
5706 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
5707 if (slice_start_ptr != nullptr) {
5708 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
5709 } else if (want_runtime_safety) {
5710 gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr);
5711 } else {
5712 gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false);
5713 }
5714 }
5715
5716 const size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5717 assert(gen_len_index != SIZE_MAX);
5718
5719 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5720 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
5721
5722 return tmp_struct_ptr;
5682}5723}
56835724
5684static LLVMValueRef get_trap_fn_val(CodeGen *g) {5725static LLVMValueRef get_trap_fn_val(CodeGen *g) {
test/runtime_safety.zig+69
...@@ -1,6 +1,75 @@...@@ -1,6 +1,75 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub fn addCases(cases: *tests.CompareOutputContext) void {
4 {
5 const check_panic_msg =
6 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
7 \\ if (std.mem.eql(u8, message, "index out of bounds")) {
8 \\ std.process.exit(126); // good
9 \\ }
10 \\ std.process.exit(0); // test failed
11 \\}
12 ;
13
14 cases.addRuntimeSafety("slicing operator with sentinel",
15 \\const std = @import("std");
16 ++ check_panic_msg ++
17 \\pub fn main() void {
18 \\ var buf = [4]u8{'a','b','c',0};
19 \\ const slice = buf[0..4 :0];
20 \\}
21 );
22 cases.addRuntimeSafety("slicing operator with sentinel",
23 \\const std = @import("std");
24 ++ check_panic_msg ++
25 \\pub fn main() void {
26 \\ var buf = [4]u8{'a','b','c',0};
27 \\ const slice = buf[0..:0];
28 \\}
29 );
30 cases.addRuntimeSafety("slicing operator with sentinel",
31 \\const std = @import("std");
32 ++ check_panic_msg ++
33 \\pub fn main() void {
34 \\ var buf_zero = [0]u8{};
35 \\ const slice = buf_zero[0..0 :0];
36 \\}
37 );
38 cases.addRuntimeSafety("slicing operator with sentinel",
39 \\const std = @import("std");
40 ++ check_panic_msg ++
41 \\pub fn main() void {
42 \\ var buf_zero = [0]u8{};
43 \\ const slice = buf_zero[0..:0];
44 \\}
45 );
46 cases.addRuntimeSafety("slicing operator with sentinel",
47 \\const std = @import("std");
48 ++ check_panic_msg ++
49 \\pub fn main() void {
50 \\ var buf_sentinel = [2:0]u8{'a','b'};
51 \\ @ptrCast(*[3]u8, &buf_sentinel)[2] = 0;
52 \\ const slice = buf_sentinel[0..3 :0];
53 \\}
54 );
55 cases.addRuntimeSafety("slicing operator with sentinel",
56 \\const std = @import("std");
57 ++ check_panic_msg ++
58 \\pub fn main() void {
59 \\ var buf_slice: []u8 = &[3]u8{ 'a', 'b', 0 };
60 \\ const slice = buf_slice[0..3 :0];
61 \\}
62 );
63 cases.addRuntimeSafety("slicing operator with sentinel",
64 \\const std = @import("std");
65 ++ check_panic_msg ++
66 \\pub fn main() void {
67 \\ var buf_slice: []u8 = &[3]u8{ 'a', 'b', 0 };
68 \\ const slice = buf_slice[0.. :0];
69 \\}
70 );
71 }
72
4 cases.addRuntimeSafety("shift left by huge amount",73 cases.addRuntimeSafety("shift left by huge amount",
5 \\const std = @import("std");74 \\const std = @import("std");
6 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {75 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {