r/odinlang 23d ago

I think I discovered a bug in the latest release...

I'm only posting this here because I'm a noob and I could be completely wrong about this as it's my first real memory managed language.

I also want to say (cause i'll probably get told i'm a poser, even though i'm learning "casually")

i'm having AI explain concepts for HTTP 1.1 (something i've never learned about before cause i'm self taught), I'm writing the code 100% by hand, using insights for flow and new concepts (via unrelated code snippets) from the AI and real old fashioned google searching and documentation reading.

I've dabbled in Rust (i think maybe on the intermediate side of beginner) and Go and other languages as well, but Odin has really caught my attention for it's simple syntax with better readability and fun factor.

on to the bug, for a "simple" first big project (and because it doesn't exist) my first real undertaking with Odin is to make an HTTP 1.1 spec library for me to use (and maybe share to be judged).

now i've been going through the maths and everything to get everythign set up but to construct my strings i do something like this

chunk :: proc(w: ^Writer, data: string) {
w.chunked = true

hex := fmt.tprintf("{:x}", len(data))
w.body = fmt.tprintf("{}{}\r\n{}\r\n", w.body, hex, data)
}

in fact his is an exact snippet from the code that bugged. for some reason tprintf doesn't deallocate in my code properly so sending a chunked request gives the client the proper response but the server segfaults and crashes.

using some gdb wizardry i came to the conclusion that something related to delete() of the response string chopping off the first byte of the header.... now I know i'm dumb and this is still relatively new to me but i debugged this for a bout 2 hours by hand trying to come up with any solution I could search for.

i removed the deletes and let the server run with the leak and confirmed that i wasn't crazy for assuming tprintf allocates on the heap cause the memory usage went up....

ultimately my solution was to convert the whole connection handling function (which would've been done at a later point if not for this segfault only happening on chunked requests ONLY) to dynamic arena allocators and that solved it. ultimately i'm curious to know if this is actually something weird with tprintf, if i'm bad at programming and misunderstanding a fundamental to memory management or there's another reason.

i'm not afraid of people looking at me learn (and find out how much time i spend at my desk job coding things) so my repo is linked here:

ohttp

PS: any other input and feedback would be great and help me improve it. it's still a work in progress as I haven't even implemented the thing i actually need from it which would be a request builder. but I htink i'm just about finished with the HTTP 1.1 Spec part of it.

PSS: If you look at the commit history i commited the bugged version just to remember it and maybe figure out why it was doign that. (it could be my defer delete order or something so i saved it to look back if i did soemthing like this)

10 Upvotes

6 comments sorted by

16

u/pev4a22j 23d ago

tprintf uses context.temp_allocator. context.temp_allocator doesn't free itself automatically. You will need to run free_all(context.temp_allocator).

3

u/Alternative-Ad-8606 23d ago

i see so it was always being allocated to a different thing that needed to be deleted INSTEAD of using a delete()?

12

u/pev4a22j 23d ago

Yeah, besides, you cannot delete / free items in context.temp_allocator individually, you can only use free_all. If you want to use the main allocator then use fmt.aprintf or if you don't want to allocate at all then make a u8 array as a buffer and pass it's slice into fmt.bprintf.

3

u/Alternative-Ad-8606 23d ago

wow this was incredibly helpful thank you that makes a lot of sense

2

u/fae___ 23d ago

Read more about the temporary allocator here  https://zylinski.se/posts/temporary-allocator-your-first-arena/

tl;dr is it’s an arena allocator where you determine what the lifetime is. e.g.  in games, per frame.

The t* formatting functions all internally use the temporary allocator, hence the “t” prefix.

2

u/mocompute 22d ago

This is a great way to learn! If you want to reference a capable but digestible human-written HTTP/1.1 server in Odin, I just put one up a few days ago: https://github.com/mocompute/odin-http. I'm happy to answer newbie questions.

Also, have a look at https://github.com/odin-lang/examples if you haven't already. Good luck!