Skip to content

Commit

Permalink
Bounds checking on length for foo[1:2] slicing #1191
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Apr 28, 2024
1 parent 89ecd4b commit 60805fd
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 8 deletions.
1 change: 1 addition & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Added `print-input` command argument to print all files used for compilation
- Allow recursive function definitions as long as they are pointers. #1182
- Default CPU to native if less than AVX, otherwise use AVX.
- Bounds checking on length for `foo[1:2]` slicing #1191.

### Fixes
- Incorrect length passed to scratch buffer printf.
Expand Down
30 changes: 22 additions & 8 deletions src/compiler/llvm_codegen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2954,16 +2954,30 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
}

// This will trap any bad negative index, so we're fine.
if (safe_mode_enabled() && !is_len_range)
if (safe_mode_enabled())
{
BEValue excess;
llvm_emit_int_comp(c, &excess, &start_index, &end_index, BINARYOP_GT);
llvm_emit_panic_if_true(c, &excess, "Negative size", slice->span, "Negative size (start %d is less than end %d)", &start_index, &end_index);

if (len.value)
if (is_len_range)
{
llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LT);
llvm_emit_panic_if_true(c, &excess, "Size exceeds index", slice->span, "Size exceeds index (end index was %d, size was %d)", &end_index, &len);
if (len.value)
{
BEValue excess;
llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LT);
BEValue actual_end_index = end_index;
actual_end_index.value = llvm_emit_sub_int(c, end_type, end_index.value, llvm_const_int(c, end_type, 1), slice->span);
llvm_emit_panic_if_true(c, &excess, "End index out of bounds", slice->span, "End index out of bounds (end index of %d exceeds size of %d)", &actual_end_index, &len);
}
}
else
{
BEValue excess;
llvm_emit_int_comp(c, &excess, &start_index, &end_index, BINARYOP_GT);
llvm_emit_panic_if_true(c, &excess, "Negative size", slice->span, "Negative size (start %d is less than end %d)", &start_index, &end_index);

if (len.value)
{
llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LE);
llvm_emit_panic_if_true(c, &excess, "End index out of bounds", slice->span, "End index out of bounds (end index of %d exceeds size of %d)", &end_index, &len);
}
}
}
}
Expand Down
128 changes: 128 additions & 0 deletions test/test_suite/subarrays/slice_checks.c3t
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// #target: macos-x64
// #safe: yes

module mymodule;

fn void main()
{
int[4] array;
int[] slice = &array;

int[] slice1 = slice[2..5];
int[] slice2 = slice[6..];
int[] slice3 = slice[0..9];
int[] slice4 = slice[5:10];
int[] slice5 = slice[1..3];
int[] slice6 = slice[2:10];
}

