src: deprecate strdup(), use mem_strdup() explicitly

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?
This commit is contained in:
Andrei Alexeyev 2024-09-05 06:38:58 +02:00
parent c8a2fb1418
commit fda8556a39
No known key found for this signature in database
GPG key ID: 72D26128040B9690
26 changed files with 50 additions and 47 deletions

View file

@ -220,7 +220,7 @@ static void credits_add(char *data, int time) {
for(c = data; *c; ++c) {
if(*c == '\n') {
buf[i] = 0;
e->data[l] = strdup(buf);
e->data[l] = mem_strdup(buf);
i = 0;
++l;
} else {
@ -229,7 +229,7 @@ static void credits_add(char *data, int time) {
}
buf[i] = 0;
e->data[l] = strdup(buf);
e->data[l] = mem_strdup(buf);
credits.end += time;
}

View file

@ -156,7 +156,7 @@ static DirWatch *dirwatch_get(const char *path, bool create) {
}
dw = ALLOC(typeof(*dw));
dw->path = strdup(path);
dw->path = mem_strdup(path);
dw->wd = wd;
WDRecord *wdrec = NOT_NULL(wdrecord_get(wd, true));
@ -355,7 +355,7 @@ FileWatch *filewatch_watch(const char *syspath) {
auto fw = list_push(&dw->filewatch_list, ALLOC(FileWatch, {
.dw = dw,
.filename = strdup(filename),
.filename = mem_strdup(filename),
}));
SDL_UnlockMutex(FW.modify_mtx);

View file

@ -157,7 +157,7 @@
*
* Example:
*
* #define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
* #define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
*/
#ifndef HT_FUNC_COPY_KEY
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = (src))

View file

@ -21,7 +21,7 @@
#define HT_FUNC_FREE_KEY(key) mem_free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT "p"
@ -41,7 +41,7 @@
#define HT_FUNC_FREE_KEY(key) mem_free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT "p"
@ -62,7 +62,7 @@
#define HT_FUNC_FREE_KEY(key) mem_free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
@ -81,7 +81,7 @@
#define HT_FUNC_FREE_KEY(key) mem_free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
@ -233,7 +233,7 @@
#define HT_FUNC_FREE_KEY(key) mem_free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = mem_strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT "s"

View file

@ -771,7 +771,7 @@ static char *copy_pattern(const char *p) {
return NULL;
}
return strdup(orig);
return mem_strdup(orig);
}
void log_add_filter(LogLevelDiff diff, const char *pmod, const char *pfunc) {

View file

@ -56,6 +56,12 @@ void *mem_dup(const void *src, size_t size)
#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().

View file

@ -22,7 +22,7 @@ MenuEntry *add_menu_entry(MenuData *menu, const char *name, MenuAction action, v
.action = action,
.arg = arg,
.transition = menu->transition,
.name = name ? strdup(name) : NULL,
.name = name ? mem_strdup(name) : NULL,
});
}

View file

