# bufPrint bug workaround

**URL:** <https://ziggit.dev/t/bufprint-bug-workaround/4366>\
**Category:** Help\
**Tags:** language, standard-library\
**Created:** [May 18, 2024, 6:12pm UTC](https://ziggit.dev/t/bufprint-bug-workaround/4366 "2024-05-18T18:12:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Av1d](https://ziggit.dev/user_avatar/ziggit.dev/av1d/32/2383_2.png) [@Av1d](https://ziggit.dev/u/Av1d)\
**Post date:** [May 18, 2024, 6:12pm UTC](https://ziggit.dev/t/bufprint-bug-workaround/4366/1 "2024-05-18T18:12:43Z")

</div>

Hi guys!

I’m building a language parser and trying to make the resulting AST printable for inspection and testing. Each expression has a `string()` method, that uses `std.fmt.bufPrint()` method to represent the expression as a string. Everything is fine until I try to use return value of one `bufPrint` in another `bufPrint`. If there are 2 placeholders, it outputs some gibberish, and if I leave only one placeholder I get a panic.

Here is the code. The issue is in the `.pref` branch.

```zig
pub const Expression = union(enum) {
    ident: Identifier,
    int: Integer,
    pref: Prefix,
    inf: Infix,

    pub fn string(self: @This(), buf: []u8) ![]u8 {
        return switch (self) {
            .ident => |ident| bufPrint(buf, "{s}", .{ident.token.get_value().?}),
            .int => |int| bufPrint(buf, "{d}", .{int.value}),
            .pref => |pref| bufPrint(buf, "({s}{s})", .{
                @tagName(pref.token),
                try pref.right.string(buf),
            }),
            .inf => unreachable,
        };
    }
};

```

Given expressions  
“!5” and “-15”  
expected output:  
“(bang5)” and “(minus15)”  
got:  
“(bang()” and “(minus(m)”

Panic on removing the first placeholder and value:  
_thread 322558 panic: @memcpy arguments alias_  
_Unwind error at address `exe:0x8051d33` (error.MissingFDE), trace may be incomplete_

Looking at the following issue it seems to be a bug with bufPrint, so I don’t think I’m doing something wrong. The question is if there is some workaround to be able to continue using bufPrint, or is there a good alternative that can be used for this task.

> <https://github.com/ziglang/zig/issues/15850>
>
> \### Zig Version
> 
> 0.11.0-dev.3298+5744ceedb
> 
> \### Steps to Reproduce and Observed …Behavior
> 
> \`\`\`zig
> const std = @import("std");
> const bufPrint = std.fmt.bufPrint;
> 
> test "bufPrint arguments alias" {
> var buf: \[10\]u8 = undefined;
> const foo = try bufPrint(&buf, "{s}", .{"foo"});
> const foobar = try bufPrint(&buf, "{s}{s}", .{ foo, "bar" });
> \_ = foobar;
> }
> \`\`\`
> \`\`\`
> $ zig test test.zig
> Test \[1/1\] test.bufPrint aliased arguments... thread 19632 panic: @memcpy arguments alias
> /snap/zig/7524/lib/std/io/fixed\_buffer\_stream.zig:70:57: 0x2112bf in write (test)
> @memcpy(self.buffer\[self.pos..\]\[0..n\], bytes\[0..n\]);
> ^
> /snap/zig/7524/lib/std/io/writer.zig:17:27: 0x21bc4b in write (test)
> return writeFn(self.context, bytes);
> ^
> /snap/zig/7524/lib/std/io/writer.zig:23:40: 0x212dc2 in writeAll (test)
> index += try self.write(bytes\[index..\]);
> ^
> /snap/zig/7524/lib/std/fmt.zig:1055:28: 0x2127f8 in formatBuf\_\_anon\_3582 (test)
> try writer.writeAll(buf);
> ^
> /snap/zig/7524/lib/std/fmt.zig:656:45: 0x210208 in formatType\_\_anon\_1453 (test)
> return formatBuf(value, options, writer);
> ^
> /snap/zig/7524/lib/std/fmt.zig:184:23: 0x2100c6 in format\_\_anon\_1440 (test)
> try formatType(
> ^
> /snap/zig/7524/lib/std/fmt.zig:1995:15: 0x20f54c in bufPrint\_\_anon\_1144 (test)
> try format(fbs.writer(), fmt, args);
> ^
> /home/jayschwa/Desktop/test.zig:7:32: 0x20f267 in test.bufPrint aliased arguments (test)
> const foobar = try bufPrint(&buf, "{s}{s}", .{ foo, "bar" });
> ^
> \`\`\`
> 
> \### Expected Behavior
> 
> This concatenative use of \`bufPrint\` worked not long ago (within the last month, I think). If the new behavior is working as intended, then documentation for the function probably ought to mention it.

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [May 18, 2024, 6:25pm UTC](https://ziggit.dev/t/bufprint-bug-workaround/4366/2 "2024-05-18T18:25:54Z")

</div>

Hi @Av1d Welcome to ziggit 🙂

> [@Av1d](#):
>
> ```zig
> bufPrint(buf, "({s}{s})", .{
> @tagName(pref.token),
> try pref.right.string(buf),
> })
> 
> ```

Here `buf` is both output and input.  
There is no guarantee that `bufPrint` is not going to override the input stored in the output buffer.  
To solve this you need different buffers.

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [May 18, 2024, 6:44pm UTC](https://ziggit.dev/t/bufprint-bug-workaround/4366/3 "2024-05-18T18:44:10Z")

</div>

I think I would define and use a format function instead and then just print the object in whatever way is appropriate. With the writer you don’t have to pre-decide whether you want to use a buffer or not and your code stays agnostic.  
This post is a good description:

> [@Idiomatic Complex Formatting](https://ziggit.dev/t/idiomatic-complex-formatting/3735/5):
>
> The idiomatic way of implementing custom formatting would be to implement a format function. [std.fmt.format](https://ziglang.org/documentation/master/std/#std.fmt.format), which std.debug.print and other formatting functions that take a format string with placeholders are derived from, has this to say in its doc comment: If a formatted user type contains a function of the type pub fn format( value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void with ? being the type formatted, this function will be call…

---

<div class="post-metadata">

**Author:** ![Av1d](https://ziggit.dev/user_avatar/ziggit.dev/av1d/32/2383_2.png) [@Av1d](https://ziggit.dev/u/Av1d)\
**Post date:** [May 20, 2024, 3:34pm UTC](https://ziggit.dev/t/bufprint-bug-workaround/4366/4 "2024-05-20T15:34:18Z")

</div>

Thank you all! That was quite helpful. I’ve actually tried @dimdin 's solution before, but decided that it’s too hacky. Now though, it does not look _too_ bad to me.

The `std.fmt.format` stuff is really interesting. Didn’t know Zig has such things in std. I’ll try to make use of it.

Appreciate the help. Cheers!
