cgen: add fixed array bounds checking for non-literal index (#8832)

pull/8904/head
Nick Treleaven 2021-02-22 12:54:24 +00:00 committed by GitHub
parent 41a3b115a1
commit 15daeaeafa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 56 additions and 4 deletions

View File

@ -18,6 +18,11 @@ Tip: use `v -cc tcc` when compiling tests for speed.
General runnable tests for different features of the V compiler.
* `vlib/v/tests/inout/compiler_test.v`
Test output of running a V program matches an expected .out file.
Check the source for how to test panics.
## Test building of actual V programs (examples, tools, V itself)
* `v build-tools`
@ -41,11 +46,12 @@ This verifies that `_keep.v` files would be unchanged by `vfmt -w`.
This checks all source files are formatted and prints a summary.
This is not required.
## Other
* `v test-fmt`
Test all files in the current directory are formatted.
## Markdown
* `v check-md -hide-warnings .`
Ensure that all .md files in the project are formatted properly,

View File

@ -274,3 +274,14 @@ pub fn is_atty(fd int) int {
return C.isatty(fd)
}
}
[inline]
fn v_fixed_index(i int, len int) int {
$if !no_bounds_checking ? {
if i < 0 || i >= len {
s := 'fixed array index out of range (index: $i, len: $len)'
panic(s)
}
}
return i
}

View File

@ -4217,6 +4217,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
g.write(')')
}
else {
// indexing
sym := g.table.get_final_type_symbol(node.left_type)
left_is_ptr := node.left_type.is_ptr()
if sym.kind == .array {
@ -4397,7 +4398,15 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
g.expr(node.left)
}
g.write('[')
g.expr(node.index)
direct := g.fn_decl != 0 && g.fn_decl.is_direct_arr
if direct || node.index is ast.IntegerLiteral {
g.expr(node.index)
} else {
// bounds check
g.write('v_fixed_index(')
g.expr(node.index)
g.write(', $info.size)')
}
g.write(']')
if is_fn_index_call {
g.write(')')

View File

@ -22,6 +22,7 @@ pub fn mark_used(mut the_table table.Table, pref &pref.Preferences, ast_files []
'__new_array_with_default',
'__new_array_with_array_default',
'new_array_from_c_array',
'v_fixed_index',
'memdup',
'vstrlen',
'__as_cast',

View File

@ -1,3 +1,7 @@
// .out file:
// To test a panic, remove everything after the long `===` line
// You can also remove the line with 'line:' e.g. for a builtin fn
import os
import term
import v.util
@ -52,7 +56,7 @@ fn test_all() {
n_found := normalize_panic_message(found, vroot)
n_expected := normalize_panic_message(expected, vroot)
if found.contains('================ V panic ================') {
if n_found.contains(n_expected) {
if n_found.starts_with(n_expected) {
println(term.green('OK (panic)'))
continue
} else {
@ -86,7 +90,10 @@ fn test_all() {
fn normalize_panic_message(message string, vroot string) string {
mut msg := message.all_before('=========================================')
msg = msg.replace(vroot + os.path_separator, '')
// change windows to nix path
s := vroot.replace(os.path_separator, '/')
// remove vroot
msg = msg.replace(s + '/', '')
msg = msg.trim_space()
return msg
}

View File

@ -0,0 +1,6 @@
1
================ V panic ================
module: builtin
function: v_fixed_index()
message: fixed array index out of range (index: 2, len: 2)
file: vlib/builtin/builtin.c.v

View File

@ -0,0 +1,4 @@
a := [1,2]!
println(a[0])
i := 2
_ = a[i]

View File

@ -0,0 +1,5 @@
================ V panic ================
module: builtin
function: slice()
message: array.slice: slice bounds out of range (3 >= 2)
file: vlib/builtin/array.v

View File

@ -0,0 +1,3 @@
a := [1,2]!
i := 3
_ = a[i..i]