mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
vlib: enable more satnitized memleak detection runs without false positives on the CI (#23200)
This commit is contained in:
parent
903e349a7c
commit
b0772193f8
13
.github/workflows/run_sanitizers_leak.suppressions
vendored
Normal file
13
.github/workflows/run_sanitizers_leak.suppressions
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# websocket tests
|
||||
leak:mbedtls_ssl_setup
|
||||
|
||||
# sqlite tests
|
||||
leak:*sqlite*
|
||||
|
||||
# v
|
||||
leak:v__*
|
||||
leak:os__*
|
||||
leak:string__plus
|
||||
leak:malloc_uncollectable
|
||||
leak:new_array_from_c_array
|
||||
leak:_vinit
|
22
.github/workflows/sanitized_ci.yml
vendored
22
.github/workflows/sanitized_ci.yml
vendored
@ -75,7 +75,7 @@ concurrency:
|
||||
jobs:
|
||||
tests-sanitize-undefined-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
VJOBS: 1
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
|
||||
tests-sanitize-undefined-gcc:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
VJOBS: 1
|
||||
@ -126,7 +126,7 @@ jobs:
|
||||
|
||||
tests-sanitize-address-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 300
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
VJOBS: 1
|
||||
@ -146,16 +146,16 @@ jobs:
|
||||
- name: Recompile V with -cstrict
|
||||
run: ./v -cg -cstrict -o v cmd/v
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self vlib
|
||||
run: ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self vlib
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
run: ./v -cflags -fsanitize=address -o v cmd/v &&
|
||||
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler vlib
|
||||
ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v -cc tcc test-self -asan-compiler vlib
|
||||
- name: Build examples (V compiled with -fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v build-examples
|
||||
run: ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v build-examples
|
||||
|
||||
tests-sanitize-address-msvc:
|
||||
runs-on: windows-2019
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc msvc
|
||||
VJOBS: 1
|
||||
@ -179,7 +179,7 @@ jobs:
|
||||
|
||||
tests-sanitize-address-gcc:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 300
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
VJOBS: 1
|
||||
@ -199,13 +199,13 @@ jobs:
|
||||
- name: Recompile V with -cstrict
|
||||
run: ./v -cg -cstrict -o v cmd/v
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self vlib
|
||||
run: ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v -cflags -fsanitize=address test-self vlib
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
run:
|
||||
./v -cflags -fsanitize=address,pointer-compare,pointer-subtract -o v cmd/v &&
|
||||
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler vlib
|
||||
ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v -cc tcc test-self -asan-compiler vlib
|
||||
- name: Build examples (V compiled with -fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v build-examples
|
||||
run: ASAN_OPTIONS=detect_leaks=1:fast_unwind_on_malloc=0 LSAN_OPTIONS=max_leaks=1:print_suppressions=0:suppressions=.github/workflows/run_sanitizers_leak.suppressions ./v build-examples
|
||||
|
||||
tests-sanitize-memory-clang:
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -106,6 +106,9 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||
output = output.replace(' (discriminator', ': (d.')
|
||||
eprintln('${output:-55s} | ${addr:14s} | ${beforeaddr}')
|
||||
}
|
||||
if sframes.len > 0 {
|
||||
unsafe { C.free(csymbols) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,11 @@ pub fn compress(data []u8, flags int) ![]u8 {
|
||||
if u64(out_len) > max_size {
|
||||
return error('compressed data is too large (${out_len} > ${max_size})')
|
||||
}
|
||||
return unsafe { address.vbytes(int(out_len)) }
|
||||
unsafe {
|
||||
ret := address.vbytes(int(out_len)).clone()
|
||||
C.free(address)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
// decompresses an array of bytes based on providing flags and returns the decompressed bytes in a new array
|
||||
@ -40,5 +44,10 @@ pub fn decompress(data []u8, flags int) ![]u8 {
|
||||
if u64(out_len) > max_size {
|
||||
return error('decompressed data is too large (${out_len} > ${max_size})')
|
||||
}
|
||||
return unsafe { address.vbytes(int(out_len)) }
|
||||
|
||||
unsafe {
|
||||
ret := address.vbytes(int(out_len)).clone()
|
||||
C.free(address)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
@ -227,3 +227,8 @@ pub fn (pub_key PublicKey) equal(other PublicKey) bool {
|
||||
res := C.EC_POINT_cmp(group, point1, point2, ctx)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// Clear allocated memory for key
|
||||
pub fn key_free(ec_key &C.EC_KEY) {
|
||||
C.EC_KEY_free(ec_key)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ fn test_ecdsa() {
|
||||
is_valid := pub_key.verify(message, signature) or { panic(err) }
|
||||
println('Signature valid: ${is_valid}')
|
||||
assert is_valid
|
||||
key_free(priv_key.key)
|
||||
}
|
||||
|
||||
fn test_generate_key() ! {
|
||||
@ -19,6 +20,7 @@ fn test_generate_key() ! {
|
||||
pub_key, priv_key := generate_key() or { panic(err) }
|
||||
assert pub_key.key != unsafe { nil }
|
||||
assert priv_key.key != unsafe { nil }
|
||||
key_free(priv_key.key)
|
||||
}
|
||||
|
||||
fn test_new_key_from_seed() ! {
|
||||
@ -27,6 +29,7 @@ fn test_new_key_from_seed() ! {
|
||||
priv_key := new_key_from_seed(seed) or { panic(err) }
|
||||
retrieved_seed := priv_key.seed() or { panic(err) }
|
||||
assert seed == retrieved_seed
|
||||
key_free(priv_key.key)
|
||||
}
|
||||
|
||||
fn test_sign_and_verify() ! {
|
||||
@ -36,6 +39,7 @@ fn test_sign_and_verify() ! {
|
||||
signature := priv_key.sign(message) or { panic(err) }
|
||||
is_valid := pub_key.verify(message, signature) or { panic(err) }
|
||||
assert is_valid
|
||||
key_free(priv_key.key)
|
||||
}
|
||||
|
||||
fn test_seed() ! {
|
||||
@ -43,6 +47,7 @@ fn test_seed() ! {
|
||||
_, priv_key := generate_key() or { panic(err) }
|
||||
seed := priv_key.seed() or { panic(err) }
|
||||
assert seed.len > 0
|
||||
key_free(priv_key.key)
|
||||
}
|
||||
|
||||
fn test_public_key() ! {
|
||||
@ -51,6 +56,9 @@ fn test_public_key() ! {
|
||||
pub_key1 := priv_key.public_key() or { panic(err) }
|
||||
pub_key2, _ := generate_key() or { panic(err) }
|
||||
assert !pub_key1.equal(pub_key2)
|
||||
key_free(priv_key.key)
|
||||
key_free(pub_key1.key)
|
||||
key_free(pub_key2.key)
|
||||
}
|
||||
|
||||
fn test_private_key_equal() ! {
|
||||
@ -59,6 +67,8 @@ fn test_private_key_equal() ! {
|
||||
seed := priv_key1.seed() or { panic(err) }
|
||||
priv_key2 := new_key_from_seed(seed) or { panic(err) }
|
||||
assert priv_key1.equal(priv_key2)
|
||||
key_free(priv_key1.key)
|
||||
key_free(priv_key2.key)
|
||||
}
|
||||
|
||||
fn test_public_key_equal() ! {
|
||||
@ -67,6 +77,9 @@ fn test_public_key_equal() ! {
|
||||
pub_key1 := priv_key.public_key() or { panic(err) }
|
||||
pub_key2 := priv_key.public_key() or { panic(err) }
|
||||
assert pub_key1.equal(pub_key2)
|
||||
key_free(priv_key.key)
|
||||
key_free(pub_key1.key)
|
||||
key_free(pub_key2.key)
|
||||
}
|
||||
|
||||
fn test_sign_with_new_key_from_seed() ! {
|
||||
@ -78,6 +91,8 @@ fn test_sign_with_new_key_from_seed() ! {
|
||||
pub_key := priv_key.public_key() or { panic(err) }
|
||||
is_valid := pub_key.verify(message, signature) or { panic(err) }
|
||||
assert is_valid
|
||||
key_free(priv_key.key)
|
||||
key_free(pub_key.key)
|
||||
}
|
||||
|
||||
fn test_invalid_signature() ! {
|
||||
@ -88,9 +103,11 @@ fn test_invalid_signature() ! {
|
||||
result := pub_key.verify(message, invalid_signature) or {
|
||||
// Expecting verification to fail
|
||||
assert err.msg() == 'Failed to verify signature'
|
||||
key_free(pub_key.key)
|
||||
return
|
||||
}
|
||||
assert !result
|
||||
key_free(pub_key.key)
|
||||
}
|
||||
|
||||
fn test_different_keys_not_equal() ! {
|
||||
@ -98,4 +115,6 @@ fn test_different_keys_not_equal() ! {
|
||||
_, priv_key1 := generate_key() or { panic(err) }
|
||||
_, priv_key2 := generate_key() or { panic(err) }
|
||||
assert !priv_key1.equal(priv_key2)
|
||||
key_free(priv_key1.key)
|
||||
key_free(priv_key2.key)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ struct Baby {
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
db := sqlite.connect(':memory:')!
|
||||
mut db := sqlite.connect(':memory:')!
|
||||
|
||||
sql db {
|
||||
create table Parent
|
||||
@ -80,4 +80,6 @@ fn test_main() {
|
||||
assert parent[0].children[0].id == 1
|
||||
assert parent[0].children[1].id == 2
|
||||
assert parent[0].children.len == 2
|
||||
|
||||
db.close()!
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ fn records_by_field[T](db sqlite.DB, fieldname string, value string) ![]T {
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
db := sqlite.connect(':memory:')!
|
||||
mut db := sqlite.connect(':memory:')!
|
||||
sql db {
|
||||
create table Blog
|
||||
}!
|
||||
@ -40,4 +40,5 @@ fn test_main() {
|
||||
return
|
||||
}
|
||||
assert rows.len == 1
|
||||
db.close()!
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub:
|
||||
type Content = []u8 | string
|
||||
|
||||
struct Host {
|
||||
pub:
|
||||
pub mut:
|
||||
db Connection
|
||||
}
|
||||
|
||||
@ -92,7 +92,8 @@ fn test_can_access_sqlite_result_consts() {
|
||||
}
|
||||
|
||||
fn test_alias_db() {
|
||||
create_host(sqlite.connect(':memory:')!)!
|
||||
mut host := create_host(sqlite.connect(':memory:')!)!
|
||||
host.db.close()!
|
||||
assert true
|
||||
}
|
||||
|
||||
@ -110,7 +111,9 @@ fn test_exec_param_many() {
|
||||
'Sam',
|
||||
]) or {
|
||||
assert err.code() == 19 // constraint failure
|
||||
db.close()!
|
||||
return
|
||||
}
|
||||
db.close()!
|
||||
assert false
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ fn test_object_with_null() {
|
||||
root.add_item_to_object('name', cjson.create_string('Andre'))
|
||||
root.add_item_to_object('age', cjson.create_null())
|
||||
assert root.print_unformatted() == '{"name":"Andre","age":null}'
|
||||
unsafe { cjson.delete(root) }
|
||||
}
|
||||
|
||||
fn test_creating_complex_json() {
|
||||
@ -18,4 +19,5 @@ fn test_creating_complex_json() {
|
||||
println(result)
|
||||
|
||||
assert result == '["user",{"username":"foo","password":"bar"}]'
|
||||
unsafe { cjson.delete(root) }
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ fn C.cJSON_Print(object &C.cJSON) &char
|
||||
|
||||
fn C.cJSON_PrintUnformatted(object &C.cJSON) &char
|
||||
|
||||
fn C.cJSON_free(voidptr)
|
||||
|
||||
//
|
||||
|
||||
// version returns the version of cJSON as a string
|
||||
@ -168,7 +170,9 @@ pub fn (mut obj Node) print() string {
|
||||
// print serialises the node to a string, without formatting its structure, so the resulting string is shorter/cheaper to transmit.
|
||||
pub fn (mut obj Node) print_unformatted() string {
|
||||
mut s := C.cJSON_PrintUnformatted(obj)
|
||||
return unsafe { tos3(s) }
|
||||
ret := unsafe { tos_clone(&u8(s)) }
|
||||
C.cJSON_free(s)
|
||||
return ret
|
||||
}
|
||||
|
||||
// str returns the unformatted serialisation to string of the given Node.
|
||||
|
@ -3,6 +3,7 @@ import net
|
||||
import net.websocket
|
||||
import time
|
||||
|
||||
@[heap]
|
||||
struct WebsocketTestResults {
|
||||
pub mut:
|
||||
nr_messages int
|
||||
|
@ -10,7 +10,7 @@ const const_users_offset = 1
|
||||
const const_users_offset2 = 1
|
||||
|
||||
fn test_orm() {
|
||||
db := sqlite.connect(':memory:') or { panic(err) }
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
|
||||
upper_1 := User{
|
||||
name: 'Test'
|
||||
@ -31,4 +31,5 @@ fn test_orm() {
|
||||
} or { panic(err) }
|
||||
|
||||
assert result[0].name == 'Test'
|
||||
db.close()!
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ struct SubStruct {
|
||||
}
|
||||
|
||||
fn test_orm_sub_structs() {
|
||||
db := sqlite.connect(':memory:') or { panic(err) }
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
sql db {
|
||||
create table Upper
|
||||
}!
|
||||
@ -34,4 +34,5 @@ fn test_orm_sub_structs() {
|
||||
}!
|
||||
|
||||
assert uppers.first().sub.name == upper_1.sub.name
|
||||
db.close()!
|
||||
}
|
||||
|
@ -6,12 +6,14 @@ struct ORMTableSpecificName {
|
||||
}
|
||||
|
||||
fn test_orm_table_name() {
|
||||
db := sqlite.connect(':memory:') or { panic(err) }
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
r := sql db {
|
||||
select from ORMTableSpecificName
|
||||
} or {
|
||||
db.close()!
|
||||
assert true
|
||||
return
|
||||
}
|
||||
db.close()!
|
||||
assert false
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ fn x(m Movie) int {
|
||||
}
|
||||
|
||||
fn test_sql_statement_inside_fn_call() {
|
||||
db := sqlite.connect(':memory:') or { panic('failed') }
|
||||
mut db := sqlite.connect(':memory:') or { panic('failed') }
|
||||
sql db {
|
||||
create table Movie
|
||||
}!
|
||||
@ -21,4 +21,5 @@ fn test_sql_statement_inside_fn_call() {
|
||||
dump(x(sql db {
|
||||
select from Movie where id == 1
|
||||
}!.first()))
|
||||
db.close()!
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user