]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
Call cvar callbacks after the cvar is set. Potentially fixes heap corruption.
authorCloudwalk <mazecraze96@gmail.com>
Fri, 26 Jun 2020 16:11:19 +0000 (12:11 -0400)
committerCloudwalk <mazecraze96@gmail.com>
Fri, 26 Jun 2020 16:12:48 +0000 (12:12 -0400)
cvar.c
cvar.h
host_cmd.c
netconn.c
netconn.h
sv_ccmds.c
sv_main.c

diff --git a/cvar.c b/cvar.c
index bcd4763fed5822ee5e65ec7da3bca5f30936d876..1b7bc874609c52f97c9ecf5288163b75fde4668d 100644 (file)
--- 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 e7234b1713b1e6da34a7dce12e2989ddb7eaf8e8..96a5829980a3accb0f84cd216d64ef3760b5edca 100644 (file)
--- 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.
index 3d1029ab9139e0a96492e1e0dd383b16918deb1b..87767e2ff9ca5edab41469176131f45c4ecc41e7 100644 (file)
@@ -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, "");
 }
 
index e4b34ca22d325b576d2d992fea799e935d6a32f0..73f2b5c1970ca47cbf61feae8d3e406021a39f32 100755 (executable)
--- 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, '.'))
index 9e568af178f84c8cfd75b1bf2d87e374fdc7b102..8e3cdab3d5914bc49d19fe5d7bc91ff5d8e66750 100755 (executable)
--- 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
index 015839f4943c6934728055961dacbe20a0f7f0ec..b549005b0658974c50c35796da8c09e858d782f8 100644 (file)
@@ -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)
                {
index f810e5b91a0a9fdf93e0af0736cfc549e2684fff..6d967254dfb788cd6690d6ad4d6e96227dd2b666 100644 (file)
--- 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);
 }
 
 //============================================================================