cgen: add fixed array bounds checking for non-literal index (#8832)
parent
41a3b115a1
commit
15daeaeafa
8
TESTS.md
8
TESTS.md
|
@ -18,6 +18,11 @@ Tip: use `v -cc tcc` when compiling tests for speed.
|
||||||
|
|
||||||
General runnable tests for different features of the V compiler.
|
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)
|
## Test building of actual V programs (examples, tools, V itself)
|
||||||
|
|
||||||
* `v build-tools`
|
* `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 checks all source files are formatted and prints a summary.
|
||||||
This is not required.
|
This is not required.
|
||||||
|
|
||||||
## Other
|
|
||||||
* `v test-fmt`
|
* `v test-fmt`
|
||||||
|
|
||||||
Test all files in the current directory are formatted.
|
Test all files in the current directory are formatted.
|
||||||
|
|
||||||
|
## Markdown
|
||||||
|
|
||||||
* `v check-md -hide-warnings .`
|
* `v check-md -hide-warnings .`
|
||||||
|
|
||||||
Ensure that all .md files in the project are formatted properly,
|
Ensure that all .md files in the project are formatted properly,
|
||||||
|
|
|
@ -274,3 +274,14 @@ pub fn is_atty(fd int) int {
|
||||||
return C.isatty(fd)
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -4217,6 +4217,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// indexing
|
||||||
sym := g.table.get_final_type_symbol(node.left_type)
|
sym := g.table.get_final_type_symbol(node.left_type)
|
||||||
left_is_ptr := node.left_type.is_ptr()
|
left_is_ptr := node.left_type.is_ptr()
|
||||||
if sym.kind == .array {
|
if sym.kind == .array {
|
||||||
|
@ -4397,7 +4398,15 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
}
|
}
|
||||||
g.write('[')
|
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(']')
|
g.write(']')
|
||||||
if is_fn_index_call {
|
if is_fn_index_call {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
|
|
@ -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_default',
|
||||||
'__new_array_with_array_default',
|
'__new_array_with_array_default',
|
||||||
'new_array_from_c_array',
|
'new_array_from_c_array',
|
||||||
|
'v_fixed_index',
|
||||||
'memdup',
|
'memdup',
|
||||||
'vstrlen',
|
'vstrlen',
|
||||||
'__as_cast',
|
'__as_cast',
|
||||||
|
|
|
@ -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 os
|
||||||
import term
|
import term
|
||||||
import v.util
|
import v.util
|
||||||
|
@ -52,7 +56,7 @@ fn test_all() {
|
||||||
n_found := normalize_panic_message(found, vroot)
|
n_found := normalize_panic_message(found, vroot)
|
||||||
n_expected := normalize_panic_message(expected, vroot)
|
n_expected := normalize_panic_message(expected, vroot)
|
||||||
if found.contains('================ V panic ================') {
|
if found.contains('================ V panic ================') {
|
||||||
if n_found.contains(n_expected) {
|
if n_found.starts_with(n_expected) {
|
||||||
println(term.green('OK (panic)'))
|
println(term.green('OK (panic)'))
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -86,7 +90,10 @@ fn test_all() {
|
||||||
|
|
||||||
fn normalize_panic_message(message string, vroot string) string {
|
fn normalize_panic_message(message string, vroot string) string {
|
||||||
mut msg := message.all_before('=========================================')
|
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()
|
msg = msg.trim_space()
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
a := [1,2]!
|
||||||
|
println(a[0])
|
||||||
|
i := 2
|
||||||
|
_ = a[i]
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
||||||
|
a := [1,2]!
|
||||||
|
i := 3
|
||||||
|
_ = a[i..i]
|
Loading…
Reference in New Issue