check array bounds #134

Closed
opened 2021-12-13 21:54:32 +08:00 by sb10q · 4 comments
Owner

Currently out of bounds accesses just return bogus data or could even corrupt memory.

from numpy import int32
from min_artiq import *

@nac3
class Demo:
    core: KernelInvariant[Core]
    array: Kernel[list[int32]]

    def __init__(self):
        self.core = Core()
        self.array = [23, 56, 3]

    @kernel
    def run(self):
        for i in range(10):
            print_int32(self.array[i])


if __name__ == "__main__":
    Demo().run()
> python demo.py
> ../../target/release/runkernel ./module.elf
print_int32: 23
print_int32: 56
print_int32: 3
print_int32: 0
print_int32: 3
print_int32: 0
print_int32: 682837568
print_int32: 32590
print_int32: 682837560
print_int32: 32590

Currently out of bounds accesses just return bogus data or could even corrupt memory. ```python from numpy import int32 from min_artiq import * @nac3 class Demo: core: KernelInvariant[Core] array: Kernel[list[int32]] def __init__(self): self.core = Core() self.array = [23, 56, 3] @kernel def run(self): for i in range(10): print_int32(self.array[i]) if __name__ == "__main__": Demo().run() ``` ``` > python demo.py > ../../target/release/runkernel ./module.elf print_int32: 23 print_int32: 56 print_int32: 3 print_int32: 0 print_int32: 3 print_int32: 0 print_int32: 682837568 print_int32: 32590 print_int32: 682837560 print_int32: 32590 ```
sb10q added the
high-priority
label 2021-12-13 21:54:32 +08:00
Collaborator

Things related to the slice also needs these array bounds checks.. I am not sure.. should this be implemented after the exception since array bound cannot be easily checked statically?

Things related to the slice also needs these array bounds checks.. I am not sure.. should this be implemented after the exception since array bound cannot be easily checked statically?
Author
Owner

Well, generally speaking they cannot be checked statically at all.
Yes raising an exception would be a correct thing to do.

Well, generally speaking they cannot be checked statically at all. Yes raising an exception would be a correct thing to do.
ychenfo was assigned by sb10q 2021-12-21 18:49:11 +08:00
Author
Owner

Broken on x86_64 ("target": "host"):

> python demo.py
; ModuleID = 'main'
source_filename = "main"

%__main__.Demo = type { %min_artiq.Core*, { i32*, i64 }* }
%min_artiq.Core = type { double }
%Exception = type { i32, %str, i32, i32, %str, %str, i64, i64, i64 }
%str = type { i8*, i64 }

@"140481820991104" = external global %__main__.Demo
@const = private unnamed_addr constant [30 x i8] c"index {0} out of bounds 0:{1}\00", align 1
@const.1 = private unnamed_addr constant [37 x i8] c"/home/sb/nac3/nac3artiq/demo/demo.py\00", align 1
@const.2 = private unnamed_addr constant [20 x i8] c"__main__.Demo.run.0\00", align 1

