Skip to content

Crash when calling delete dynamic array with tracking_allocator #5076

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bigidea-kz opened this issue Apr 26, 2025 · 2 comments
Closed

Crash when calling delete dynamic array with tracking_allocator #5076

bigidea-kz opened this issue Apr 26, 2025 · 2 comments

Comments

@bigidea-kz
Copy link

OS: Windows 11
Odin version: dev-2025-04-nightly:d9f990d

Hello!

I'm learning the Odin programming language and encountered a crash today while experimenting with tracking_allocator.

I wrote a simple application, and the crash happens when calling delete(app.items) inside the destroy_app procedure:

destroy_app :: proc(app: ^App) {
    fmt.println("Destroy app: before delete")
    delete(app.items)
    fmt.println("Destroy app: after delete")

    for _, leak in app.allocator.allocation_map {
        fmt.printf("Memory leak: %v bytes at %p\n", leak.size, leak.location)
    }
    for i, bad_free in app.allocator.bad_free_array {
        fmt.printf("Bad free #%d: %p\n", i, bad_free)
    }

    mem.tracking_allocator_destroy(&app.allocator)
}

Full code

package main

import "core:fmt"
import "core:mem"
import "core:strings"

Item :: struct {
    title: string,
}

App :: struct {
    items: [dynamic]Item,
    allocator: mem.Tracking_Allocator,
}

init_app :: proc() -> App {
    app: App

    mem.tracking_allocator_init(&app.allocator, context.allocator)
    context.allocator = mem.tracking_allocator(&app.allocator)

    app.items = make([dynamic]Item, 0, 10)

    return app
}

destroy_app :: proc(app: ^App) {
    fmt.println("Destroy app: before delete")
    delete(app.items)
    fmt.println("Destroy app: after delete")

    for _, leak in app.allocator.allocation_map {
        fmt.printf("Memory leak: %v bytes at %p\n", leak.size, leak.location)
    }
    for i, bad_free in app.allocator.bad_free_array {
        fmt.printf("Bad free #%d: %p\n", i, bad_free)
    }

    mem.tracking_allocator_destroy(&app.allocator)
}

add_item :: proc(app: ^App) {
    task := Item{
        title = "Task"
    }

    append(&app.items, task)
}

main :: proc() {
    app := init_app()
    defer destroy_app(&app)

    add_item(&app)

    fmt.println("Reading task")
    for item in &app.items {
        fmt.println("task: ", item.title)
    }

    fmt.println("End program")
}
@bigidea-kz bigidea-kz changed the title Crash when calling delete(app.items) with tracking_allocator Crash when calling delete dynamic array with tracking_allocator Apr 26, 2025
@laytan
Copy link
Collaborator

laytan commented Apr 26, 2025

Context is scoped, assigning to it in init_app only reflects inside that same scope, see https://odin-lang.org/docs/overview/#implicit-context-system

@laytan laytan closed this as completed Apr 26, 2025
@Kelimion
Copy link
Member

The way I handle this:

package foo

import "core:mem"
import "core:fmt"

_main :: proc() {
    // Actual app begins here
}

main :: proc() {
	track: mem.Tracking_Allocator
	mem.tracking_allocator_init(&track, context.allocator)
	defer mem.tracking_allocator_destroy(&track)
	context.allocator = mem.tracking_allocator(&track)

	_main

	for _, leak in track.allocation_map {
		fmt.printf("%v leaked %m\n", leak.location, leak.size)
	}
}

For your app that'd be:

package main

import "core:fmt"
import "core:mem"

Item :: struct {
	title: string,
}

App :: struct {
	items: [dynamic]Item,
	allocator: mem.Tracking_Allocator,
}

init_app :: proc() -> App {
	app: App
	app.items = make([dynamic]Item, 0, 10)
	return app
}

destroy_app :: proc(app: ^App) {
	fmt.println("Destroy app: before delete")
	delete(app.items)
	fmt.println("Destroy app: after delete")

}

add_item :: proc(app: ^App) {
	task := Item{
		title = "Task",
	}
	append(&app.items, task)
}

_main :: proc() {
	app := init_app()
	defer destroy_app(&app)

	add_item(&app)

	fmt.println("Reading task")
	for item in &app.items {
		fmt.println("task: ", item.title)
	}
}

main :: proc() {
	track: mem.Tracking_Allocator
	mem.tracking_allocator_init(&track, context.allocator)
	context.allocator = mem.tracking_allocator(&track)

	_main()

	for _, leak in track.allocation_map {
		fmt.printf("Memory leak: %v bytes at %p\n", leak.size, leak.location)
	}
	for i, bad_free in track.bad_free_array {
		fmt.printf("Bad free #%d: %p\n", i, bad_free)
	}

	mem.tracking_allocator_destroy(&track)
	fmt.println("End program")
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants