From 9b260c644ab630a054c579117f72c0635488825a Mon Sep 17 00:00:00 2001 From: cloudwalk Date: Sat, 27 Jun 2020 02:27:18 +0000 Subject: [PATCH] Call cvar callbacks after the cvar is set. Potentially fixes heap corruption. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12735 d7cf8633-e32d-0410-b094-e92efae38249 --- cvar.c | 19 ++++++++----------- cvar.h | 4 ++-- host_cmd.c | 18 +++++++++--------- netconn.c | 4 ++-- netconn.h | 2 +- sv_ccmds.c | 4 ++-- sv_main.c | 9 +++------ 7 files changed, 27 insertions(+), 33 deletions(-) diff --git a/cvar.c b/cvar.c index bcd4763f..1b7bc874 100644 --- a/cvar.c +++ b/cvar.c @@ -375,28 +375,21 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value) { qboolean changed; size_t valuelen; - char new_value[MAX_INPUTLINE]; changed = strcmp(var->string, value) != 0; // LadyHavoc: don't reallocate when there is no change if (!changed) return; - memcpy(new_value,value,MAX_INPUTLINE); - - // Call the function stored in the cvar for bounds checking, cleanup, etc - if (var->callback) - var->callback(new_value); - // LadyHavoc: don't reallocate when the buffer is the same size - valuelen = strlen(new_value); + valuelen = strlen(value); if (!var->string || strlen(var->string) != valuelen) { Z_Free ((char *)var->string); // free the old value string var->string = (char *)Z_Malloc (valuelen + 1); } - memcpy ((char *)var->string, new_value, valuelen + 1); + memcpy ((char *)var->string, value, valuelen + 1); var->value = atof (var->string); var->integer = (int) var->value; if ((var->flags & CVAR_NOTIFY) && changed && sv.active && !sv_disablenotify.integer) @@ -418,6 +411,10 @@ static void Cvar_SetQuick_Internal (cvar_t *var, const char *value) CL_SetInfo(var->name, var->string, true, false, false, false); Cvar_UpdateAutoCvar(var); + + // Call the function stored in the cvar for bounds checking, cleanup, etc + if (var->callback) + var->callback(var); } void Cvar_SetQuick (cvar_t *var, const char *value) @@ -448,7 +445,7 @@ void Cvar_Set(cvar_state_t *cvars, const char *var_name, const char *value) void Cvar_Set_NoCallback(cvar_t *var, const char *value) { - void (*callback_save)(char *) = var->callback; + void (*callback_save)(cvar_t *) = var->callback; var->callback = NULL; Cvar_SetQuick_Internal(var, value); var->callback = callback_save; @@ -481,7 +478,7 @@ void Cvar_SetValue(cvar_state_t *cvars, const char *var_name, float value) Cvar_Set(cvars, var_name, val); } -void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(char *)) +void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *)) { variable->callback = callback; } diff --git a/cvar.h b/cvar.h index e7234b17..96a58299 100644 --- a/cvar.h +++ b/cvar.h @@ -129,7 +129,7 @@ typedef struct cvar_s const char *defstring; - void (*callback)(char *value); + void (*callback)(struct cvar_s *var); qboolean ignore_callback; char **aliases; @@ -180,7 +180,7 @@ void Cvar_MenuOption(cvar_t *variable, int menu, int value[16], const char *name void Cvar_RegisterAlias(cvar_t *variable, const char *alias ); -void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(char *)); +void Cvar_RegisterCallback(cvar_t *variable, void (*callback)(cvar_t *)); /// registers a cvar that already has the name, string, and optionally the /// archive elements set. diff --git a/host_cmd.c b/host_cmd.c index 3d1029ab..87767e2f 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -180,26 +180,26 @@ CL_Color_f cvar_t cl_color = {CVAR_READONLY | CVAR_CLIENT | CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"}; // Ignore the callbacks so this two-to-three way synchronization doesn't cause an infinite loop. -static void CL_Color_c(char *string) +static void CL_Color_c(cvar_t *var) { char vabuf[1024]; - Cvar_Set_NoCallback(&topcolor, va(vabuf, sizeof(vabuf), "%i", ((atoi(string) >> 4) & 15))); - Cvar_Set_NoCallback(&bottomcolor, va(vabuf, sizeof(vabuf), "%i", (atoi(string) & 15))); + Cvar_Set_NoCallback(&topcolor, va(vabuf, sizeof(vabuf), "%i", ((var->integer >> 4) & 15))); + Cvar_Set_NoCallback(&bottomcolor, va(vabuf, sizeof(vabuf), "%i", (var->integer & 15))); } -static void CL_Topcolor_c(char *string) +static void CL_Topcolor_c(cvar_t *var) { char vabuf[1024]; - Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", atoi(string)*16 + bottomcolor.integer)); + Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", var->integer*16 + bottomcolor.integer)); } -static void CL_Bottomcolor_c(char *string) +static void CL_Bottomcolor_c(cvar_t *var) { char vabuf[1024]; - Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", topcolor.integer*16 + atoi(string))); + Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", topcolor.integer*16 + var->integer)); } static void CL_Color_f(cmd_state_t *cmd) @@ -482,12 +482,12 @@ static void CL_Rcon_f(cmd_state_t *cmd) // credit: taken from QuakeWorld } } -static void CL_RCon_ClearPassword_c(char *string) +static void CL_RCon_ClearPassword_c(cvar_t *var) { // whenever rcon_secure is changed to 0, clear rcon_password for // security reasons (prevents a send-rcon-password-as-plaintext // attack based on NQ protocol session takeover and svc_stufftext) - if(atoi(string) <= 0) + if(var->integer <= 0) Cvar_SetQuick(&rcon_password, ""); } diff --git a/netconn.c b/netconn.c index e4b34ca2..73f2b5c1 100755 --- a/netconn.c +++ b/netconn.c @@ -166,12 +166,12 @@ static lhnetaddress_t favorites[MAX_FAVORITESERVERS]; static int nFavorites_idfp = 0; static char favorites_idfp[MAX_FAVORITESERVERS][FP64_SIZE+1]; -void NetConn_UpdateFavorites_c(char *string) +void NetConn_UpdateFavorites_c(cvar_t *var) { const char *p; nFavorites = 0; nFavorites_idfp = 0; - p = string; + p = var->string; while((size_t) nFavorites < sizeof(favorites) / sizeof(*favorites) && COM_ParseToken_Console(&p)) { if(com_token[0] != '[' && strlen(com_token) == FP64_SIZE && !strchr(com_token, '.')) diff --git a/netconn.h b/netconn.h index 9e568af1..8e3cdab3 100755 --- a/netconn.h +++ b/netconn.h @@ -470,7 +470,7 @@ void ServerList_ResetMasks(void); void ServerList_QueryList(qboolean resetcache, qboolean querydp, qboolean queryqw, qboolean consoleoutput); /// called whenever net_slist_favorites changes -void NetConn_UpdateFavorites_c(char *string); +void NetConn_UpdateFavorites_c(cvar_t *var); #endif #define MAX_CHALLENGES 128 diff --git a/sv_ccmds.c b/sv_ccmds.c index 015839f4..b549005b 100644 --- a/sv_ccmds.c +++ b/sv_ccmds.c @@ -163,12 +163,12 @@ static void SV_Restart_f(cmd_state_t *cmd) //=========================================================================== // Disable cheats if sv_cheats is turned off -static void SV_DisableCheats_c(char *value) +static void SV_DisableCheats_c(cvar_t *var) { prvm_prog_t *prog = SVVM_prog; int i = 0; - if (value[0] == '0' && !value[1]) + if (var->value == 0) { while (svs.clients[i].edict) { diff --git a/sv_main.c b/sv_main.c index f810e5b9..6d967254 100644 --- a/sv_main.c +++ b/sv_main.c @@ -414,13 +414,10 @@ prvm_required_field_t sv_reqglobals[] = #undef PRVM_DECLARE_function }; -static void Host_Timescale_c(char *string) +static void Host_Timescale_c(cvar_t *var) { - double value; - value = atof(string); - - if(value < 0.00001 && value != 0) - string[0] = '0', string[1] = 0; + if(var->value < 0.00001 && var->value != 0) + Cvar_SetValueQuick(var, 0); } //============================================================================ -- 2.39.2