diff options
author | Tim Angus <tim@ngus.net> | 2011-04-23 22:38:25 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:18:07 +0000 |
commit | 06006eb6930de74c577c87daf6a0f7917e22d578 (patch) | |
tree | 8caec25df040a3f3eddc99b593e51d993b9be1be /src/qcommon | |
parent | 98438cc3e7d32312bb52b413c12698b67b8cfeb0 (diff) |
* Merge ioq3-r1946
Diffstat (limited to 'src/qcommon')
-rw-r--r-- | src/qcommon/cmd.c | 77 | ||||
-rw-r--r-- | src/qcommon/common.c | 266 | ||||
-rw-r--r-- | src/qcommon/cvar.c | 53 | ||||
-rw-r--r-- | src/qcommon/files.c | 298 | ||||
-rw-r--r-- | src/qcommon/msg.c | 8 | ||||
-rw-r--r-- | src/qcommon/net_ip.c | 107 | ||||
-rw-r--r-- | src/qcommon/q_platform.h | 7 | ||||
-rw-r--r-- | src/qcommon/q_shared.c | 63 | ||||
-rw-r--r-- | src/qcommon/q_shared.h | 35 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 45 | ||||
-rw-r--r-- | src/qcommon/unzip.c | 21 | ||||
-rw-r--r-- | src/qcommon/vm.c | 14 | ||||
-rw-r--r-- | src/qcommon/vm_local.h | 2 | ||||
-rw-r--r-- | src/qcommon/vm_powerpc.c | 6 | ||||
-rw-r--r-- | src/qcommon/vm_powerpc_asm.c | 7 | ||||
-rw-r--r-- | src/qcommon/vm_sparc.c | 6 | ||||
-rw-r--r-- | src/qcommon/vm_x86.c | 33 | ||||
-rw-r--r-- | src/qcommon/vm_x86_64.c | 32 | ||||
-rw-r--r-- | src/qcommon/vm_x86_64_assembler.c | 29 |
19 files changed, 683 insertions, 426 deletions
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c index 7ce50ccc..8ea761e8 100644 --- a/src/qcommon/cmd.c +++ b/src/qcommon/cmd.c @@ -470,6 +470,31 @@ char *Cmd_Cmd(void) } /* + Replace command separators with space to prevent interpretation + This is a hack to protect buggy qvms + https://bugzilla.icculus.org/show_bug.cgi?id=3593 + https://bugzilla.icculus.org/show_bug.cgi?id=4769 +*/ + +void Cmd_Args_Sanitize(void) +{ + int i; + + for(i = 1; i < cmd.argc; i++) + { + char *c = cmd.argv[i]; + + if(strlen(c) > MAX_CVAR_VALUE_STRING - 1) + c[MAX_CVAR_VALUE_STRING - 1] = '\0'; + + while ((c = strpbrk(c, "\n\r;"))) { + *c = ' '; + ++c; + } + } +} + +/* ============ Cmd_TokenizeString @@ -604,6 +629,20 @@ void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ) { /* ============ +Cmd_FindCommand +============ +*/ +cmd_function_t *Cmd_FindCommand( const char *cmd_name ) +{ + cmd_function_t *cmd; + for( cmd = cmd_functions; cmd; cmd = cmd->next ) + if( !Q_stricmp( cmd_name, cmd->name ) ) + return cmd; + return NULL; +} + +/* +============ Cmd_AddCommand ============ */ @@ -611,14 +650,12 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) { cmd_function_t *cmd; // fail if the command already exists - for ( cmd = cmd_functions ; cmd ; cmd=cmd->next ) { - if ( !strcmp( cmd_name, cmd->name ) ) { - // allow completion-only commands to be silently doubled - if ( function != NULL ) { - Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); - } - return; - } + if( Cmd_FindCommand( cmd_name ) ) + { + // allow completion-only commands to be silently doubled + if( function != NULL ) + Com_Printf( "Cmd_AddCommand: %s already defined\n", cmd_name ); + return; } // use a small malloc to avoid zone fragmentation @@ -672,6 +709,28 @@ void Cmd_RemoveCommand( const char *cmd_name ) { } } +/* +============ +Cmd_RemoveCommandSafe + +Only remove commands with no associated function +============ +*/ +void Cmd_RemoveCommandSafe( const char *cmd_name ) +{ + cmd_function_t *cmd = Cmd_FindCommand( cmd_name ); + + if( !cmd ) + return; + if( cmd->function ) + { + Com_Error( ERR_DROP, "Restricted source tried to remove " + "system command \"%s\"\n", cmd_name ); + return; + } + + Cmd_RemoveCommand( cmd_name ); +} /* ============ @@ -798,7 +857,7 @@ Cmd_CompleteCfgName */ void Cmd_CompleteCfgName( char *args, int argNum ) { if( argNum == 2 ) { - Field_CompleteFilename( "", "cfg", qfalse ); + Field_CompleteFilename( "", "cfg", qfalse, qtrue ); } } diff --git a/src/qcommon/common.c b/src/qcommon/common.c index 38902e92..1cf54d07 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -51,6 +51,7 @@ jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame FILE *debuglogfile; +static fileHandle_t pipefile; static fileHandle_t logfile; fileHandle_t com_journalFile; // events are written here fileHandle_t com_journalDataFile; // config files are written here @@ -60,7 +61,6 @@ cvar_t *com_developer; cvar_t *com_dedicated; cvar_t *com_timescale; cvar_t *com_fixedtime; -cvar_t *com_dropsim; // 0.0 to 1.0, simulated packet drops cvar_t *com_journal; cvar_t *com_maxfps; cvar_t *com_altivec; @@ -68,6 +68,7 @@ cvar_t *com_timedemo; cvar_t *com_sv_running; cvar_t *com_cl_running; cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print +cvar_t *com_pipefile; cvar_t *com_showtrace; cvar_t *com_version; cvar_t *com_blood; @@ -83,6 +84,8 @@ cvar_t *com_maxfpsUnfocused; cvar_t *com_minimized; cvar_t *com_maxfpsMinimized; cvar_t *com_abnormalExit; +cvar_t *com_homepath; +cvar_t *com_busyWait; // com_speeds times int time_game; @@ -90,7 +93,6 @@ int time_frontend; // renderer frontend time int time_backend; // renderer backend time int com_frameTime; -int com_frameMsec; int com_frameNumber; qboolean com_errorEntered = qfalse; @@ -289,9 +291,9 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { Cvar_Set("com_errorMessage", com_errorMessage); if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT) { + VM_Forced_Unload_Start(); SV_Shutdown( "Server disconnected" ); CL_Disconnect( qtrue ); - VM_Forced_Unload_Start(); CL_FlushMemory( ); VM_Forced_Unload_Done(); // make sure we can get at our local stuff @@ -300,32 +302,36 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { longjmp (abortframe, -1); } else if (code == ERR_DROP) { Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage); + VM_Forced_Unload_Start(); SV_Shutdown (va("Server crashed: %s", com_errorMessage)); CL_Disconnect( qtrue ); - VM_Forced_Unload_Start(); CL_FlushMemory( ); VM_Forced_Unload_Done(); FS_PureServerSetLoadedPaks("", ""); com_errorEntered = qfalse; longjmp (abortframe, -1); } else if ( code == ERR_NEED_CD ) { + VM_Forced_Unload_Start(); SV_Shutdown( "Server didn't have CD" ); if ( com_cl_running && com_cl_running->integer ) { CL_Disconnect( qtrue ); - VM_Forced_Unload_Start(); CL_FlushMemory( ); VM_Forced_Unload_Done(); CL_CDDialog(); } else { Com_Printf("Server didn't have CD\n" ); + VM_Forced_Unload_Done(); } + FS_PureServerSetLoadedPaks("", ""); com_errorEntered = qfalse; longjmp (abortframe, -1); } else { + VM_Forced_Unload_Start(); CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage)); SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage)); + VM_Forced_Unload_Done(); } Com_Shutdown (); @@ -446,7 +452,6 @@ be after execing the config and default. void Com_StartupVariable( const char *match ) { int i; char *s; - cvar_t *cv; for (i=0 ; i < com_numConsoleLines ; i++) { Cmd_TokenizeString( com_consoleLines[i] ); @@ -455,11 +460,13 @@ void Com_StartupVariable( const char *match ) { } s = Cmd_Argv(1); - if ( !match || !strcmp( s, match ) ) { - Cvar_Set( s, Cmd_Argv(2) ); - cv = Cvar_Get( s, "", 0 ); - cv->flags |= CVAR_USER_CREATED; -// com_consoleLines[i] = 0; + + if(!match || !strcmp(s, match)) + { + if(Cvar_Flags(s) == CVAR_NONEXISTENT) + Cvar_Get(s, Cmd_Argv(2), CVAR_USER_CREATED); + else + Cvar_Set(s, Cmd_Argv(2)); } } } @@ -504,8 +511,8 @@ qboolean Com_AddStartupCommands( void ) { //============================================================================ void Info_Print( const char *s ) { - char key[512]; - char value[512]; + char key[BIG_INFO_KEY]; + char value[BIG_INFO_VALUE]; char *o; int l; @@ -525,7 +532,7 @@ void Info_Print( const char *s ) { } else *o = 0; - Com_Printf ("%s", key); + Com_Printf ("%s ", key); if (!*s) { @@ -1946,7 +1953,6 @@ EVENT LOOP static sysEvent_t eventQueue[ MAX_QUEUED_EVENTS ]; static int eventHead = 0; static int eventTail = 0; -static byte sys_packetReceived[ MAX_MSGLEN ]; /* ================ @@ -1999,8 +2005,6 @@ sysEvent_t Com_GetSystemEvent( void ) { sysEvent_t ev; char *s; - msg_t netmsg; - netadr_t adr; // return if we have data if ( eventHead > eventTail ) @@ -2022,21 +2026,6 @@ sysEvent_t Com_GetSystemEvent( void ) Com_QueueEvent( 0, SE_CONSOLE, 0, 0, len, b ); } - // check for network packets - MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); - if ( Sys_GetPacket ( &adr, &netmsg ) ) - { - netadr_t *buf; - int len; - - // copy out to a seperate buffer for qeueing - len = sizeof( netadr_t ) + netmsg.cursize; - buf = Z_Malloc( len ); - *buf = adr; - memcpy( buf+1, netmsg.data, netmsg.cursize ); - Com_QueueEvent( 0, SE_PACKET, 0, 0, len, buf ); - } - // return if we have data if ( eventHead > eventTail ) { @@ -2196,7 +2185,6 @@ int Com_EventLoop( void ) { MSG_Init( &buf, bufData, sizeof( bufData ) ); while ( 1 ) { - NET_FlushPacketQueue(); ev = Com_GetEvent(); // if no more events are available @@ -2217,57 +2205,26 @@ int Com_EventLoop( void ) { } - switch ( ev.evType ) { - default: - Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType ); - break; - case SE_NONE: - break; - case SE_KEY: - CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime ); + switch(ev.evType) + { + case SE_KEY: + CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime ); break; - case SE_CHAR: - CL_CharEvent( ev.evValue ); + case SE_CHAR: + CL_CharEvent( ev.evValue ); break; - case SE_MOUSE: - CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime ); + case SE_MOUSE: + CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime ); break; - case SE_JOYSTICK_AXIS: - CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime ); + case SE_JOYSTICK_AXIS: + CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime ); break; - case SE_CONSOLE: - Cbuf_AddText( (char *)ev.evPtr ); - Cbuf_AddText( "\n" ); + case SE_CONSOLE: + Cbuf_AddText( (char *)ev.evPtr ); + Cbuf_AddText( "\n" ); break; - case SE_PACKET: - // this cvar allows simulation of connections that - // drop a lot of packets. Note that loopback connections - // don't go through here at all. - if ( com_dropsim->value > 0 ) { - static int seed; - - if ( Q_random( &seed ) < com_dropsim->value ) { - break; // drop this packet - } - } - - evFrom = *(netadr_t *)ev.evPtr; - buf.cursize = ev.evPtrLength - sizeof( evFrom ); - - // we must copy the contents of the message out, because - // the event buffers are only large enough to hold the - // exact payload, but channel messages need to be large - // enough to hold fragment reassembly - if ( (unsigned)buf.cursize > buf.maxsize ) { - Com_Printf("Com_EventLoop: oversize packet\n"); - continue; - } - Com_Memcpy( buf.data, (byte *)((netadr_t *)ev.evPtr + 1), buf.cursize ); - if ( com_sv_running->integer ) { - Com_RunAndTimeServerPacket( &evFrom, &buf ); - } else { - CL_PacketEvent( evFrom, &buf ); - } + default: + Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType ); break; } @@ -2518,7 +2475,6 @@ void Com_Init( char *commandLine ) { // Clear queues Com_Memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) ); - Com_Memset( &sys_packetReceived[ 0 ], 0, MAX_MSGLEN * sizeof( byte ) ); // initialize the weak pseudo-random number generator for use later. Com_InitRand(); @@ -2543,11 +2499,14 @@ void Com_Init( char *commandLine ) { Cmd_Init (); // get the developer cvar set as early as possible - Com_StartupVariable( "developer" ); + com_developer = Cvar_Get("developer", "0", CVAR_TEMP); // done early so bind command exists CL_InitKeyCommands(); + com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT); + + // Com_StartupVariable( FS_InitFilesystem (); Com_InitJournaling(); @@ -2593,13 +2552,11 @@ void Com_Init( char *commandLine ) { com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE); com_blood = Cvar_Get ("com_blood", "1", CVAR_ARCHIVE); - com_developer = Cvar_Get ("developer", "0", CVAR_TEMP ); com_logfile = Cvar_Get ("logfile", "0", CVAR_TEMP ); com_timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT | CVAR_SYSTEMINFO ); com_fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT); com_showtrace = Cvar_Get ("com_showtrace", "0", CVAR_CHEAT); - com_dropsim = Cvar_Get ("com_dropsim", "0", CVAR_CHEAT); com_speeds = Cvar_Get ("com_speeds", "0", 0); com_timedemo = Cvar_Get ("timedemo", "0", CVAR_CHEAT); com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT); @@ -2618,6 +2575,7 @@ void Com_Init( char *commandLine ) { com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM ); com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE ); com_abnormalExit = Cvar_Get( "com_abnormalExit", "0", CVAR_ROM ); + com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE); s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ ); com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); @@ -2677,9 +2635,36 @@ void Com_Init( char *commandLine ) { Com_Printf ("Altivec support is %s\n", com_altivec->integer ? "enabled" : "disabled"); #endif + com_pipefile = Cvar_Get( "com_pipefile", "", CVAR_ARCHIVE|CVAR_LATCH ); + if( com_pipefile->string[0] ) + { + pipefile = FS_FCreateOpenPipeFile( com_pipefile->string ); + } + Com_Printf ("--- Common Initialization Complete ---\n"); } +/* +=============== +Com_ReadFromPipe + +Read whatever is in com_pipefile, if anything, and execute it +=============== +*/ +void Com_ReadFromPipe( void ) +{ + char buffer[MAX_STRING_CHARS] = {""}; + qboolean read; + + if( !pipefile ) + return; + + read = FS_Read( buffer, sizeof( buffer ), pipefile ); + if( read ) + Cbuf_ExecuteText( EXEC_APPEND, buffer ); +} + + //================================================================== void Com_WriteConfigToFile( const char *filename ) { @@ -2801,19 +2786,16 @@ Com_Frame void Com_Frame( void ) { int msec, minMsec; - static int lastTime; - int key; + int timeVal; + static int lastTime = 0, bias = 0; int timeBeforeFirstEvents; - int timeBeforeServer; - int timeBeforeEvents; - int timeBeforeClient; - int timeAfter; + int timeBeforeServer; + int timeBeforeEvents; + int timeBeforeClient; + int timeAfter; - - - if ( setjmp (abortframe) ) { return; // an ERR_DROP was thrown } @@ -2824,10 +2806,6 @@ void Com_Frame( void ) { timeBeforeClient = 0; timeAfter = 0; - - // old net chan encryption key - key = 0x87243987; - // write config file if anything changed Com_WriteConfiguration(); @@ -2838,37 +2816,59 @@ void Com_Frame( void ) { timeBeforeFirstEvents = Sys_Milliseconds (); } - // we may want to spin here if things are going too fast - if ( !com_dedicated->integer && !com_timedemo->integer ) { - if( com_minimized->integer && com_maxfpsMinimized->integer > 0 ) { - minMsec = 1000 / com_maxfpsMinimized->integer; - } else if( com_unfocused->integer && com_maxfpsUnfocused->integer > 0 ) { - minMsec = 1000 / com_maxfpsUnfocused->integer; - } else if( com_maxfps->integer > 0 ) { - minMsec = 1000 / com_maxfps->integer; - } else { - minMsec = 1; + // Figure out how much time we have + if(!com_timedemo->integer) + { + if(com_dedicated->integer) + minMsec = SV_FrameMsec(); + else + { + if(com_minimized->integer && com_maxfpsMinimized->integer > 0) + minMsec = 1000 / com_maxfpsMinimized->integer; + else if(com_unfocused->integer && com_maxfpsUnfocused->integer > 0) + minMsec = 1000 / com_maxfpsUnfocused->integer; + else if(com_maxfps->integer > 0) + minMsec = 1000 / com_maxfps->integer; + else + minMsec = 1; + + timeVal = com_frameTime - lastTime; + bias += timeVal - minMsec; + + if(bias > minMsec) + bias = minMsec; + + // Adjust minMsec if previous frame took too long to render so + // that framerate is stable at the requested value. + minMsec -= bias; } - } else { - minMsec = 1; } + else + minMsec = 1; - msec = minMsec; - do { - int timeRemaining = minMsec - msec; + timeVal = 0; + do + { + // Busy sleep the last millisecond for better timeout precision + if(com_busyWait->integer || timeVal < 2) + NET_Sleep(0); + else + NET_Sleep(timeVal - 1); - // The existing Sys_Sleep implementations aren't really - // precise enough to be of use beyond 100fps - // FIXME: implement a more precise sleep (RDTSC or something) - if( timeRemaining >= 10 ) - Sys_Sleep( timeRemaining ); + msec = Sys_Milliseconds() - com_frameTime; + + if(msec >= minMsec) + timeVal = 0; + else + timeVal = minMsec - msec; + + } while(timeVal > 0); + + lastTime = com_frameTime; + com_frameTime = Com_EventLoop(); + + msec = com_frameTime - lastTime; - com_frameTime = Com_EventLoop(); - if ( lastTime > com_frameTime ) { - lastTime = com_frameTime; // possible on first frame - } - msec = com_frameTime - lastTime; - } while ( msec < minMsec ); Cbuf_Execute (); if (com_altivec->modified) @@ -2877,11 +2877,8 @@ void Com_Frame( void ) { com_altivec->modified = qfalse; } - lastTime = com_frameTime; - // mess with msec if needed - com_frameMsec = msec; - msec = Com_ModifyMsec( msec ); + msec = Com_ModifyMsec(msec); // // server side @@ -2941,6 +2938,9 @@ void Com_Frame( void ) { } #endif + + NET_FlushPacketQueue(); + // // report timing information // @@ -2974,8 +2974,7 @@ void Com_Frame( void ) { c_pointcontents = 0; } - // old net chan encryption key - key = lastTime * 0x87243987; + Com_ReadFromPipe( ); com_frameNumber++; } @@ -2996,6 +2995,11 @@ void Com_Shutdown (void) { com_journalFile = 0; } + if( pipefile ) { + FS_FCloseFile( pipefile ); + FS_HomeRemove( com_pipefile->string ); + } + } //------------------------------------------------------------------------ @@ -3183,15 +3187,15 @@ Field_CompleteFilename =============== */ void Field_CompleteFilename( const char *dir, - const char *ext, qboolean stripExt ) + const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk ) { matchCount = 0; shortestMatch[ 0 ] = 0; - FS_FilenameCompletion( dir, ext, stripExt, FindMatches ); + FS_FilenameCompletion( dir, ext, stripExt, FindMatches, allowNonPureFilesOnDisk ); if( !Field_Complete( ) ) - FS_FilenameCompletion( dir, ext, stripExt, PrintMatches ); + FS_FilenameCompletion( dir, ext, stripExt, PrintMatches, allowNonPureFilesOnDisk ); } /* diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index b0a21506..8db30e6a 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -364,6 +364,18 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { flags &= ~CVAR_VM_CREATED; } + // Make sure servers cannot mark engine-added variables as SERVER_CREATED + if(var->flags & CVAR_SERVER_CREATED) + { + if(!(flags & CVAR_SERVER_CREATED)) + var->flags &= ~CVAR_SERVER_CREATED; + } + else + { + if(flags & CVAR_SERVER_CREATED) + flags &= ~CVAR_SERVER_CREATED; + } + var->flags |= flags; // only allow one non-empty reset string without a warning @@ -613,6 +625,28 @@ void Cvar_Set( const char *var_name, const char *value) { /* ============ +Cvar_SetSafe +============ +*/ +void Cvar_SetSafe( const char *var_name, const char *value ) +{ + int flags = Cvar_Flags( var_name ); + + if( flags != CVAR_NONEXISTENT && flags & CVAR_PROTECTED ) + { + if( value ) + Com_Error( ERR_DROP, "Restricted source tried to set " + "\"%s\" to \"%s\"\n", var_name, value ); + else + Com_Error( ERR_DROP, "Restricted source tried to " + "modify \"%s\"\n", var_name ); + return; + } + Cvar_Set( var_name, value ); +} + +/* +============ Cvar_SetLatched ============ */ @@ -636,6 +670,21 @@ void Cvar_SetValue( const char *var_name, float value) { Cvar_Set (var_name, val); } +/* +============ +Cvar_SetValueSafe +============ +*/ +void Cvar_SetValueSafe( const char *var_name, float value ) +{ + char val[32]; + + if( Q_isintegral( value ) ) + Com_sprintf( val, sizeof(val), "%i", (int)value ); + else + Com_sprintf( val, sizeof(val), "%f", value ); + Cvar_SetSafe( var_name, val ); +} /* ============ @@ -1211,9 +1260,9 @@ void Cvar_Update( vmCvar_t *vmCvar ) { } vmCvar->modificationCount = cv->modificationCount; if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING ) - Com_Error( ERR_DROP, "Cvar_Update: src %s length %zd exceeds MAX_CVAR_VALUE_STRING", + Com_Error( ERR_DROP, "Cvar_Update: src %s length %u exceeds MAX_CVAR_VALUE_STRING", cv->string, - strlen(cv->string)); + (unsigned int) strlen(cv->string)); Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING ); vmCvar->value = cv->value; diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 302ce0fe..62617223 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -173,21 +173,6 @@ or configs will never get loaded from disk! */ -// every time a new demo pk3 file is built, this checksum must be updated. -// the easiest way to get it is to just run the game and see what it spits out -#define DEMO_PAK0_CHECKSUM 2985612116u -static const unsigned pak_checksums[] = { - 1566731103u, - 298122907u, - 412165236u, - 2991495316u, - 1197932710u, - 4087071573u, - 3709064859u, - 908855077u, - 977125798u -}; - // if this is defined, the executable positively won't work with any paks other // than the demo pak, even if productid is present. This is only used for our // last demo release to prevent the mac and linux users from using the demo @@ -326,7 +311,7 @@ qboolean FS_PakIsPure( pack_t *pack ) { for ( i = 0 ; i < fs_numServerPaks ; i++ ) { // FIXME: also use hashed file names // NOTE TTimo: a pk3 with same checksum but different name would be validated too - // I don't see this as allowing for any exploit, it would only happen if the client does manips of it's file names 'not a bug' + // I don't see this as allowing for any exploit, it would only happen if the client does manips of its file names 'not a bug' if ( pack->checksum == fs_serverPaks[i] ) { return qtrue; // on the aproved list } @@ -538,57 +523,6 @@ static void FS_CheckFilenameIsNotExecutable( const char *filename, } } - -/* -================= -FS_CopyFile - -Copy a fully specified file from one place to another -================= -*/ -static void FS_CopyFile( char *fromOSPath, char *toOSPath ) { - FILE *f; - int len; - byte *buf; - - Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath ); - - FS_CheckFilenameIsNotExecutable( toOSPath, __func__ ); - - if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) { - Com_Printf( "Ignoring journal files\n"); - return; - } - - f = fopen( fromOSPath, "rb" ); - if ( !f ) { - return; - } - fseek (f, 0, SEEK_END); - len = ftell (f); - fseek (f, 0, SEEK_SET); - - // we are using direct malloc instead of Z_Malloc here, so it - // probably won't work on a mac... Its only for developers anyway... - buf = malloc( len ); - if (fread( buf, 1, len, f ) != len) - Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" ); - fclose( f ); - - if( FS_CreatePath( toOSPath ) ) { - return; - } - - f = fopen( toOSPath, "wb" ); - if ( !f ) { - return; - } - if (fwrite( buf, 1, len, f ) != len) - Com_Error( ERR_FATAL, "Short write in FS_Copyfiles()\n" ); - fclose( f ); - free( buf ); -} - /* =========== FS_Remove @@ -800,11 +734,7 @@ void FS_SV_Rename( const char *from, const char *to ) { FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); - if (rename( from_ospath, to_ospath )) { - // Failed, try copying it and deleting the original - FS_CopyFile ( from_ospath, to_ospath ); - FS_Remove ( from_ospath ); - } + rename(from_ospath, to_ospath); } @@ -834,11 +764,7 @@ void FS_Rename( const char *from, const char *to ) { FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); - if (rename( from_ospath, to_ospath )) { - // Failed, try copying it and deleting the original - FS_CopyFile ( from_ospath, to_ospath ); - FS_Remove ( from_ospath ); - } + rename(from_ospath, to_ospath); } /* @@ -959,6 +885,52 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { /* =========== +FS_FCreateOpenPipeFile + +=========== +*/ +fileHandle_t FS_FCreateOpenPipeFile( const char *filename ) { + char *ospath; + FILE *fifo; + fileHandle_t f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + f = FS_HandleForFile(); + fsh[f].zipFile = qfalse; + + Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); + + // don't let sound stutter + S_ClearSoundBuffer(); + + ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename ); + + if ( fs_debug->integer ) { + Com_Printf( "FS_FCreateOpenPipeFile: %s\n", ospath ); + } + + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + + fifo = Sys_Mkfifo( ospath ); + if( fifo ) { + fsh[f].handleFiles.file.o = fifo; + fsh[f].handleSync = qfalse; + } + else + { + Com_Printf( S_COLOR_YELLOW "WARNING: Could not create new com_pipefile at %s. " + "com_pipefile will not be used.\n", ospath ); + f = 0; + } + + return f; +} + +/* +=========== FS_FilenameCompare Ignore case and seprator char distinctions @@ -995,6 +967,59 @@ qboolean FS_FilenameCompare( const char *s1, const char *s2 ) { /* =========== +FS_IsExt + +Return qtrue if ext matches file extension filename +=========== +*/ + +qboolean FS_IsExt(const char *filename, const char *ext, int namelen) +{ + int extlen; + + extlen = strlen(ext); + + if(extlen > namelen) + return qfalse; + + filename += namelen - extlen; + + return !Q_stricmp(filename, ext); +} + +/* +=========== +FS_IsDemoExt + +Return qtrue if filename has a demo extension +=========== +*/ + +qboolean FS_IsDemoExt(const char *filename, int namelen) +{ + char *ext_test; + int index, protocol; + + ext_test = Q_strrchr(filename, '.'); + if(ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1)) + { + protocol = atoi(ext_test + ARRAY_LEN(DEMOEXT)); + + if(protocol == PROTOCOL_VERSION) + return qtrue; + + for(index = 0; demo_protocols[index]; index++) + { + if(demo_protocols[index] == protocol) + return qtrue; + } + } + + return qfalse; +} + +/* +=========== FS_FOpenFileRead Finds the file in the search path. @@ -1014,7 +1039,6 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF long hash; FILE *temp; int l; - char demoExt[16]; hash = 0; @@ -1061,7 +1085,6 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" ); } - Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION ); // qpaths are not supposed to have a leading slash if ( filename[0] == '/' || filename[0] == '\\' ) { filename++; @@ -1106,16 +1129,19 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF // shaders, txt, arena files by themselves do not count as a reference as // these are loaded from all pk3s // from every pk3 file.. - l = strlen( filename ); - if ( !(pak->referenced & FS_GENERAL_REF)) { - if ( Q_stricmp(filename + l - 7, ".shader") != 0 && - Q_stricmp(filename + l - 4, ".txt") != 0 && - Q_stricmp(filename + l - 4, ".cfg") != 0 && - Q_stricmp(filename + l - 7, ".config") != 0 && - strstr(filename, "levelshots") == NULL && - Q_stricmp(filename + l - 4, ".bot") != 0 && - Q_stricmp(filename + l - 6, ".arena") != 0 && - Q_stricmp(filename + l - 5, ".menu") != 0) { + l = strlen(filename); + + if (!(pak->referenced & FS_GENERAL_REF)) + { + if(!FS_IsExt(filename, ".shader", l) && + !FS_IsExt(filename, ".txt", l) && + !FS_IsExt(filename, ".cfg", l) && + !FS_IsExt(filename, ".config", l) && + !FS_IsExt(filename, ".bot", l) && + !FS_IsExt(filename, ".arena", l) && + !FS_IsExt(filename, ".menu", l) && + !strstr(filename, "levelshots")) + { pak->referenced |= FS_GENERAL_REF; } } @@ -1166,13 +1192,14 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF // this test can make the search fail although the file is in the directory // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 // turned out I used FS_FileExists instead - if ( fs_numServerPaks ) { - - if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files - && Q_stricmp( filename + l - 5, ".menu" ) // menu files - && Q_stricmp( filename + l - 5, ".game" ) // menu files - && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files - && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files + if(fs_numServerPaks) + { + if(!FS_IsExt(filename, ".cfg", l) && // for config files + !FS_IsExt(filename, ".menu", l) && // menu files + !FS_IsExt(filename, ".game", l) && // menu files + !FS_IsExt(filename, ".cfg", l) && // for journal files + !FS_IsDemoExt(filename, l)) // demos + { continue; } } @@ -1206,6 +1233,32 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF } +char *FS_FindDll( const char *filename ) { + searchpath_t *search; + directory_t *dir; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + for ( search = fs_searchpaths ; search ; search = search->next ) { + if ( search->dir ) { + FILE *f; + char *netpath; + + dir = search->dir; + netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); + f = fopen( netpath, "rb" ); + if (f) { + fclose( f ); + return netpath; + } + } + } + + return NULL; +} + /* ================= FS_Read @@ -1881,7 +1934,7 @@ Returns a uniqued list of files that match the given criteria from all search paths =============== */ -char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) { +char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles, qboolean allowNonPureFilesOnDisk ) { int nfiles; char **listCopy; char *list[MAX_FOUND_FILES]; @@ -1977,7 +2030,7 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt char *name; // don't scan directories for files if we are pure or restricted - if ( fs_numServerPaks ) { + if ( fs_numServerPaks && !allowNonPureFilesOnDisk ) { continue; } else { netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path ); @@ -2014,7 +2067,7 @@ FS_ListFiles ================= */ char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) { - return FS_ListFilteredFiles( path, extension, NULL, numfiles ); + return FS_ListFilteredFiles( path, extension, NULL, numfiles, qfalse ); } /* @@ -2393,7 +2446,7 @@ void FS_NewDir_f( void ) { Com_Printf( "---------------\n" ); - dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs ); + dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs, qfalse ); FS_SortFileList(dirnames, ndirs); @@ -2605,25 +2658,6 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { /* ================ -FS_idPak -================ -*/ -qboolean FS_idPak( char *pak, char *base ) { - int i; - - for (i = 0; i < NUM_ID_PAKS; i++) { - if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) { - break; - } - } - if (i < NUM_ID_PAKS) { - return qtrue; - } - return qfalse; -} - -/* -================ FS_CheckDirTraversal Check whether the string contains stuff like "../" to prevent directory traversal bugs @@ -2682,11 +2716,6 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { badchecksum = qfalse; havepak = qfalse; - // never autodownload any of the tremulous paks - if ( FS_idPak(fs_serverReferencedPakNames[i], BASEGAME) ) { - continue; - } - // Make sure the server cannot make us write to non-quake3 directories. if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i])) { @@ -2863,13 +2892,13 @@ static void FS_Startup( const char *gameName ) fs_packFiles = 0; fs_debug = Cvar_Get( "fs_debug", "0", 0 ); - fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT ); + fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT|CVAR_PROTECTED ); fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT ); homePath = Sys_DefaultHomePath(); if (!homePath || !homePath[0]) { homePath = fs_basepath->string; } - fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT ); + fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED ); fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); // add search path elements in reverse priority order @@ -2879,7 +2908,7 @@ static void FS_Startup( const char *gameName ) // fs_homepath is somewhat particular to *nix systems, only add if relevant #ifdef MACOS_X - fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT ); + fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); // Make MacOSX also include the base path included with the .app bundle if (fs_apppath->string[0]) FS_AddGameDirectory(fs_apppath->string, gameName); @@ -2937,7 +2966,6 @@ static void FS_Startup( const char *gameName ) Com_Printf( "%d files in pk3 files\n", fs_packFiles ); } - /* ===================== FS_GamePureChecksum @@ -3256,7 +3284,7 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) ); } - for (i = 0 ; i < sizeof(fs_serverReferencedPakNames) / sizeof(*fs_serverReferencedPakNames); i++) + for (i = 0 ; i < ARRAY_LEN(fs_serverReferencedPakNames); i++) { if(fs_serverReferencedPakNames[i]) Z_Free(fs_serverReferencedPakNames[i]); @@ -3465,13 +3493,13 @@ void FS_Flush( fileHandle_t f ) { } void FS_FilenameCompletion( const char *dir, const char *ext, - qboolean stripExt, void(*callback)(const char *s) ) { + qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk ) { char **filenames; int nfiles; int i; char filename[ MAX_STRING_CHARS ]; - filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles ); + filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles, allowNonPureFilesOnDisk ); FS_SortFileList( filenames, nfiles ); @@ -3487,3 +3515,11 @@ void FS_FilenameCompletion( const char *dir, const char *ext, } FS_FreeFileList( filenames ); } + +const char *FS_GetCurrentGameDir(void) +{ + if(fs_gamedirvar->string[0]) + return fs_gamedirvar->string; + + return BASEGAME; +} diff --git a/src/qcommon/msg.c b/src/qcommon/msg.c index ba956bc8..05a7aa9f 100644 --- a/src/qcommon/msg.c +++ b/src/qcommon/msg.c @@ -885,7 +885,7 @@ void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entity float fullFloat; int *fromF, *toF; - numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]); + numFields = ARRAY_LEN( entityStateFields ); // all fields should be 32 bits to avoid any compiler packing issues // the "number" field is not part of the field list @@ -1030,7 +1030,7 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, return; } - numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]); + numFields = ARRAY_LEN( entityStateFields ); lc = MSG_ReadByte(msg); if ( lc > numFields || lc < 0 ) { @@ -1203,7 +1203,7 @@ void MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct p c = msg->cursize; - numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] ); + numFields = ARRAY_LEN( playerStateFields ); lc = 0; for ( i = 0, field = playerStateFields ; i < numFields ; i++, field++ ) { @@ -1353,7 +1353,7 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t print = 0; } - numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] ); + numFields = ARRAY_LEN( playerStateFields ); lc = MSG_ReadByte(msg); if ( lc > numFields || lc < 0 ) { diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c index c1e527c5..e3a95e4a 100644 --- a/src/qcommon/net_ip.c +++ b/src/qcommon/net_ip.c @@ -51,6 +51,7 @@ typedef unsigned short sa_family_t; # define EADDRNOTAVAIL WSAEADDRNOTAVAIL # define EAFNOSUPPORT WSAEAFNOSUPPORT # define ECONNRESET WSAECONNRESET +typedef u_long ioctlarg_t; # define socketError WSAGetLastError( ) static WSADATA winsockdata; @@ -86,6 +87,7 @@ typedef int SOCKET; # define SOCKET_ERROR -1 # define closesocket close # define ioctlsocket ioctl +typedef int ioctlarg_t; # define socketError errno #endif @@ -108,6 +110,8 @@ static cvar_t *net_port6; static cvar_t *net_mcast6addr; static cvar_t *net_mcast6iface; +static cvar_t *net_dropsim; + static struct sockaddr socksRelayAddr; static SOCKET ip_socket = INVALID_SOCKET; @@ -202,7 +206,7 @@ char *NET_ErrorString( void ) { default: return "NO ERROR"; } #else - return strerror (errno); + return strerror(socketError); #endif } @@ -521,16 +525,17 @@ qboolean NET_IsLocalAddress( netadr_t adr ) { /* ================== -Sys_GetPacket +NET_GetPacket -Never called by the game logic, just the system event queing +Receive one packet ================== */ #ifdef _DEBUG int recvfromCount; #endif -qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { +qboolean NET_GetPacket(netadr_t *net_from, msg_t *net_message, fd_set *fdr) +{ int ret; struct sockaddr_storage from; socklen_t fromlen; @@ -540,7 +545,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { recvfromCount++; // performance check #endif - if(ip_socket != INVALID_SOCKET) + if(ip_socket != INVALID_SOCKET && FD_ISSET(ip_socket, fdr)) { fromlen = sizeof(from); ret = recvfrom( ip_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen ); @@ -574,7 +579,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { net_message->readcount = 0; } - if( ret == net_message->maxsize ) { + if( ret >= net_message->maxsize ) { Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) ); return qfalse; } @@ -584,7 +589,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { } } - if(ip6_socket != INVALID_SOCKET) + if(ip6_socket != INVALID_SOCKET && FD_ISSET(ip6_socket, fdr)) { fromlen = sizeof(from); ret = recvfrom(ip6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen); @@ -601,7 +606,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { SockadrToNetadr((struct sockaddr *) &from, net_from); net_message->readcount = 0; - if(ret == net_message->maxsize) + if(ret >= net_message->maxsize) { Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) ); return qfalse; @@ -612,7 +617,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { } } - if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket) + if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket && FD_ISSET(multicast6_socket, fdr)) { fromlen = sizeof(from); ret = recvfrom(multicast6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen); @@ -629,7 +634,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { SockadrToNetadr((struct sockaddr *) &from, net_from); net_message->readcount = 0; - if(ret == net_message->maxsize) + if(ret >= net_message->maxsize) { Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) ); return qfalse; @@ -825,7 +830,7 @@ NET_IPSocket int NET_IPSocket( char *net_interface, int port, int *err ) { SOCKET newsocket; struct sockaddr_in address; - u_long _true = 1; + ioctlarg_t _true = 1; int i = 1; *err = 0; @@ -893,7 +898,7 @@ NET_IP6Socket int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { SOCKET newsocket; struct sockaddr_in6 address; - u_long _true = 1; + ioctlarg_t _true = 1; *err = 0; @@ -1496,6 +1501,8 @@ static qboolean NET_GetCvars( void ) { modified += net_socksPassword->modified; net_socksPassword->modified = qfalse; + net_dropsim = Cvar_Get("net_dropsim", "", CVAR_TEMP); + return modified ? qtrue : qfalse; } @@ -1624,6 +1631,42 @@ void NET_Shutdown( void ) { #endif } +/* +==================== +NET_Event + +Called from NET_Sleep which uses select() to determine which sockets have seen action. +==================== +*/ + +void NET_Event(fd_set *fdr) +{ + byte bufData[MAX_MSGLEN + 1]; + netadr_t from; + msg_t netmsg; + + while(1) + { + MSG_Init(&netmsg, bufData, sizeof(bufData)); + + if(NET_GetPacket(&from, &netmsg, fdr)) + { + if(net_dropsim->value > 0.0f && net_dropsim->value <= 100.0f) + { + // com_dropsim->value percent of incoming packets get dropped. + if(rand() < (int) (((double) RAND_MAX) / 100.0 * (double) net_dropsim->value)) + continue; // drop this packet + } + + if(com_sv_running->integer) + Com_RunAndTimeServerPacket(&from, &netmsg); + else + CL_PacketEvent(from, &netmsg); + } + else + break; + } +} /* ==================== @@ -1632,31 +1675,23 @@ NET_Sleep Sleeps msec or until something happens on the network ==================== */ -void NET_Sleep( int msec ) { +void NET_Sleep(int msec) +{ struct timeval timeout; - fd_set fdset; - int highestfd = -1; - - if (!com_dedicated->integer) - return; // we're not a server, just run full speed - - if (ip_socket == INVALID_SOCKET && ip6_socket == INVALID_SOCKET) - return; - - if (msec < 0 ) - return; + fd_set fdr; + int highestfd = -1, retval; - FD_ZERO(&fdset); + FD_ZERO(&fdr); if(ip_socket != INVALID_SOCKET) { - FD_SET(ip_socket, &fdset); + FD_SET(ip_socket, &fdr); highestfd = ip_socket; } if(ip6_socket != INVALID_SOCKET) { - FD_SET(ip6_socket, &fdset); + FD_SET(ip6_socket, &fdr); if(ip6_socket > highestfd) highestfd = ip6_socket; @@ -1664,9 +1699,23 @@ void NET_Sleep( int msec ) { timeout.tv_sec = msec/1000; timeout.tv_usec = (msec%1000)*1000; - select(highestfd + 1, &fdset, NULL, NULL, &timeout); -} + +#ifdef _WIN32 + if(highestfd < 0) + { + // windows ain't happy when select is called without valid FDs + SleepEx(msec, 0); + return; + } +#endif + retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout); + + if(retval < 0) + Com_Printf("Warning: select() syscall failed: %s\n", NET_ErrorString()); + else if(retval > 0) + NET_Event(&fdr); +} /* ==================== diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h index 4d4d2856..3e9619ee 100644 --- a/src/qcommon/q_platform.h +++ b/src/qcommon/q_platform.h @@ -155,11 +155,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //================================================================= LINUX === -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD_kernel__) #include <endian.h> +#if defined(__linux__) #define OS_STRING "linux" +#else +#define OS_STRING "kFreeBSD" +#endif + #define ID_INLINE inline #define PATH_SEP '/' diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c index ce28f953..8b13aba2 100644 --- a/src/qcommon/q_shared.c +++ b/src/qcommon/q_shared.c @@ -706,10 +706,6 @@ char* Q_strrchr( const char* string, int c ) qboolean Q_isanumber( const char *s ) { -#ifdef Q3_VM - //FIXME: implement - return qfalse; -#else char *p; double d; @@ -719,7 +715,6 @@ qboolean Q_isanumber( const char *s ) d = strtod( s, &p ); return *p == '\0'; -#endif } qboolean Q_isintegral( float f ) @@ -727,6 +722,39 @@ qboolean Q_isintegral( float f ) return (int)f == f; } +#ifdef _MSC_VER +/* +============= +Q_vsnprintf + +Special wrapper function for Microsoft's broken _vsnprintf() function. +MinGW comes with its own snprintf() which is not broken. +============= +*/ + +int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int retval; + + retval = _vsnprintf(str, size, format, ap); + + if(retval < 0 || retval == size) + { + // Microsoft doesn't adhere to the C99 standard of vsnprintf, + // which states that the return value must be the number of + // bytes written if the output string had sufficient length. + // + // Obviously we cannot determine that value from Microsoft's + // implementation, so we have no choice but to return size. + + str[size - 1] = '\0'; + return size; + } + + return retval; +} +#endif + /* ============= Q_strncpyz @@ -954,28 +982,18 @@ void Q_ParseNewlines( char *dest, const char *src, int destsize ) *dest++ = '\0'; } -void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { +void QDECL Com_sprintf(char *dest, int size, const char *fmt, ...) +{ int len; va_list argptr; - char bigbuffer[32000]; // big, but small enough to fit in PPC stack va_start (argptr,fmt); - len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr); + len = Q_vsnprintf(dest, size, fmt, argptr); va_end (argptr); - if ( len >= sizeof( bigbuffer ) ) { - Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); - } - if (len >= size) { - Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); -#ifdef _DEBUG - __asm { - int 3; - } -#endif - } - Q_strncpyz (dest, bigbuffer, size ); -} + if(len >= size) + Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len); +} /* ============ @@ -1317,6 +1335,7 @@ void Info_SetValueForKey( char *s, const char *key, const char *value ) { Info_SetValueForKey_Big Changes or adds a key/value pair +Includes and retains zero-length values ================== */ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { @@ -1337,7 +1356,7 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { } Info_RemoveKey_Big (s, key); - if (!value || !strlen(value)) + if (!value) return; Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 3f2cb9d5..1cedf6a8 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -38,8 +38,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION #define GAMENAME_FOR_MASTER "Tremulous" +#define HEARTBEAT_FOR_MASTER GAMENAME_FOR_MASTER +#define FLATLINE_FOR_MASTER GAMENAME_FOR_MASTER "dead" #define MAX_TEAMNAME 32 +#define MAX_MASTER_SERVERS 5 // number of supported master servers + +#define DEMOEXT "dm_" // standard demo extension #ifdef _MSC_VER @@ -118,16 +123,6 @@ typedef int intptr_t; #include <ctype.h> #include <limits.h> -// vsnprintf is ISO/IEC 9899:1999 -// abstracting this to make it portable -#ifdef _WIN32 - #define Q_vsnprintf _vsnprintf - #define Q_snprintf _snprintf -#else - #define Q_vsnprintf vsnprintf - #define Q_snprintf snprintf -#endif - #ifdef _MSC_VER #include <io.h> @@ -139,8 +134,15 @@ typedef int intptr_t; typedef unsigned __int32 uint32_t; typedef unsigned __int16 uint16_t; typedef unsigned __int8 uint8_t; + + // vsnprintf is ISO/IEC 9899:1999 + // abstracting this to make it portable + int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap); #else #include <stdint.h> + + #define Q_vsnprintf vsnprintf + #define Q_snprintf snprintf #endif #endif @@ -165,12 +167,13 @@ typedef int sfxHandle_t; typedef int fileHandle_t; typedef int clipHandle_t; -#define PAD(x,y) (((x)+(y)-1) & ~((y)-1)) +#define PAD(x,y) (((x)+(y)-1) & ~((y)-1)) +#define PADLEN(x,y) (PAD((x), (y)) - (x)) #ifdef __GNUC__ -#define ALIGN(x) __attribute__((aligned(x))) +#define QALIGN(x) __attribute__((aligned(x))) #else -#define ALIGN(x) +#define QALIGN(x) #endif #ifndef NULL @@ -184,7 +187,7 @@ typedef int clipHandle_t; #define MAX_QINT 0x7fffffff #define MIN_QINT (-MAX_QINT-1) -#define ARRAY_LEN(x) (sizeof(x) / sizeof(*x)) +#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x))) // angle indexes @@ -886,6 +889,7 @@ default values. #define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to. #define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs. +#define CVAR_PROTECTED 0x2000 // prevent modifying this var from VMs or the server #define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist. // nothing outside the Cvar_*() functions should modify these fields! @@ -1414,4 +1418,7 @@ typedef struct #define DLP_PROMPTED 0x20 // prompt has been processed by client #define DLP_STALE 0x40 // prompt is not being shown by UI VM +#define LERP( a, b, w ) ( ( a ) * ( 1.0f - ( w ) ) + ( b ) * ( w ) ) +#define LUMA( red, green, blue ) ( 0.2126f * ( red ) + 0.7152f * ( green ) + 0.0722f * ( blue ) ) + #endif // __Q_SHARED_H diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 09132159..d09ee299 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -416,6 +416,9 @@ void Cmd_RemoveCommand( const char *cmd_name ); typedef void (*completionFunc_t)( char *args, int argNum ); +// don't allow VMs to remove system commands +void Cmd_RemoveCommandSafe( const char *cmd_name ); + void Cmd_CommandCompletion( void(*callback)(const char *s) ); // callback with each valid string void Cmd_SetCommandCompletionFunc( const char *command, @@ -431,6 +434,7 @@ char *Cmd_ArgsFrom( int arg ); void Cmd_ArgsBuffer( char *buffer, int bufferLength ); void Cmd_LiteralArgsBuffer( char *buffer, int bufferLength ); char *Cmd_Cmd (void); +void Cmd_Args_Sanitize( void ); // The functions that execute commands get their parameters with these // functions. Cmd_Argv () will return an empty string, not a NULL // if arg > argc, so string operations are allways safe. @@ -489,11 +493,15 @@ void Cvar_Update( vmCvar_t *vmCvar ); void Cvar_Set( const char *var_name, const char *value ); // will create the variable with no flags if it doesn't exist +void Cvar_SetSafe( const char *var_name, const char *value ); +// sometimes we set variables from an untrusted source: fail if flags & CVAR_PROTECTED + void Cvar_SetLatched( const char *var_name, const char *value); // don't set the cvar immediately void Cvar_SetValue( const char *var_name, float value ); -// expands value to a string and calls Cvar_Set +void Cvar_SetValueSafe( const char *var_name, float value ); +// expands value to a string and calls Cvar_Set/Cvar_SetSafe float Cvar_VariableValue( const char *var_name ); int Cvar_VariableIntegerValue( const char *var_name ); @@ -561,8 +569,6 @@ issues. #define FS_UI_REF 0x02 #define FS_CGAME_REF 0x04 #define FS_QAGAME_REF 0x08 -// number of id paks that will never be autodownloaded from baseq3 -#define NUM_ID_PAKS 9 #define MAX_FILE_HANDLES 64 @@ -595,6 +601,9 @@ void FS_FreeFileList( char **list ); qboolean FS_FileExists( const char *file ); qboolean FS_CreatePath (char *OSPath); + +char *FS_FindDll( const char *filename ); + char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); qboolean FS_CompareZipChecksum(const char *zipfile); @@ -605,6 +614,7 @@ int FS_GetModList( char *listbuf, int bufsize ); fileHandle_t FS_FOpenFileWrite( const char *qpath ); fileHandle_t FS_FOpenFileAppend( const char *filename ); +fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); // will properly create any needed paths and deal with seperater character issues fileHandle_t FS_SV_FOpenFileWrite( const char *filename ); @@ -692,7 +702,6 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ); // sole exception of .cfg files. qboolean FS_CheckDirTraversal(const char *checkdir); -qboolean FS_idPak( char *pak, char *base ); qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ); void FS_Rename( const char *from, const char *to ); @@ -701,7 +710,9 @@ void FS_Remove( const char *osPath ); void FS_HomeRemove( const char *homePath ); void FS_FilenameCompletion( const char *dir, const char *ext, - qboolean stripExt, void(*callback)(const char *s) ); + qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk ); + +const char *FS_GetCurrentGameDir(void); /* ============================================================== @@ -723,7 +734,7 @@ void Field_Clear( field_t *edit ); void Field_AutoComplete( field_t *edit ); void Field_CompleteKeyname( void ); void Field_CompleteFilename( const char *dir, - const char *ext, qboolean stripExt ); + const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk ); void Field_CompleteCommand( char *cmd, qboolean doCommands, qboolean doCvars ); @@ -754,13 +765,12 @@ typedef enum typedef enum { // SE_NONE must be zero - SE_NONE = 0, // evTime is still valid - SE_KEY, // evValue is a key code, evValue2 is the down flag - SE_CHAR, // evValue is an ascii char - SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves + SE_NONE = 0, // evTime is still valid + SE_KEY, // evValue is a key code, evValue2 is the down flag + SE_CHAR, // evValue is an ascii char + SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127) - SE_CONSOLE, // evPtr is a char* - SE_PACKET // evPtr is a netadr_t followed by data bytes to evPtrLength + SE_CONSOLE // evPtr is a char* } sysEventType_t; typedef struct { @@ -793,6 +803,7 @@ int Com_Filter(char *filter, char *name, int casesensitive); int Com_FilterPath(char *filter, char *name, int casesensitive); int Com_RealTime(qtime_t *qtime); qboolean Com_SafeMode( void ); +void Com_RunAndTimeServerPacket(netadr_t *evFrom, msg_t *buf); void Com_StartupVariable( const char *match ); // checks for and removes command line "+set var arg" constructs @@ -817,6 +828,7 @@ extern cvar_t *com_maxfpsUnfocused; extern cvar_t *com_minimized; extern cvar_t *com_maxfpsMinimized; extern cvar_t *com_altivec; +extern cvar_t *com_homepath; // both client and server must agree to pause extern cvar_t *cl_paused; @@ -831,7 +843,6 @@ extern int time_frontend; extern int time_backend; // renderer backend time extern int com_frameTime; -extern int com_frameMsec; extern qboolean com_errorEntered; @@ -976,6 +987,9 @@ void S_ClearSoundBuffer( void ); void SCR_DebugGraph (float value, int color); // FIXME: move logging to common? +// AVI files have the start of pixel lines 4 byte-aligned +#define AVI_LINE_PADDING 4 + // // server interface // @@ -983,6 +997,7 @@ void SV_Init( void ); void SV_Shutdown( char *finalmsg ); void SV_Frame( int msec ); void SV_PacketEvent( netadr_t from, msg_t *msg ); +int SV_FrameMsec(void); qboolean SV_GameCommand( void ); @@ -1012,7 +1027,7 @@ typedef enum { void Sys_Init (void); // general development dll loading for virtual machine testing -void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...), +void * QDECL Sys_LoadDll( const char *name, intptr_t (QDECL **entryPoint)(int, ...), intptr_t (QDECL *systemcalls)(intptr_t, ...) ); void Sys_UnloadDll( void *dllHandle ); @@ -1053,7 +1068,6 @@ cpuFeatures_t Sys_GetProcessorFeatures( void ); void Sys_SetErrorText( const char *text ); void Sys_SendPacket( int length, const void *data, netadr_t to ); -qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ); qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ); //Does NOT parse port numbers, only base addresses. @@ -1062,6 +1076,7 @@ qboolean Sys_IsLANAddress (netadr_t adr); void Sys_ShowIP(void); qboolean Sys_Mkdir( const char *path ); +FILE *Sys_Mkfifo( const char *ospath ); char *Sys_Cwd( void ); void Sys_SetDefaultInstallPath(const char *path); char *Sys_DefaultInstallPath(void); diff --git a/src/qcommon/unzip.c b/src/qcommon/unzip.c index d0b3d2a5..b307e98d 100644 --- a/src/qcommon/unzip.c +++ b/src/qcommon/unzip.c @@ -35,23 +35,10 @@ woven in by Terry Thorsen 1/2003. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" #include "unzip.h" -#ifdef STDC -# include <stddef.h> -# include <string.h> -# include <stdlib.h> -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include <errno.h> -#endif - - #ifndef local # define local static #endif @@ -74,10 +61,10 @@ woven in by Terry Thorsen 1/2003. #endif #ifndef ALLOC -# define ALLOC(size) (malloc(size)) +# define ALLOC(size) (Z_Malloc(size)) #endif #ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} +# define TRYFREE(p) {if (p) Z_Free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c index 14fa32e9..225119fb 100644 --- a/src/qcommon/vm.c +++ b/src/qcommon/vm.c @@ -307,7 +307,7 @@ Dlls will call this directly rcg010206 The horror; the horror. - The syscall mechanism relies on stack manipulation to get it's args. + The syscall mechanism relies on stack manipulation to get its args. This is likely due to C's inability to pass "..." parameters to a function in one clean chunk. On PowerPC Linux, these parameters are not necessarily passed on the stack, so while (&arg[0] == arg) @@ -347,7 +347,7 @@ intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) { args[0] = arg; va_start(ap, arg); - for (i = 1; i < sizeof (args) / sizeof (args[i]); i++) + for (i = 1; i < ARRAY_LEN (args); i++) args[i] = va_arg(ap, intptr_t); va_end(ap); @@ -385,8 +385,8 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { return NULL; } - // show where the qvm was loaded from - Cmd_ExecuteString( va( "which %s\n", filename ) ); + // show where the qvm was loaded from + Cmd_ExecuteString( va( "which %s\n", filename ) ); if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) { Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" ); @@ -560,7 +560,7 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), if ( interpret == VMI_NATIVE ) { // try to load as a system dll Com_Printf( "Loading dll file %s.\n", vm->name ); - vm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall ); + vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall ); if ( vm->dllHandle ) { return vm; } @@ -757,7 +757,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) { int args[10]; va_list ap; va_start(ap, callnum); - for (i = 0; i < sizeof (args) / sizeof (args[i]); i++) { + for (i = 0; i < ARRAY_LEN(args); i++) { args[i] = va_arg(ap, int); } va_end(ap); @@ -782,7 +782,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) { a.callnum = callnum; va_start(ap, callnum); - for (i = 0; i < sizeof (a.args) / sizeof (a.args[0]); i++) { + for (i = 0; i < ARRAY_LEN(a.args); i++) { a.args[i] = va_arg(ap, int); } va_end(ap); diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h index e9c3f7cc..80430be0 100644 --- a/src/qcommon/vm_local.h +++ b/src/qcommon/vm_local.h @@ -169,8 +169,6 @@ struct vm_s { int breakFunction; // increment breakCount on function entry to this int breakCount; - char fqpath[MAX_QPATH+1] ; - byte *jumpTableTargets; int numJumpTableTargets; }; diff --git a/src/qcommon/vm_powerpc.c b/src/qcommon/vm_powerpc.c index 6b7404dc..831e5672 100644 --- a/src/qcommon/vm_powerpc.c +++ b/src/qcommon/vm_powerpc.c @@ -690,7 +690,7 @@ static const long int gpr_list[] = { r7, r8, r9, r10, }; static const long int gpr_vstart = 8; /* position of first volatile register */ -static const long int gpr_total = sizeof( gpr_list ) / sizeof( gpr_list[0] ); +static const long int gpr_total = ARRAY_LEN( gpr_list ); static const long int fpr_list[] = { /* static registers, normally none is used */ @@ -704,7 +704,7 @@ static const long int fpr_list[] = { f12, f13, }; static const long int fpr_vstart = 8; -static const long int fpr_total = sizeof( fpr_list ) / sizeof( fpr_list[0] ); +static const long int fpr_total = ARRAY_LEN( fpr_list ); /* * prepare some dummy structures and emit init code @@ -1837,7 +1837,7 @@ PPC_ComputeCode( vm_t *vm ) unsigned char *dataAndCode = mmap( NULL, codeLength, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 ); - if ( ! dataAndCode ) + if (dataAndCode == MAP_FAILED) DIE( "Not enough memory" ); ppc_instruction_t *codeNow, *codeBegin; diff --git a/src/qcommon/vm_powerpc_asm.c b/src/qcommon/vm_powerpc_asm.c index da6a8434..58d65a00 100644 --- a/src/qcommon/vm_powerpc_asm.c +++ b/src/qcommon/vm_powerpc_asm.c @@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include "vm_local.h" #include "vm_powerpc_asm.h" #include <string.h> @@ -389,8 +390,7 @@ static const struct powerpc_operand powerpc_operands[] = }; -static const unsigned int num_powerpc_operands = - (sizeof (powerpc_operands) / sizeof (powerpc_operands[0])); +static const unsigned int num_powerpc_operands = ARRAY_LEN (powerpc_operands); /* The functions used to insert and extract complicated operands. */ @@ -1004,6 +1004,3 @@ static const struct powerpc_opcode powerpc_opcodes[] = { { "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, { "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } }, }; - -static const int powerpc_num_opcodes = - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); diff --git a/src/qcommon/vm_sparc.c b/src/qcommon/vm_sparc.c index 69bbdc5f..370ee200 100644 --- a/src/qcommon/vm_sparc.c +++ b/src/qcommon/vm_sparc.c @@ -259,7 +259,7 @@ static const struct sparc_opcode sparc_opcodes[] = { { "fbg", BFCC(0,6), { ARG_DISP22 }, }, { "fble", BFCC(0,13), { ARG_DISP22 }, }, }; -#define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0])) +#define SPARC_NUM_OPCODES (ARRAY_LEN(sparc_opcodes)) #define RS1(X) (((X) & 0x1f) << 14) #define RS2(X) (((X) & 0x1f) << 0) @@ -320,7 +320,7 @@ static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const #define IN(inst, args...) \ ({ const int argv[] = { args }; \ - const int argc = sizeof(argv) / sizeof(argv[0]); \ + const int argc = ARRAY_LEN(argv); \ sparc_assemble(inst, argc, argv); \ }) @@ -1427,7 +1427,7 @@ static void sparc_compute_code(vm_t *vm, struct func_info * const fp) data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - if (!data_and_code) + if (data_and_code == MAP_FAILED) DIE("Not enough memory"); code_now = code_begin = (unsigned int *) diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c index 41806f2a..f25be998 100644 --- a/src/qcommon/vm_x86.c +++ b/src/qcommon/vm_x86.c @@ -54,6 +54,7 @@ static void VM_Destroy_Compiled(vm_t* self); */ +#define VMFREE_BUFFERS() do {Z_Free(buf); Z_Free(jused);} while(0) static byte *buf = NULL; static byte *jused = NULL; static int compiledOfs = 0; @@ -290,6 +291,7 @@ static int Hex( int c ) { return c - '0'; } + VMFREE_BUFFERS(); Com_Error( ERR_DROP, "Hex: bad char '%c'", c ); return 0; @@ -409,6 +411,7 @@ qboolean EmitMovEBXEDI(vm_t *vm, int andit) { #define JUSED(x) \ do { \ if (x < 0 || x >= jusedSize) { \ + VMFREE_BUFFERS(); \ Com_Error( ERR_DROP, \ "VM_CompileX86: jump target out of range at offset %d", pc ); \ } \ @@ -430,7 +433,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // allocate a very large temp buffer, we will shrink it later maxLength = header->codeLength * 8; - buf = Z_Malloc( maxLength ); + buf = Z_Malloc(maxLength); jused = Z_Malloc(jusedSize); Com_Memset(jused, 0, jusedSize); @@ -455,16 +458,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { LastCommand = LAST_COMMAND_NONE; - while ( instruction < header->instructionCount ) { - if ( compiledOfs > maxLength - 16 ) { - Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" ); + while(instruction < header->instructionCount) + { + if(compiledOfs > maxLength - 16) + { + VMFREE_BUFFERS(); + Com_Error(ERR_DROP, "VM_CompileX86: maxLength exceeded"); } vm->instructionPointers[ instruction ] = compiledOfs; instruction++; - if ( pc > header->codeLength ) { - Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" ); + if(pc > header->codeLength) + { + VMFREE_BUFFERS(); + Com_Error(ERR_DROP, "VM_CompileX86: pc > header->codeLength"); } op = code[ pc ]; @@ -1076,7 +1084,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers ); break; default: - Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc ); + VMFREE_BUFFERS(); + Com_Error(ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc); } pop0 = pop1; pop1 = op; @@ -1087,13 +1096,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { vm->codeLength = compiledOfs; #ifdef VM_X86_MMAP vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == (void*)-1) - Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); + if(vm->codeBase == MAP_FAILED) + Com_Error(ERR_FATAL, "VM_CompileX86: can't mmap memory"); #elif _WIN32 // allocate memory with EXECUTE permissions under windows. vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(!vm->codeBase) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed"); + Com_Error(ERR_FATAL, "VM_CompileX86: VirtualAlloc failed"); #else vm->codeBase = malloc(compiledOfs); #endif @@ -1102,14 +1111,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #ifdef VM_X86_MMAP if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); + Com_Error(ERR_FATAL, "VM_CompileX86: mprotect failed"); #elif _WIN32 { DWORD oldProtect = 0; // remove write permissions. if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect)) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed"); + Com_Error(ERR_FATAL, "VM_CompileX86: VirtualProtect failed"); } #endif diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index 13c39172..6b335447 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -55,6 +55,8 @@ static FILE* qdasmout; #define Dfprintf(args...) #endif +#define VM_FREEBUFFERS(vm) do {assembler_init(0); VM_Destroy_Compiled(vm);} while(0) + void assembler_set_output(char* buf); size_t assembler_get_code_size(void); void assembler_init(int pass); @@ -252,6 +254,7 @@ void emit(const char* fmt, ...) #define CHECK_INSTR(nr) \ do { if(nr < 0 || nr >= header->instructionCount) { \ + VM_FREEBUFFERS(vm); \ Com_Error( ERR_DROP, \ "%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \ } } while(0) @@ -430,6 +433,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // const optimization unsigned got_const = 0, const_value = 0; + + vm->codeBase = NULL; gettimeofday(&tvstart, NULL); @@ -442,15 +447,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #ifdef VM_X86_64_MMAP vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == (void*)-1) - Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); + if(vm->codeBase == MAP_FAILED) + Com_Error(ERR_FATAL, "VM_CompileX86_64: can't mmap memory"); #elif __WIN64__ // allocate memory with write permissions under windows. vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); if(!vm->codeBase) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed"); + Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualAlloc failed"); #else vm->codeBase = malloc(compiledOfs); + if(!vm_codeBase) + Com_Error(ERR_FATAL, "VM_CompileX86_64: Failed to allocate memory"); #endif assembler_set_output((char*)vm->codeBase); @@ -931,7 +938,9 @@ emit_do_syscall: } - if(got_const) { + if(got_const) + { + VM_FREEBUFFERS(vm); Com_Error(ERR_DROP, "leftover const\n"); } @@ -944,14 +953,14 @@ emit_do_syscall: #ifdef VM_X86_64_MMAP if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); + Com_Error(ERR_FATAL, "VM_CompileX86_64: mprotect failed"); #elif __WIN64__ { DWORD oldProtect = 0; // remove write permissions; give exec permision if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect)) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed"); + Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualProtect failed"); } #endif @@ -988,11 +997,16 @@ emit_do_syscall: void VM_Destroy_Compiled(vm_t* self) { -#ifdef _WIN32 - VirtualFree(self->codeBase, 0, MEM_RELEASE); + if(self && self->codeBase) + { +#ifdef VM_X86_64_MMAP + munmap(self->codeBase, self->codeLength); +#elif __WIN64__ + VirtualFree(self->codeBase, 0, MEM_RELEASE); #else - munmap(self->codeBase, self->codeLength); + free(self->codeBase); #endif + } } /* diff --git a/src/qcommon/vm_x86_64_assembler.c b/src/qcommon/vm_x86_64_assembler.c index 99d2898e..06695d8d 100644 --- a/src/qcommon/vm_x86_64_assembler.c +++ b/src/qcommon/vm_x86_64_assembler.c @@ -22,6 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ +#define _ISOC99_SOURCE + +#include "vm_local.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -240,9 +243,15 @@ static void hash_add_label(const char* label, unsigned address) { struct hashentry* h; unsigned i = hashkey(label, -1U); - i %= sizeof(labelhash)/sizeof(labelhash[0]); - h = malloc(sizeof(struct hashentry)); - h->label = strdup(label); + int labellen; + + i %= ARRAY_LEN(labelhash); + h = Z_Malloc(sizeof(struct hashentry)); + + labellen = strlen(label) + 1; + h->label = Z_Malloc(labellen); + memcpy(h->label, label, labellen); + h->address = address; h->next = labelhash[i]; labelhash[i] = h; @@ -252,7 +261,7 @@ static unsigned lookup_label(const char* label) { struct hashentry* h; unsigned i = hashkey(label, -1U); - i %= sizeof(labelhash)/sizeof(labelhash[0]); + i %= ARRAY_LEN(labelhash); for(h = labelhash[i]; h; h = h->next ) { if(!strcmp(h->label, label)) @@ -268,15 +277,15 @@ static void labelhash_free(void) struct hashentry* h; unsigned i; unsigned z = 0, min = -1U, max = 0, t = 0; - for ( i = 0; i < sizeof(labelhash)/sizeof(labelhash[0]); ++i) + for ( i = 0; i < ARRAY_LEN(labelhash); ++i) { unsigned n = 0; h = labelhash[i]; while(h) { struct hashentry* next = h->next; - free(h->label); - free(h); + Z_Free(h->label); + Z_Free(h); h = next; ++n; } @@ -286,7 +295,7 @@ static void labelhash_free(void) min = MIN(min, n); max = MAX(max, n); } - printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max); + printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, ARRAY_LEN(labelhash), z, min, max); memset(labelhash, 0, sizeof(labelhash)); } @@ -1008,7 +1017,7 @@ static op_t* getop(const char* n) #else unsigned m, t, b; int r; - t = sizeof(ops)/sizeof(ops[0])-1; + t = ARRAY_LEN(ops)-1; b = 0; while(b <= t) @@ -1299,7 +1308,7 @@ void assembler_init(int pass) if(!ops_sorted) { ops_sorted = 1; - qsort(ops, sizeof(ops)/sizeof(ops[0])-1, sizeof(ops[0]), opsort); + qsort(ops, ARRAY_LEN(ops)-1, sizeof(ops[0]), opsort); } } |