define void @__main__.Demo.run.0(%__main__.Demo* %0) personality i32 (...)* @__artiq_personality {
init:
  br label %test

test:                                             ; preds = %succ, %init
  %tmp.0 = phi i32 [ -1, %init ], [ %start_loop, %succ ]
  %start_loop = add i32 %tmp.0, 1
  %cmp1 = icmp slt i32 %start_loop, 10
  %cmp2 = icmp sgt i32 %start_loop, 10
  br i1 %cmp1, label %body1, label %cont

body1:                                            ; preds = %test
  %load6 = load { i32*, i64 }*, { i32*, i64 }** getelementptr inbounds (%__main__.Demo, %__main__.Demo* @"140481820991104", i32 0, i32 1), align 8
  %gep7 = getelementptr { i32*, i64 }, { i32*, i64 }* %load6, i32 0, i32 0
  %load8 = load i32*, i32** %gep7, align 8
  %gep9 = getelementptr { i32*, i64 }, { i32*, i64 }* %load6, i32 0, i32 1
  %load10 = load i64, i64* %gep9, align 4
  %is_neg = icmp slt i32 %start_loop, i64 0
  %adjusted = add i32 %start_loop, i64 %load10
  %index = select i1 %is_neg, i32 %adjusted, i32 %start_loop
  %inbound = icmp ult i32 %index, i64 %load10
  br i1 %inbound, label %succ, label %fail, !prof !0

cont:                                             ; preds = %test
  ret void

succ:                                             ; preds = %body1
  %gep14 = getelementptr i32, i32* %load8, i32 %index
  %load15 = load i32, i32* %gep14, align 4
  call void @print_int32(i32 %load15)
  br label %test

fail:                                             ; preds = %body1
  %alloca = alloca %Exception, align 8
  %exn.id = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 0
  store i32 9, i32* %exn.id, align 4
  %exn.msg = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 5
  store %str { i8* getelementptr inbounds ([30 x i8], [30 x i8]* @const, i32 0, i32 0), i64 29 }, %str* %exn.msg, align 8
  %exn.param = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 6
  %sext = sext i32 %start_loop to i64
  store i64 %sext, i64* %exn.param, align 4
  %exn.param12 = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 7
  store i64 %load10, i64* %exn.param12, align 4
  %exn.param13 = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 8
  store i64 0, i64* %exn.param13, align 4
  %file_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 1
  store %str { i8* getelementptr inbounds ([37 x i8], [37 x i8]* @const.1, i32 0, i32 0), i64 36 }, %str* %file_ptr, align 8
  %row_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 2
  store i32 16, i32* %row_ptr, align 4
  %col_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 3
  store i32 35, i32* %col_ptr, align 4
  %name_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 4
  store %str { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @const.2, i32 0, i32 0), i64 19 }, %str* %name_ptr, align 8
  call void @__artiq_raise(%Exception* %alloca)
  unreachable
}

declare i32 @__artiq_personality(...)

declare void @print_int32(i32)

; Function Attrs: noreturn
declare void @__artiq_raise(%Exception*) #0

attributes #0 = { noreturn }

!0 = !{!"branch_weights", i32 2000, i32 1}

"Both operands to ICmp instruction are not of the same type!\n  %is_neg = icmp slt i32 %start_loop, i64 0\nBoth operands to a binary operator are not of the same type!\n  %adjusted = add i32 %start_loop, i64 %load10\nBoth operands to ICmp instruction are not of the same type!\n  %inbound = icmp ult i32 %index, i64 %load10\n"
thread '<unnamed>' panicked at 'explicit panic', /home/sb/nac3/nac3core/src/codegen/mod.rs:224:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Got an error: explicit panic
thread '<unnamed>' panicked at 'tasks panicked', nac3core/src/codegen/mod.rs:190:13
Traceback (most recent call last):
  File "/home/sb/nac3/nac3artiq/demo/demo.py", line 20, in <module>
    Demo().run()
  File "/home/sb/nac3/nac3artiq/demo/min_artiq.py", line 82, in run_on_core
    self.core.run(fake_method, *args, **kwargs)
  File "/home/sb/nac3/nac3artiq/demo/min_artiq.py", line 168, in run
    compiler.compile_method_to_file(obj, name, args, "module.elf", embedding)
pyo3_runtime.PanicException: tasks panicked

