fda8556a39
This fixes a nasty bug that manifests on windows when building without precompiled headers. util/stringops.h used to silently replace strdup with a macro that's compatible with mem_free(). This header would typically be included everywhere due to PCH, but without it the strdup from libc would sometimes be in scope. On most platforms mem_free() is equivalent to free(), but not on windows, because we have to use _aligned_free() there. Attempting to mem_free() the result of a libc strdup() would segfault in such a configuration. Avoid the footgun by banning strdup() entirely. Maybe redefining libc names isn't such a great idea, who knew?
126 lines
3.3 KiB
C
126 lines
3.3 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#pragma once
|
|
#include "taisei.h"
|
|
|
|
#include "util/macrohax.h"
|
|
|
|
/*
|
|
* NOTE: All allocation functions return zero-initialized memory (except realloc) and never NULL.
|
|
*/
|
|
|
|
void mem_free(void *ptr);
|
|
|
|
void *mem_alloc(size_t size)
|
|
attr_malloc
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(1)
|
|
attr_returns_allocated;
|
|
|
|
void *mem_alloc_array(size_t num_members, size_t size)
|
|
attr_malloc
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(1, 2)
|
|
attr_returns_allocated;
|
|
|
|
void *mem_realloc(void *ptr, size_t size)
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(2)
|
|
attr_returns_allocated;
|
|
|
|
void *mem_alloc_aligned(size_t size, size_t alignment)
|
|
attr_malloc
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(1)
|
|
attr_alloc_align(2)
|
|
attr_returns_allocated;
|
|
|
|
void *mem_alloc_array_aligned(size_t num_members, size_t size, size_t alignment)
|
|
attr_malloc
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(1, 2)
|
|
attr_alloc_align(3)
|
|
attr_returns_allocated;
|
|
|
|
void *mem_dup(const void *src, size_t size)
|
|
attr_malloc
|
|
attr_dealloc(mem_free, 1)
|
|
attr_alloc_size(2)
|
|
attr_returns_allocated;
|
|
|
|
#define memdup mem_dup
|
|
|
|
INLINE attr_returns_allocated attr_nonnull(1)
|
|
char *mem_strdup(const char *str) {
|
|
size_t sz = strlen(str) + 1;
|
|
return memcpy(mem_alloc(sz), str, sz);
|
|
}
|
|
|
|
/*
|
|
* This macro transparently handles allocation of both normal and over-aligned types.
|
|
* The allocation must be free'd with mem_free().
|
|
*
|
|
* You should use it like this:
|
|
*
|
|
* auto x = ALLOC(MyType); // x is a pointer to MyType
|
|
*
|
|
* This style is also allowed:
|
|
*
|
|
* MyType *x = ALLOC(typeof(*x));
|
|
*
|
|
* This style can also be used, but is not recommended:
|
|
*
|
|
* MyType *x = ALLOC(MyType);
|
|
*
|
|
* You can also provide an optional initializer as the second argument, like so:
|
|
*
|
|
* auto x = ALLOC(MyStructType, { .foo = 42, .bar = 69 });
|
|
*/
|
|
#define ALLOC(_type, ...)\
|
|
MACROHAX_OVERLOAD_HASARGS(ALLOC_, __VA_ARGS__)(_type, ##__VA_ARGS__)
|
|
|
|
#define ALLOC_0(_type) \
|
|
(_type *)__builtin_choose_expr( \
|
|
alignof(_type) > alignof(max_align_t), \
|
|
mem_alloc_aligned(sizeof(_type), alignof(_type)), \
|
|
mem_alloc(sizeof(_type)))
|
|
|
|
#define ALLOC_1(_type, ...) ({ \
|
|
auto _alloc_ptr = ALLOC_0(_type); \
|
|
*_alloc_ptr = (_type) __VA_ARGS__; \
|
|
_alloc_ptr; \
|
|
})
|
|
|
|
/*
|
|
* Like ALLOC(), but for array allocations:
|
|
*
|
|
* auto x = ALLOC_ARRAY(10, int); // x is an int*
|
|
*
|
|
* Unlike ALLOC(), this macro does not accept an optional initializer.
|
|
*/
|
|
#define ALLOC_ARRAY(_nmemb, _type) \
|
|
(_type *)__builtin_choose_expr( \
|
|
alignof(_type) > alignof(max_align_t), \
|
|
mem_alloc_array_aligned(_nmemb, sizeof(_type), alignof(_type)), \
|
|
mem_alloc_array(_nmemb, sizeof(_type)))
|
|
|
|
/*
|
|
* Like ALLOC(), but for structs with flexible array members:
|
|
*
|
|
* auto x = ALLOC(MyFlexStruct, 42); // allocates sizeof(MyFlexStruct)+42 bytes
|
|
*
|
|
* Unlike ALLOC(), this macro does not accept an optional initializer.
|
|
*/
|
|
#define ALLOC_FLEX(_type, _extra_size) \
|
|
(_type *)__builtin_choose_expr( \
|
|
alignof(_type) > alignof(max_align_t), \
|
|
mem_alloc_aligned(sizeof(_type) + (_extra_size), alignof(_type)), \
|
|
mem_alloc(sizeof(_type) + (_extra_size)))
|
|
|
|
void mem_install_sdl_callbacks(void);
|