From 2fd960f12c986baa10d4663e5f54c1ce929b5c2b Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 30 Jun 2020 18:28:28 +0300 Subject: [PATCH] builtin: implement a double free detection for v strings --- vlib/builtin/string.v | 23 ++++++++++++++++++----- vlib/v/gen/str.v | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 0159689ac5..849e7d3295 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -46,10 +46,18 @@ pub struct string { pub: str byteptr // points to a C style 0 terminated string of bytes. len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str). - is_lit bool +mut: + is_lit int } - // mut: - // hash_cache int +// mut: +// hash_cache int +// +// NB string.is_lit is an enumeration of the following: +// .is_lit == 0 => a fresh string, should be freed by autofree +// .is_lit == 1 => a literal string from .rodata, should NOT be freed +// .is_lit == -98761234 => already freed string, protects against double frees. +// ^^^^^^^^^ calling free on these is a bug. +// Any other value means that the string has been corrupted. pub struct ustring { pub mut: @@ -109,7 +117,7 @@ pub fn tos_lit(s charptr) string { return string{ str: byteptr(s) len: C.strlen(s) - is_lit:true + is_lit: 1 } } @@ -1186,10 +1194,15 @@ pub fn (c byte) is_letter() bool { } pub fn (s &string) free() { - if s.is_lit || s.len == 0 { + if s.is_lit == -98761234 { + C.printf('double string.free() detected\n') + return + } + if s.is_lit == 1 || s.len == 0 { return } free(s.str) + s.is_lit = -98761234 } // all_before('23:34:45.234', '.') == '23:34:45' diff --git a/vlib/v/gen/str.v b/vlib/v/gen/str.v index f7b0912be9..8f395eceeb 100644 --- a/vlib/v/gen/str.v +++ b/vlib/v/gen/str.v @@ -108,7 +108,7 @@ string _STR_TMP(const char *fmt, ...) { //puts(g_str_buf); #endif string res = tos(g_str_buf, len); - res.is_lit = true; + res.is_lit = 1; return res; } // endof _STR_TMP