Broken on x86_64 (``"target": "host"``): ``` > python demo.py ; ModuleID = 'main' source_filename = "main" %__main__.Demo = type { %min_artiq.Core*, { i32*, i64 }* } %min_artiq.Core = type { double } %Exception = type { i32, %str, i32, i32, %str, %str, i64, i64, i64 } %str = type { i8*, i64 } @"140481820991104" = external global %__main__.Demo @const = private unnamed_addr constant [30 x i8] c"index {0} out of bounds 0:{1}\00", align 1 @const.1 = private unnamed_addr constant [37 x i8] c"/home/sb/nac3/nac3artiq/demo/demo.py\00", align 1 @const.2 = private unnamed_addr constant [20 x i8] c"__main__.Demo.run.0\00", align 1 define void @__main__.Demo.run.0(%__main__.Demo* %0) personality i32 (...)* @__artiq_personality { init: br label %test test: ; preds = %succ, %init %tmp.0 = phi i32 [ -1, %init ], [ %start_loop, %succ ] %start_loop = add i32 %tmp.0, 1 %cmp1 = icmp slt i32 %start_loop, 10 %cmp2 = icmp sgt i32 %start_loop, 10 br i1 %cmp1, label %body1, label %cont body1: ; preds = %test %load6 = load { i32*, i64 }*, { i32*, i64 }** getelementptr inbounds (%__main__.Demo, %__main__.Demo* @"140481820991104", i32 0, i32 1), align 8 %gep7 = getelementptr { i32*, i64 }, { i32*, i64 }* %load6, i32 0, i32 0 %load8 = load i32*, i32** %gep7, align 8 %gep9 = getelementptr { i32*, i64 }, { i32*, i64 }* %load6, i32 0, i32 1 %load10 = load i64, i64* %gep9, align 4 %is_neg = icmp slt i32 %start_loop, i64 0 %adjusted = add i32 %start_loop, i64 %load10 %index = select i1 %is_neg, i32 %adjusted, i32 %start_loop %inbound = icmp ult i32 %index, i64 %load10 br i1 %inbound, label %succ, label %fail, !prof !0 cont: ; preds = %test ret void succ: ; preds = %body1 %gep14 = getelementptr i32, i32* %load8, i32 %index %load15 = load i32, i32* %gep14, align 4 call void @print_int32(i32 %load15) br label %test fail: ; preds = %body1 %alloca = alloca %Exception, align 8 %exn.id = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 0 store i32 9, i32* %exn.id, align 4 %exn.msg = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 5 store %str { i8* getelementptr inbounds ([30 x i8], [30 x i8]* @const, i32 0, i32 0), i64 29 }, %str* %exn.msg, align 8 %exn.param = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 6 %sext = sext i32 %start_loop to i64 store i64 %sext, i64* %exn.param, align 4 %exn.param12 = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 7 store i64 %load10, i64* %exn.param12, align 4 %exn.param13 = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 8 store i64 0, i64* %exn.param13, align 4 %file_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 1 store %str { i8* getelementptr inbounds ([37 x i8], [37 x i8]* @const.1, i32 0, i32 0), i64 36 }, %str* %file_ptr, align 8 %row_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 2 store i32 16, i32* %row_ptr, align 4 %col_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 3 store i32 35, i32* %col_ptr, align 4 %name_ptr = getelementptr inbounds %Exception, %Exception* %alloca, i32 0, i32 4 store %str { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @const.2, i32 0, i32 0), i64 19 }, %str* %name_ptr, align 8 call void @__artiq_raise(%Exception* %alloca) unreachable } declare i32 @__artiq_personality(...) declare void @print_int32(i32) ; Function Attrs: noreturn declare void @__artiq_raise(%Exception*) #0 attributes #0 = { noreturn } !0 = !{!"branch_weights", i32 2000, i32 1} "Both operands to ICmp instruction are not of the same type!\n %is_neg = icmp slt i32 %start_loop, i64 0\nBoth operands to a binary operator are not of the same type!\n %adjusted = add i32 %start_loop, i64 %load10\nBoth operands to ICmp instruction are not of the same type!\n %inbound = icmp ult i32 %index, i64 %load10\n" thread '<unnamed>' panicked at 'explicit panic', /home/sb/nac3/nac3core/src/codegen/mod.rs:224:13 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Got an error: explicit panic thread '<unnamed>' panicked at 'tasks panicked', nac3core/src/codegen/mod.rs:190:13 Traceback (most recent call last): File "/home/sb/nac3/nac3artiq/demo/demo.py", line 20, in <module> Demo().run() File "/home/sb/nac3/nac3artiq/demo/min_artiq.py", line 82, in run_on_core self.core.run(fake_method, *args, **kwargs) File "/home/sb/nac3/nac3artiq/demo/min_artiq.py", line 168, in run compiler.compile_method_to_file(obj, name, args, "module.elf", embedding) pyo3_runtime.PanicException: tasks panicked ```
Contributor

Ah, yes, forgot to do sext.

Ah, yes, forgot to do sext.
sb10q closed this issue 2022-02-13 17:41:47 +08:00
Sign in to join this conversation.
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3#134
No description provided.