Skip to content

Commit c1fa8e1

Browse files
Fix crash in nk_buffer_realloc and forbid the use of realloc
In short: the default implementation of nk_allocator (aka nk_malloc) is fundamentally broken, and should have used realloc instead of malloc. This led to the strange workaround in nk_buffer_realloc that would crash whenever you use custom allocator with correct realloc assumption. We cannot change nk_malloc at this point, as people could have implemented their own allocators based on it, but we can ensure that Nuklear itself will never try to reallocate memory. Fixes: #768
1 parent b5f67b8 commit c1fa8e1

4 files changed

Lines changed: 30 additions & 21 deletions

File tree

demo/sdl3_renderer/nuklear_sdl3_renderer.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,7 @@ NK_INTERN void *
112112
nk_sdl_alloc(nk_handle user, void *old, nk_size size)
113113
{
114114
NK_UNUSED(user);
115-
/* FIXME: nk_sdl_alloc should use SDL_realloc here, not SDL_malloc
116-
* but this could cause a double-free due to bug within Nuklear, see:
117-
* https://github.com/Immediate-Mode-UI/Nuklear/issues/768
118-
* */
119-
#if 0
120115
return SDL_realloc(old, size);
121-
#else
122-
NK_UNUSED(old);
123-
return SDL_malloc(size);
124-
#endif
125116
}
126117

127118
NK_INTERN void

nuklear.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8498,7 +8498,16 @@ NK_LIB void*
84988498
nk_malloc(nk_handle unused, void *old,nk_size size)
84998499
{
85008500
NK_UNUSED(unused);
8501-
NK_UNUSED(old);
8501+
/*
8502+
* Due to historical reasons, Nuklear always calls alloc(user,old,size)
8503+
* with the "old" pointer always being NULL. For full explanation, see:
8504+
* https://github.com/Immediate-Mode-UI/Nuklear/issues/768
8505+
*
8506+
* Note that this limitation is only meant for Nuklear's internal code.
8507+
* If you're wondering what to pass into nk_allocator's "alloc" field,
8508+
* you can still pass realloc there and it will work just fine.
8509+
*/
8510+
NK_ASSERT(!old && "Nuklear's internal code must never reallocate existing memory !");
85028511
return malloc(size);
85038512
}
85048513
NK_LIB void
@@ -8591,15 +8600,13 @@ nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
85918600
return 0;
85928601

85938602
buffer_size = b->memory.size;
8594-
temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
8603+
temp = b->pool.alloc(b->pool.userdata, 0, capacity);
85958604
NK_ASSERT(temp);
85968605
if (!temp) return 0;
85978606

85988607
*size = capacity;
8599-
if (temp != b->memory.ptr) {
8600-
NK_MEMCPY(temp, b->memory.ptr, buffer_size);
8601-
b->pool.free(b->pool.userdata, b->memory.ptr);
8602-
}
8608+
NK_MEMCPY(temp, b->memory.ptr, buffer_size);
8609+
b->pool.free(b->pool.userdata, b->memory.ptr);
86038610

86048611
if (b->size == buffer_size) {
86058612
/* no back buffer so just set correct size */
@@ -30736,6 +30743,8 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
3073630743
/// - [y]: Minor version with non-breaking API and library changes
3073730744
/// - [z]: Patch version with no direct changes to the API
3073830745
///
30746+
/// - 2026/01/27 (4.13.1) - Fix crash inside of nk_buffer_realloc and
30747+
/// forbid the use of realloc in the whole library (internally only)
3073930748
/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'
3074030749
/// Add new updated demo: sdl3_renderer
3074130750
/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,

src/CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
/// - [y]: Minor version with non-breaking API and library changes
88
/// - [z]: Patch version with no direct changes to the API
99
///
10+
/// - 2026/01/27 (4.13.1) - Fix crash inside of nk_buffer_realloc and
11+
/// forbid the use of realloc in the whole library (internally only)
1012
/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'
1113
/// Add new updated demo: sdl3_renderer
1214
/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,

src/nuklear_buffer.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@ NK_LIB void*
1111
nk_malloc(nk_handle unused, void *old,nk_size size)
1212
{
1313
NK_UNUSED(unused);
14-
NK_UNUSED(old);
14+
/*
15+
* Due to historical reasons, Nuklear always calls alloc(user,old,size)
16+
* with the "old" pointer always being NULL. For full explanation, see:
17+
* https://github.com/Immediate-Mode-UI/Nuklear/issues/768
18+
*
19+
* Note that this limitation is only meant for Nuklear's internal code.
20+
* If you're wondering what to pass into nk_allocator's "alloc" field,
21+
* you can still pass realloc there and it will work just fine.
22+
*/
23+
NK_ASSERT(!old && "Nuklear's internal code must never reallocate existing memory !");
1524
return malloc(size);
1625
}
1726
NK_LIB void
@@ -104,15 +113,13 @@ nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
104113
return 0;
105114

106115
buffer_size = b->memory.size;
107-
temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
116+
temp = b->pool.alloc(b->pool.userdata, 0, capacity);
108117
NK_ASSERT(temp);
109118
if (!temp) return 0;
110119

111120
*size = capacity;
112-
if (temp != b->memory.ptr) {
113-
NK_MEMCPY(temp, b->memory.ptr, buffer_size);
114-
b->pool.free(b->pool.userdata, b->memory.ptr);
115-
}
121+
NK_MEMCPY(temp, b->memory.ptr, buffer_size);
122+
b->pool.free(b->pool.userdata, b->memory.ptr);
116123

117124
if (b->size == buffer_size) {
118125
/* no back buffer so just set correct size */

0 commit comments

Comments
 (0)