From 68b1e58a4d60c4988e0b34292a271ea006956fc1 Mon Sep 17 00:00:00 2001 From: Eugene Date: Fri, 7 Jun 2024 23:34:04 +0300 Subject: [PATCH] Allow src and dest buffers to be overlapped in Q_strncpy() for QVM compatibility reasons --- code/qcommon/q_shared.c | 44 +++++++++++++++++++++++++++++++++++------ code/qcommon/q_shared.h | 2 +- code/server/sv_game.c | 2 +- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index a7c69bcc0..ee1975fbb 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1309,24 +1309,56 @@ void Q_strncpyz( char *dest, const char *src, int destsize ) /* ============= Q_strncpy + +allows src and dest to be overlapped for QVM compatibility purposes ============= */ -char *Q_strncpy( char *dest, const char *src, int destsize ) +char *Q_strncpy( char *dest, char *src, int destsize ) { - char *start = dest; + char *s = src, *start = dest; + int src_len; - while ( destsize > 0 && (*dest++ = *src++) != '\0' ) { - --destsize; + while ( *s != '\0' ) + ++s; + src_len = (int)(s - src); + + if ( src_len > destsize ) { + src_len = destsize; + } + destsize -= src_len; + + if ( dest > src && dest < src + src_len ) { + int i; +#ifdef _DEBUG + Com_Printf( S_COLOR_YELLOW "Q_strncpy: overlapped (dest > src) buffers\n" ); +#endif + for ( i = src_len - 1; i >= 0; --i ) { + dest[i] = src[i]; // back overlapping + } + dest += src_len; + } else { +#ifdef _DEBUG + if ( src >= dest && src < dest + src_len ) { + Com_Printf( S_COLOR_YELLOW "Q_strncpy: overlapped (src >= dst) buffers\n" ); +#ifdef _MSC_VER + // __debugbreak(); +#endif + } +#endif + while ( src_len > 0 ) { + *dest++ = *src++; + --src_len; + } } - while ( --destsize > 0 ) { + while ( destsize > 0 ) { *dest++ = '\0'; + --destsize; } return start; } - /* ============= Q_stricmpn diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index cfa260062..c6d3ba1dc 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -842,7 +842,7 @@ void Q_strcat( char *dest, int size, const char *src ); int Q_replace( const char *str1, const char *str2, char *src, int max_len ); char *Q_stradd( char *dst, const char *src ); -char *Q_strncpy( char *dest, const char *src, int destsize ); +char *Q_strncpy( char *dest, char *src, int destsize ); // strlen that discounts Quake color sequences int Q_PrintStrlen( const char *string ); diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 290947126..95eff21c3 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -487,7 +487,7 @@ static intptr_t SV_GameSystemCalls( intptr_t *args ) { return 0; case G_GET_ENTITY_TOKEN: { - const char *s = COM_Parse( &sv.entityParsePoint ); + char *s = (char*)COM_Parse( &sv.entityParsePoint ); VM_CHECKBOUNDS( gvm, args[1], args[2] ); //Q_strncpyz( VMA(1), s, args[2] ); // we can't use our optimized Q_strncpyz() function