Skip to content
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

all: make GC opt-in via sdl_use_gc, remove -d sdl_memory_no_gc #860

Merged
merged 3 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,22 @@ Also note that SDL2 **is not** compatible with SDL `v1.x`.
## Notes on garbage collection and memory issues

Currently, with some setups, SDL2 is known to trigger crashes when used in conjunction
with V's default garbage collector. In these cases running apps importing `sdl` with
`v run` you may experience runtime crashes and output similar to this:
with V's default garbage collector. Because of this you have to explicitly **opt-in**
to use V's garbage collection with SDL2.

If you choose to use the garbage collector with SDL objects
(by running apps importing `sdl` with `v -d sdl_use_gc run`)
you may experience runtime crashes and output similar to this:

```
main__main: RUNTIME ERROR: invalid memory access
```

We are tracking the issue here: https://github.com/vlang/sdl/issues/744

The crashes can be avoided by passing `-d sdl_memory_no_gc` when compiling V applications
that contains `import sdl` and managing SDL2's memory manually with calls to the various
`destroy` and `sdl.free/1` functions.
The crashes can be avoided by simply **not** passing `-d sdl_use_gc` and
managing memory manually with SDL's memory functions like `sdl.free/1`, `sdl.malloc/1`,
`sdl.calloc/2`, `sdl.realloc/2` and the various `create_*` and `destroy` functions.

## Support

Expand Down Expand Up @@ -131,9 +135,9 @@ To do this, change to the root directory of the sdl module, like
`cd %HOMEPATH%\.vmodules\sdl`
and run
`v run windows_install_dependencies.vsh`.
This will create a directory called "thirdparty" which will be used to download and extract the required libraries.
To successfully run a provided example or your own projects, the sdl dlls must be copied to the main application directory.
e.g.:
This will create a directory called "thirdparty" which will be used to download and
extract the required libraries. To successfully run a provided example or your own projects,
the sdl dlls must be copied to the main application directory. e.g.:
```bash
copy thirdparty\SDL2-2.0.8\lib\x64\SDL2.dll examples\basic_window\
cd ..
Expand Down
24 changes: 12 additions & 12 deletions c/memory.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module c
// that Boehm will later know how to process. The callbacks here provide such versions:
fn cb_malloc_func(size usize) voidptr {
mut res := unsafe { nil }
$if sdl_memory_no_gc ? {
res = unsafe { C.malloc(size) }
} $else {
$if sdl_use_gc ? {
res = unsafe { malloc(int(size)) }
} $else {
res = unsafe { C.malloc(size) }
}
$if trace_sdl_memory ? {
C.fprintf(C.stderr, c'>> sdl.c.cb_malloc_func | size: %lu | => %p\n', size, res)
Expand All @@ -17,10 +17,10 @@ fn cb_malloc_func(size usize) voidptr {

fn cb_calloc_func(nmemb usize, size usize) voidptr {
mut res := unsafe { nil }
$if sdl_memory_no_gc ? {
res = unsafe { C.calloc(int(nmemb), int(size)) }
} $else {
$if sdl_use_gc ? {
res = unsafe { vcalloc(isize(nmemb) * isize(size)) }
} $else {
res = unsafe { C.calloc(int(nmemb), int(size)) }
}
$if trace_sdl_memory ? {
C.fprintf(C.stderr, c'>> sdl.c.cb_calloc_func | nmemb: %lu | size: %lu | => %p\n',
Expand All @@ -31,10 +31,10 @@ fn cb_calloc_func(nmemb usize, size usize) voidptr {

fn cb_realloc_func(mem voidptr, size usize) voidptr {
mut res := unsafe { nil }
$if sdl_memory_no_gc ? {
res = unsafe { C.realloc(&u8(mem), int(size)) }
} $else {
$if sdl_use_gc ? {
res = unsafe { v_realloc(&u8(mem), isize(size)) }
} $else {
res = unsafe { C.realloc(&u8(mem), int(size)) }
}
$if trace_sdl_memory ? {
C.fprintf(C.stderr, c'>> sdl.c.cb_realloc_func | mem: %p | size: %lu | => %p\n',
Expand All @@ -47,10 +47,10 @@ fn cb_free_func(mem voidptr) {
$if trace_sdl_memory ? {
C.fprintf(C.stderr, c'>> sdl.c.cb_free_func | mem: %p\n', mem)
}
$if sdl_memory_no_gc ? {
unsafe { C.free(mem) }
} $else {
$if sdl_use_gc ? {
unsafe { free(mem) }
} $else {
unsafe { C.free(mem) }
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/crash_with_gc.vv
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// This file serves as a MRE (minimal reproducible example) of a runtime crash triggered by compiling and running
// this file with just `v run ~/.vmodules/sdl/tests/crash_with_gc.vv`. On some setups, the problem seems to be
// this file with `v -d sdl_use_gc run ~/.vmodules/sdl/tests/crash_with_gc.vv`. On some setups, the problem seems to be
// memory corruption happening between actions in SDL2's memory allocations and V's default garbage collector.
// Especially when a lot of heap allocations occur.
//
// The example does not crash if compiled with `-d sdl_memory_no_gc`.
// The example crashes if compiled with `-d sdl_use_gc`.
// See also: https://github.com/vlang/sdl/issues/744
module main

Expand Down Expand Up @@ -53,7 +53,7 @@ fn main() {
sdl.render_clear(renderer)
sdl.render_present(renderer)
}
println('Exiting. If this was compiled without `-d sdl_memory_no_gc`, an invalid memory access error should occur')
println('Exiting. If this was compiled with `-d sdl_use_gc`, an invalid memory access error should occur')

sdl.destroy_renderer(renderer)
sdl.destroy_window(window)
Expand Down
Loading