diff --git a/code/botlib/be_aas_bspq3.c b/code/botlib/be_aas_bspq3.c index 34862bcbe4..c6a8b1efc4 100644 --- a/code/botlib/be_aas_bspq3.c +++ b/code/botlib/be_aas_bspq3.c @@ -286,8 +286,7 @@ int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) { if (!strcmp(epair->key, key)) { - strncpy(value, epair->value, size-1); - value[size-1] = '\0'; + Q_strncpyz(value, epair->value, size); return qtrue; } //end if } //end for diff --git a/code/botlib/be_ai_char.c b/code/botlib/be_ai_char.c index 4adb28124f..048d13f3f3 100644 --- a/code/botlib/be_ai_char.c +++ b/code/botlib/be_ai_char.c @@ -758,8 +758,7 @@ void Characteristic_String(int character, int index, char *buf, int size) //an integer will be converted to a float if (ch->c[index].type == CT_STRING) { - strncpy(buf, ch->c[index].value.string, size-1); - buf[size-1] = '\0'; + Q_strncpyz(buf, ch->c[index].value.string, size); } //end if else { diff --git a/code/botlib/be_ai_chat.c b/code/botlib/be_ai_chat.c index abbcdc09a1..e0f0de75f3 100644 --- a/code/botlib/be_ai_chat.c +++ b/code/botlib/be_ai_chat.c @@ -1499,8 +1499,7 @@ void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size) if (match->variables[variable].length < size) size = match->variables[variable].length+1; assert( match->variables[variable].offset >= 0 ); - strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1); - buf[size-1] = '\0'; + Q_strncpyz(buf, &match->string[ (int) match->variables[variable].offset], size); } //end if else { @@ -2846,8 +2845,7 @@ void BotGetChatMessage(int chatstate, char *buf, int size) if (!cs) return; BotRemoveTildes(cs->chatmessage); - strncpy(buf, cs->chatmessage, size-1); - buf[size-1] = '\0'; + Q_strncpyz(buf, cs->chatmessage, size); //clear the chat message from the state strcpy(cs->chatmessage, ""); } //end of the function BotGetChatMessage @@ -2883,9 +2881,7 @@ void BotSetChatName(int chatstate, char *name, int client) cs = BotChatStateFromHandle(chatstate); if (!cs) return; cs->client = client; - Com_Memset(cs->name, 0, sizeof(cs->name)); - strncpy(cs->name, name, sizeof(cs->name)-1); - cs->name[sizeof(cs->name)-1] = '\0'; + Q_strncpyz(cs->name, name, sizeof(cs->name)); } //end of the function BotSetChatName //=========================================================================== // diff --git a/code/botlib/be_interface.c b/code/botlib/be_interface.c index eb0efb9518..ffff762845 100644 --- a/code/botlib/be_interface.c +++ b/code/botlib/be_interface.c @@ -235,8 +235,7 @@ int Export_BotLibVarGet(const char *var_name, char *value, int size) char *varvalue; varvalue = LibVarGetString(var_name); - strncpy(value, varvalue, size-1); - value[size-1] = '\0'; + Q_strncpyz(value, varvalue, size); return BLERR_NOERROR; } //end of the function Export_BotLibVarGet //=========================================================================== diff --git a/code/botlib/l_struct.c b/code/botlib/l_struct.c index 0d5d6b01e1..14dc116972 100644 --- a/code/botlib/l_struct.c +++ b/code/botlib/l_struct.c @@ -221,9 +221,7 @@ int ReadString(source_t *source, fielddef_t *fd, void *p) //remove the double quotes StripDoubleQuotes(token.string); //copy the string - strncpy((char *) p, token.string, MAX_STRINGFIELD-1); - //make sure the string is closed with a zero - ((char *)p)[MAX_STRINGFIELD-1] = '\0'; + Q_strncpyz((char *) p, token.string, MAX_STRINGFIELD); // return 1; } //end of the function ReadString diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c index c8c54fcd68..5829e8f391 100644 --- a/code/cgame/cg_servercmds.c +++ b/code/cgame/cg_servercmds.c @@ -241,26 +241,36 @@ void CG_ShaderStateChanged(void) { char timeOffset[16]; const char *o; char *n,*t; + int length; o = CG_ConfigString( CS_SHADERSTATE ); while (o && *o) { n = strstr(o, "="); if (n && *n) { - strncpy(originalShader, o, n-o); - originalShader[n-o] = 0; + length = n-o+1; + if (length > sizeof(originalShader)) { + length = sizeof(originalShader); + } + Q_strncpyz(originalShader, o, length); n++; t = strstr(n, ":"); if (t && *t) { - strncpy(newShader, n, t-n); - newShader[t-n] = 0; + length = t-n+1; + if (length > sizeof(newShader)) { + length = sizeof(newShader); + } + Q_strncpyz(newShader, n, length); } else { break; } t++; o = strstr(t, "@"); if (o) { - strncpy(timeOffset, t, o-t); - timeOffset[o-t] = 0; + length = o-t+1; + if (length > sizeof(timeOffset)) { + length = sizeof(timeOffset); + } + Q_strncpyz(timeOffset, t, length); o++; trap_R_RemapShader( originalShader, newShader, timeOffset ); } diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm index 0874b479d9..eb15a60202 100644 --- a/code/cgame/cg_syscalls.asm +++ b/code/cgame/cg_syscalls.asm @@ -94,6 +94,7 @@ equ trap_FS_Seek -90 equ memset -101 equ memcpy -102 equ strncpy -103 +equ Q_strncpy -103 ; alternate name equ sin -104 equ cos -105 equ atan2 -106 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 613d084209..09223fc3a4 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -618,7 +618,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { Com_Memcpy( VMA(1), VMA(2), args[3] ); return 0; case CG_STRNCPY: - strncpy( VMA(1), VMA(2), args[3] ); + Q_strncpy( VMA(1), VMA(2), args[3] ); return args[1]; case CG_SIN: return FloatAsInt( sin( VMF(1) ) ); diff --git a/code/client/cl_ui.c b/code/client/cl_ui.c index 714364847f..e433cea6f5 100644 --- a/code/client/cl_ui.c +++ b/code/client/cl_ui.c @@ -1005,7 +1005,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) { return 0; case UI_STRNCPY: - strncpy( VMA(1), VMA(2), args[3] ); + Q_strncpy( VMA(1), VMA(2), args[3] ); return args[1]; case UI_SIN: diff --git a/code/game/ai_chat.c b/code/game/ai_chat.c index a65875ff5e..0e50a630d4 100644 --- a/code/game/ai_chat.c +++ b/code/game/ai_chat.c @@ -237,8 +237,7 @@ char *BotMapTitle(void) { trap_GetServerinfo(info, sizeof(info)); - strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1); - mapname[sizeof(mapname)-1] = '\0'; + Q_strncpyz(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)); return mapname; } diff --git a/code/game/ai_cmd.c b/code/game/ai_cmd.c index 2944fb06d3..cb69174e88 100644 --- a/code/game/ai_cmd.c +++ b/code/game/ai_cmd.c @@ -1105,8 +1105,7 @@ void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) { //get the sub team name trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate)); //set the sub team name - strncpy(bs->subteam, teammate, 32); - bs->subteam[31] = '\0'; + Q_strncpyz(bs->subteam, teammate, sizeof(bs->subteam)); // trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL); @@ -1297,8 +1296,7 @@ void BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) { if (match->subtype & ST_I) { //get the team mate that will be the team leader trap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate)); - strncpy(bs->teamleader, teammate, sizeof(bs->teamleader)); - bs->teamleader[sizeof(bs->teamleader)-1] = '\0'; + Q_strncpyz(bs->teamleader, teammate, sizeof(bs->teamleader)); } //chats for someone else else { diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c index 3ecaccb7db..eb9b5850e3 100644 --- a/code/game/ai_dmq3.c +++ b/code/game/ai_dmq3.c @@ -1397,8 +1397,7 @@ char *ClientName(int client, char *name, int size) { return "[client out of range]"; } trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); - strncpy(name, Info_ValueForKey(buf, "n"), size-1); - name[size-1] = '\0'; + Q_strncpyz(name, Info_ValueForKey(buf, "n"), size); Q_CleanStr( name ); return name; } @@ -1416,8 +1415,7 @@ char *ClientSkin(int client, char *skin, int size) { return "[client out of range]"; } trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); - strncpy(skin, Info_ValueForKey(buf, "model"), size-1); - skin[size-1] = '\0'; + Q_strncpyz(skin, Info_ValueForKey(buf, "model"), size); return skin; } @@ -1520,8 +1518,7 @@ char *EasyClientName(int client, char *buf, int size) { memmove(ptr, ptr+1, strlen(ptr + 1)+1); } } - strncpy(buf, name, size-1); - buf[size-1] = '\0'; + Q_strncpyz(buf, name, size); return buf; } @@ -3692,8 +3689,7 @@ void BotMapScripts(bot_state_t *bs) { trap_GetServerinfo(info, sizeof(info)); - strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1); - mapname[sizeof(mapname)-1] = '\0'; + Q_strncpyz(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)); if (!Q_stricmp(mapname, "q3tourney6") || !Q_stricmp(mapname, "q3tourney6_ctf") || !Q_stricmp(mapname, "mpq3tourney6")) { vec3_t mins = {694, 200, 480}, maxs = {968, 472, 680}; diff --git a/code/game/ai_team.c b/code/game/ai_team.c index 78e25b0c05..fba03f2202 100644 --- a/code/game/ai_team.c +++ b/code/game/ai_team.c @@ -1956,8 +1956,7 @@ void BotTeamAI(bot_state_t *bs) { trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER); ClientName(bs->client, netname, sizeof(netname)); - strncpy(bs->teamleader, netname, sizeof(bs->teamleader)); - bs->teamleader[sizeof(bs->teamleader)-1] = '\0'; + Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader)); bs->becometeamleader_time = 0; } return; diff --git a/code/game/g_syscalls.asm b/code/game/g_syscalls.asm index 6fdb869051..d4ad0de77f 100644 --- a/code/game/g_syscalls.asm +++ b/code/game/g_syscalls.asm @@ -50,6 +50,7 @@ equ trap_FS_Seek -46 equ memset -101 equ memcpy -102 equ strncpy -103 +equ Q_strncpy -103 ; alternate name equ sin -104 equ cos -105 equ atan2 -106 diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index e845c28393..2669521aaa 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -802,6 +802,31 @@ int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap) } #endif +#ifndef Q3_VM +/* +============= +Q_strncpy + +strncpy that allows overlapping dest and src + +QVMs uses the strncpy syscall to call this +============= +*/ +char *Q_strncpy( char *dest, const char *src, int destsize ) { + char *start = dest; + + while ( destsize > 0 && (*dest++ = *src++) != '\0' ) { + --destsize; + } + + while ( --destsize > 0 ) { + *dest++ = '\0'; + } + + return start; +} +#endif + /* ============= Q_strncpyz @@ -820,7 +845,7 @@ void Q_strncpyz( char *dest, const char *src, int destsize ) { Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); } - strncpy( dest, src, destsize-1 ); + Q_strncpy( dest, src, destsize-1 ); dest[destsize-1] = 0; } diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index d7ede8af29..f8c97e7e3d 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -827,6 +827,11 @@ char *Q_strlwr( char *s1 ); char *Q_strupr( char *s1 ); const char *Q_stristr( const char *s, const char *find); +#ifndef Q3_VM +// allows overlapping dest and src +char *Q_strncpy( char *dest, const char *src, int destsize ); +#endif + // buffer size safe library replacements void Q_strncpyz( char *dest, const char *src, int destsize ); void Q_strcat( char *dest, int size, const char *src ); diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 161d975e63..7683ea4dd6 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -809,7 +809,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { return 0; case TRAP_STRNCPY: - strncpy( VMA(1), VMA(2), args[3] ); + Q_strncpy( VMA(1), VMA(2), args[3] ); return args[1]; case TRAP_SIN: diff --git a/code/server/sv_rankings.c b/code/server/sv_rankings.c index 9eb2e9b277..63a3887053 100644 --- a/code/server/sv_rankings.c +++ b/code/server/sv_rankings.c @@ -138,8 +138,7 @@ void SV_RankBegin( char *gamekey ) // initialize rankings GRankLogLevel( GRLOG_OFF ); - memset(SV_RankGameKey,0,sizeof(SV_RankGameKey)); - strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1); + Q_strncpyz(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)); init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); s_server_context = init.context; s_rankings_contexts++; diff --git a/code/ui/ui_shared.c b/code/ui/ui_shared.c index 74bc77eb74..e8b3a10e64 100644 --- a/code/ui/ui_shared.c +++ b/code/ui/ui_shared.c @@ -3001,6 +3001,7 @@ void Item_Text_Wrapped_Paint(itemDef_t *item) { char text[1024]; const char *p, *start, *textPtr; char buff[1024]; + int length; int width, height; float x, y; vec4_t color; @@ -3032,11 +3033,14 @@ void Item_Text_Wrapped_Paint(itemDef_t *item) { start = textPtr; p = strchr(textPtr, '\r'); while (p && *p) { - strncpy(buff, start, p-start+1); - buff[p-start] = '\0'; + length = p-start+1; + if (length > sizeof(buff)) { + length = sizeof(buff); + } + Q_strncpyz(buff, start, length); DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle); y += height + 5; - start += p - start + 1; + start += length; p = strchr(p+1, '\r'); } DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle); diff --git a/code/ui/ui_syscalls.asm b/code/ui/ui_syscalls.asm index 6dc352e9a7..a885981452 100644 --- a/code/ui/ui_syscalls.asm +++ b/code/ui/ui_syscalls.asm @@ -92,6 +92,7 @@ equ trap_SetPbClStatus -88 equ memset -101 equ memcpy -102 equ strncpy -103 +equ Q_strncpy -103 ; alternate name equ sin -104 equ cos -105 equ atan2 -106