From d4d910bcfcf96a6e2e393f56a905e40608d6a575 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 15 Jul 2024 18:51:18 +0200 Subject: [PATCH 1/2] fmt: fix optional_len or use_nul_termination being used by both array and elems ```odin My_Struct :: struct { names: [^]string `fmt:"v,name_count"`, name_count: int, } main :: proc() { name := "hello?" foo := My_Struct { names = &name, name_count = 1, } fmt.println(foo) } ``` Before: `My_Struct{names = ["h"], name_count = 1}` After: `My_Struct{names = ["hello?"], name_count = 1}` --- core/fmt/fmt.odin | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index ef0647462..9aa9c99dc 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2751,9 +2751,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { elem := runtime.type_info_base(info.elem) if elem != nil { if n, ok := fi.optional_len.?; ok { + fi.optional_len = nil fmt_array(fi, ptr, n, elem.size, elem, verb) return } else if fi.use_nul_termination { + fi.use_nul_termination = false fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) return } @@ -2855,8 +2857,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { n := info.count ptr := v.data if ol, ok := fi.optional_len.?; ok { + fi.optional_len = nil n = min(n, ol) } else if fi.use_nul_termination { + fi.use_nul_termination = false fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) return } @@ -2867,8 +2871,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { n := slice.len ptr := slice.data if ol, ok := fi.optional_len.?; ok { + fi.optional_len = nil n = min(n, ol) } else if fi.use_nul_termination { + fi.use_nul_termination = false fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) return } @@ -2879,8 +2885,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { n := array.len ptr := array.data if ol, ok := fi.optional_len.?; ok { + fi.optional_len = nil n = min(n, ol) } else if fi.use_nul_termination { + fi.use_nul_termination = false fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) return } From f362e0fa20b6deedae24bcaeb518efed9de7f6b6 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 15 Jul 2024 19:27:48 +0200 Subject: [PATCH 2/2] add test for leaking struct tag into elems --- tests/core/fmt/test_core_fmt.odin | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 49142e24d..3a1eb37e7 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -372,6 +372,22 @@ test_odin_value_export :: proc(t: ^testing.T) { } } +@(test) +leaking_struct_tag :: proc(t: ^testing.T) { + My_Struct :: struct { + names: [^]string `fmt:"v,name_count"`, + name_count: int, + } + + name := "hello?" + foo := My_Struct { + names = &name, + name_count = 1, + } + + check(t, "My_Struct{names = [\"hello?\"], name_count = 1}", "%v", foo) +} + @(private) check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) { got := fmt.tprintf(format, ..args)