@ -313,7 +313,7 @@ static int bind_addvalue(OptionBinding *b, char *val) {
}
b->values = mem_realloc(b->values, (1 + b->valrange_max) * sizeof(char*));
b->values[b->valrange_max] = strdup(val);
b->values[b->valrange_max] = mem_strdup(val);
return b->valrange_max;
}
@ -965,7 +965,7 @@ static MenuData* create_options_menu_gamepad(MenuData *parent) {
m->end = destroy_options_menu_gamepad;
OptionsMenuContext *ctx = m->context;
ctx->data = strdup(config_get_str(CONFIG_GAMEPAD_DEVICE));
ctx->data = mem_strdup(config_get_str(CONFIG_GAMEPAD_DEVICE));
ctx->draw_overlay = draw_gamepad_options_overlay;
ctx->gamepad_testmode.allowed = true;

View file

@ -400,7 +400,7 @@ static int fill_replayview_menu(MenuData *m) {
auto ictx = ALLOC(ReplayviewItemContext, {
.replay = rpy,
.replayname = strdup(filename),
.replayname = mem_strdup(filename),
});
add_menu_entry(m, " ", replayview_run, ictx)->transition = /*rpy->numstages < 2 ? TransFadeBlack :*/ NULL;

View file

@ -195,7 +195,7 @@ char *pixmap_source_path(const char *prefix, const char *path) {
strcpy(base_path + strlen(prefix), path);
if(pixmap_check_filename(base_path) && vfs_query(base_path).exists) {
return strdup(base_path);
return mem_strdup(base_path);
}
char *dot = strrchr(base_path, '.');

View file

@ -218,7 +218,7 @@ static spvc_result write_glsl_attribs(spvc_compiler compiler, ShaderSource *out)
log_debug("[%i] %s\t\tid=%i\t\tbase_type_id=%i\t\ttype_id=%i\t\tlocation=%i", i, res->name, res->id, res->base_type_id, res->type_id, location);
attrs[i].name = strdup(res->name);
attrs[i].name = mem_strdup(res->name);
attrs[i].location = location;
}
@ -284,7 +284,7 @@ bool _spirv_decompile(const ShaderSource *in, ShaderSource *out, const SPIRVDeco
assume(code != NULL);
out->content = strdup(code);
out->content = mem_strdup(code);
out->content_size = strlen(code) + 1;
out->stage = in->stage;
out->lang = *options->lang;

View file

@ -110,7 +110,7 @@ ShaderObject *gl33_shader_object_compile(ShaderSource *source) {
for(uint i = 0; i < nattribs; ++i) {
GLSLAttribute *a = source->meta.glsl.attributes + i;
shobj->attribs[i].name = strdup(a->name);
shobj->attribs[i].name = mem_strdup(a->name);
shobj->attribs[i].location = a->location;
}
} else {

View file

@ -573,7 +573,7 @@ static void register_watched_path(InternalResource *ires, const char *vfspath, F
free_slot = dynarray_append(&ires->watched_paths, {});
}
free_slot->vfs_path = strdup(vfspath);
free_slot->vfs_path = mem_strdup(vfspath);
free_slot->watch = w;
done:
@ -816,7 +816,7 @@ struct valfunc_arg {
static void *valfunc_begin_load_resource(void *varg) {
struct valfunc_arg *arg = varg;
auto ires = ires_alloc(arg->type);
ires->name = strdup(NOT_NULL(arg->name));
ires->name = mem_strdup(NOT_NULL(arg->name));
ires->refcount.value = 1;
return ires;
}
@ -1702,7 +1702,7 @@ void res_util_strip_ext(char *path) {
char *res_util_basename(const char *prefix, const char *path) {
assert(strstartswith(path, prefix));
char *out = strdup(path + strlen(prefix));
char *out = mem_strdup(path + strlen(prefix));
res_util_strip_ext(out);
return out;

View file

@ -43,7 +43,7 @@ static void load_sprite_stage1(ResourceLoadState *st) {
auto state = ALLOC(struct sprite_load_state, { .spr = spr });
if(texture_res_handler.procs.check(st->path)) {
state->texture_name = strdup(st->name);
state->texture_name = mem_strdup(st->name);
res_load_dependency(st, RES_TEXTURE, state->texture_name);
res_load_continue_after_dependencies(st, load_sprite_stage2, state);
return;
@ -88,7 +88,7 @@ static void load_sprite_stage1(ResourceLoadState *st) {
}
if(!state->texture_name) {
state->texture_name = strdup(st->name);
state->texture_name = mem_strdup(st->name);
log_info("%s: inferred texture name from sprite name", state->texture_name);
}

View file

@ -669,7 +669,7 @@ void texture_loader_stage1(ResourceLoadState *st) {
return;
}
} else {
ld->src_paths.main = strdup(st->path);
ld->src_paths.main = mem_strdup(st->path);
}

View file

@ -31,8 +31,8 @@ static void add_stage(
.type = type,
.spell = spell,
.difficulty = diff,
.title = title ? strdup(title) : NULL,
.subtitle = subtitle ? strdup(subtitle) : NULL,
.title = title ? mem_strdup(title) : NULL,
.subtitle = subtitle ? mem_strdup(subtitle) : NULL,
});
}

View file

@ -96,4 +96,8 @@ INLINE void *libc_realloc(void *ptr, size_t size) { return realloc(ptr, size); }
attr_deprecated("Use the memory.h API instead")
void *realloc(void *ptr, size_t size);
#undef strdup
attr_deprecated("Use mem_strdup from memory.h instead")
char *strdup(const char *s);
PRAGMA(GCC diagnostic pop)

View file

@ -87,7 +87,7 @@ bool parse_keyvalue_file_cb(const char *filename, KVCallback callback, void *dat
static bool kvcallback_hashtable(const char *key, const char *val, void *data) {
ht_str2ptr_t *ht = data;
ht_set(ht, key, strdup(val));
ht_set(ht, key, mem_strdup(val));
return true;
}

View file

@ -51,7 +51,7 @@ bool strstartswith_any(const char *s, const char **earray) {
void stralloc(char **dest, const char *src) {
mem_free(*dest);
*dest = src ? strdup(src) : NULL;
*dest = src ? mem_strdup(src) : NULL;
}
char* strjoin(const char *first, ...) {
@ -124,7 +124,7 @@ char* strftimealloc(const char *fmt, const struct tm *timeinfo) {
char str[sz_allocated];
if(strftime(str, sz_allocated, fmt, timeinfo)) {
return strdup(str);
return mem_strdup(str);
}
sz_allocated *= 2;
@ -133,7 +133,7 @@ char* strftimealloc(const char *fmt, const struct tm *timeinfo) {
char* strappend(char **dst, const char *src) {
if(!*dst) {
return *dst = strdup(src);
return *dst = mem_strdup(src);
}
*dst = mem_realloc(*dst, strlen(*dst) + strlen(src) + 1);

View file

@ -25,13 +25,6 @@
#undef strlcpy
#define strlcpy SDL_strlcpy
#undef strdup
#define strdup _ts_strdup
INLINE attr_returns_allocated attr_nonnull(1) char *strdup(const char *str) {
size_t sz = strlen(str) + 1;
return memcpy(mem_alloc(sz), str, sz);
}
#ifndef TAISEI_BUILDCONF_HAVE_STRTOK_R
#undef strtok_r
#define strtok_r _ts_strtok_r

View file

@ -61,7 +61,7 @@ char *vfs_path_normalize(const char *path, char *out) {
}
char *vfs_path_normalize_alloc(const char *path) {
return vfs_path_normalize(path, strdup(path));
return vfs_path_normalize(path, mem_strdup(path));
}
char *vfs_path_normalize_inplace(char *path) {
@ -145,5 +145,5 @@ char *vfs_syspath_normalize_inplace(char *path) {
char *vfs_syspath_join_alloc(const char *parent, const char *child) {
char buf[strlen(parent) + strlen(child) + 2];
vfs_syspath_join(buf, sizeof(buf), parent, child);
return strdup(buf);
return mem_strdup(buf);
}

View file

@ -281,7 +281,7 @@ char** vfs_dir_list_sorted(const char *path, size_t *out_size, int (*compare)(co
continue;
}
dynarray_append(&results, strdup(e));
dynarray_append(&results, mem_strdup(e));
}
vfs_dir_close(dir);

View file

@ -95,7 +95,7 @@ static char *vfs_syspath_repr(VFSNode *node) {
}
static char *vfs_syspath_syspath(VFSNode *node) {
char *p = strdup(VFS_NODE_CAST(VFSSysPathNode, node)->path);
char *p = mem_strdup(VFS_NODE_CAST(VFSSysPathNode, node)->path);
vfs_syspath_normalize_inplace(p);
return p;
}
@ -186,5 +186,5 @@ static VFSNode *vfs_syspath_create_internal(char *path) {
}
VFSNode *vfs_syspath_create(const char *path) {
return vfs_syspath_create_internal(strdup(path));
return vfs_syspath_create_internal(mem_strdup(path));
}

View file

@ -187,7 +187,7 @@ static char* vfs_syspath_repr(VFSNode *node) {
static char* vfs_syspath_syspath(VFSNode *node) {
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
char *p = strdup(pnode->path);
char *p = mem_strdup(pnode->path);
vfs_syspath_normalize_inplace(p);
return p;
}
@ -322,5 +322,5 @@ static VFSNode *vfs_syspath_create_internal(char *path) {
}
VFSNode *vfs_syspath_create(const char *path) {
return vfs_syspath_create_internal(strdup(path));
return vfs_syspath_create_internal(mem_strdup(path));
}

View file

@ -114,7 +114,7 @@ static bool vfs_vdir_mkdir(VFSNode *node, const char *subdir) {
}
static char *vfs_vdir_repr(VFSNode *node) {
return strdup("virtual directory");
return mem_strdup("virtual directory");
}
VFS_NODE_FUNCS(VFSVDirNode, {

View file

@ -228,7 +228,7 @@ const char *vfs_zipfile_iter_shared(VFSZipFileIterData *idata, VFSZipFileTLS *tl
// strip the trailing slash
mem_free(idata->allocated);
idata->allocated = strdup(p);
idata->allocated = mem_strdup(p);
*strchr(idata->allocated, '/') = 0;
r = idata->allocated;
} else {