/* #expect: mymodule.ll

store i32 0, ptr %array, align 4
%ptradd = getelementptr inbounds i8, ptr %array, i64 4
store i32 0, ptr %ptradd, align 4
%ptradd1 = getelementptr inbounds i8, ptr %array, i64 8
store i32 0, ptr %ptradd1, align 4
%ptradd2 = getelementptr inbounds i8, ptr %array, i64 12
store i32 0, ptr %ptradd2, align 4
%0 = insertvalue %"int[]" undef, ptr %array, 0
%1 = insertvalue %"int[]" %0, i64 4, 1
store %"int[]" %1, ptr %slice, align 8
%2 = load %"int[]", ptr %slice, align 8
%3 = extractvalue %"int[]" %2, 0
%4 = extractvalue %"int[]" %2, 1
%gt = icmp ugt i64 2, %4
%5 = call i1 @llvm.expect.i1(i1 %gt, i1 false)
br i1 %5, label %panic, label %checkok

checkok: ; preds = %entry
%ge = icmp uge i64 5, %4
%6 = call i1 @llvm.expect.i1(i1 %ge, i1 false)
br i1 %6, label %panic5, label %checkok12

checkok12: ; preds = %checkok
%ptradd13 = getelementptr inbounds i8, ptr %3, i64 8
%7 = insertvalue %"int[]" undef, ptr %ptradd13, 0
%8 = insertvalue %"int[]" %7, i64 4, 1
store %"int[]" %8, ptr %slice1, align 8
%9 = load %"int[]", ptr %slice, align 8
%10 = extractvalue %"int[]" %9, 0
%11 = extractvalue %"int[]" %9, 1
%gt14 = icmp ugt i64 6, %11
%12 = call i1 @llvm.expect.i1(i1 %gt14, i1 false)
br i1 %12, label %panic15, label %checkok22

checkok22: ; preds = %checkok12
%size = sub i64 %11, 6
%ptradd23 = getelementptr inbounds i8, ptr %10, i64 24
%13 = insertvalue %"int[]" undef, ptr %ptradd23, 0
%14 = insertvalue %"int[]" %13, i64 %size, 1
store %"int[]" %14, ptr %slice2, align 8
%15 = load %"int[]", ptr %slice, align 8
%16 = extractvalue %"int[]" %15, 0
%17 = extractvalue %"int[]" %15, 1
%gt24 = icmp ugt i64 0, %17
%18 = call i1 @llvm.expect.i1(i1 %gt24, i1 false)
br i1 %18, label %panic25, label %checkok32

checkok32: ; preds = %checkok22
%ge33 = icmp uge i64 9, %17
%19 = call i1 @llvm.expect.i1(i1 %ge33, i1 false)
br i1 %19, label %panic34, label %checkok41

checkok41: ; preds = %checkok32
%20 = insertvalue %"int[]" undef, ptr %16, 0
%21 = insertvalue %"int[]" %20, i64 10, 1
store %"int[]" %21, ptr %slice3, align 8
%22 = load %"int[]", ptr %slice, align 8
%23 = extractvalue %"int[]" %22, 0
%24 = extractvalue %"int[]" %22, 1
%gt42 = icmp ugt i64 5, %24
%25 = call i1 @llvm.expect.i1(i1 %gt42, i1 false)
br i1 %25, label %panic43, label %checkok50

checkok50: ; preds = %checkok41
%gt51 = icmp ugt i64 15, %24
%26 = call i1 @llvm.expect.i1(i1 %gt51, i1 false)
br i1 %26, label %panic52, label %checkok59

checkok59: ; preds = %checkok50
%ptradd60 = getelementptr inbounds i8, ptr %23, i64 20
%27 = insertvalue %"int[]" undef, ptr %ptradd60, 0
%28 = insertvalue %"int[]" %27, i64 10, 1
store %"int[]" %28, ptr %slice4, align 8
%29 = load %"int[]", ptr %slice, align 8
%30 = extractvalue %"int[]" %29, 0
%31 = extractvalue %"int[]" %29, 1
%gt61 = icmp ugt i64 1, %31
%32 = call i1 @llvm.expect.i1(i1 %gt61, i1 false)
br i1 %32, label %panic62, label %checkok69

checkok69: ; preds = %checkok59
%ge70 = icmp uge i64 3, %31
%33 = call i1 @llvm.expect.i1(i1 %ge70, i1 false)
br i1 %33, label %panic71, label %checkok78

checkok78: ; preds = %checkok69
%ptradd79 = getelementptr inbounds i8, ptr %30, i64 4
%34 = insertvalue %"int[]" undef, ptr %ptradd79, 0
%35 = insertvalue %"int[]" %34, i64 3, 1
store %"int[]" %35, ptr %slice5, align 8
%36 = load %"int[]", ptr %slice, align 8
%37 = extractvalue %"int[]" %36, 0
%38 = extractvalue %"int[]" %36, 1
%gt80 = icmp ugt i64 2, %38
%39 = call i1 @llvm.expect.i1(i1 %gt80, i1 false)
br i1 %39, label %panic81, label %checkok88

checkok88: ; preds = %checkok78
%gt89 = icmp ugt i64 12, %38
%40 = call i1 @llvm.expect.i1(i1 %gt89, i1 false)
br i1 %40, label %panic90, label %checkok97

checkok97: ; preds = %checkok88
%ptradd98 = getelementptr inbounds i8, ptr %37, i64 8
%41 = insertvalue %"int[]" undef, ptr %ptradd98, 0
%42 = insertvalue %"int[]" %41, i64 10, 1
store %"int[]" %42, ptr %slice6, align 8
ret void

0 comments on commit 60805fd

Please sign in to comment.