Go Fiber - Don't forget "Zero Allocation"

anilsenay

Anıl Şenay

Posted on January 6, 2024

Go Fiber - Don't forget "Zero Allocation"

I've been using Fiber for a long time and have found it to be quite efficient and enjoyable. It's a Golang web framework. Its performance, ease of use, and speed have made it the preferred option for many developers, including me. But even with the familiarity that comes with using it for a considerable amount of time, it's still simple to forget some important ideas. In my instance, after using Fiber nonstop for a while, I forgot about its zero-allocation paradigm. Although zero-allocation is an excellent feature intended to improve efficiency, I recently ran into a problem since I had momentarily forget it. It took me some time to remember that values returned from *fiber.Ctx are mutable to providing zero-allocation in Fiber.

Zero-Allocation

In summary, zero-allocation is a memory management method that aims to minimize the quantity of objects produced and garbage collected during runtime. Performance can be greatly improved by this method since it lowers the overhead related to memory allocation and deallocation. Fiber is a quick and light web framework that uses the zero-allocation concept to produce the best outcomes.

Some values returned from *fiber.Ctx are not immutable by default.

This quote is taken from Welcome page of Fiber documentation. You can also look at a few of the examples and details.

My Experiment

I was used Fiber to create a new Go application. A handler was included in the program to generate new items and store them in an in-memory slice. The handler merely appends new items to the slice after obtaining values from the request. I discovered that the values of the older slice items have also changed after adding a few items! It was a "WTF" moment, and I believed there was a glitch in my execution. I discovered after some debugging that the previous items were changed after the new request's values were obtained.

Let's look at this simple example to recreate the similar issue:

package main

import "github.com/gofiber/fiber/v2"

type Todo struct {
    Text string
}

func main() {
    todoList := []Todo{}
    app := fiber.New(fiber.Config{})

    app.Post("/", func(c *fiber.Ctx) error {
        text := c.Query("text")
        todoList = append(todoList, Todo{Text: text})
        return c.JSON(todoList)
    })

    _ = app.Listen(":3000")
}
Enter fullscreen mode Exit fullscreen mode

Next, make a localhost:3000?text=asd post request. and here is the response: :

[
    {
        "Text": "asd"
    }
]
Enter fullscreen mode Exit fullscreen mode

Then, send a second request: localhost:3000?text=q and response is:

[
    {
        "Text": "qsd"
    },
    {
        "Text": "q"
    },
]
Enter fullscreen mode Exit fullscreen mode

As you can see, the initial character of the first item has also been altered to q!

The only method to avoid this issue is to copy the value before assigning it to somewhere. The Fiber documentation offers a few solutions. Thus, I won't bring them up in this post once more. Pick the one that works best for you.

Conclusion

I just laughed and wanted to share it with others when I realized that. Even after using Fiber to create numerous microservices, I might still forget one of its fundamental ideas, which may happen to other developers as well.

Although there is no denying that zero-allocation improves efficiency, developers need to be aware of how it may affect user input processing. Because shared memory space increases the possibility of accidentally changing or overwriting user input, defensive and cautious coding techniques are essential. In order to guarantee data integrity and stability, developers must copy values returned from *fiber.Ctx before using them.

💖 💪 🙅 🚩
anilsenay
Anıl Şenay

Posted on January 6, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related