void RLFEAddLog( CDirectory *pDir, RLFE_STATUS status, const char *testName, const char *subTestName, const char *logText ) { int pathLen, logLen, num; BYTE buf[4]; char pathBuf[BUFFER_SIZE], *path; ASSERTNR(testName || subTestName); ASSERTNR(logText); path = pathBuf; if (testName) path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, testName); if (subTestName) path += sprintf_s(path, REMAININGARRAYLEN(pathBuf, path), "%c%s", PIPE_SEP_CHAR, subTestName); // String has a leading PIPE_SEP_CHAR, so chop that off. path = pathBuf + 1; pathLen = (int)strlen(path); ASSERTNR(pathLen < BUFFER_SIZE - 1); logLen = (int)strlen(logText); num = pDir->GetDirectoryNumber(); ASSERTNR((SHORT)num == num); *(SHORT *)buf = (SHORT)num; buf[2] = (BYTE)pDir->stat; buf[3] = (BYTE)status; #ifdef TRACE printf("RLFEAddLog: %d, %d, %s, %s\n", pDir->stat, num, path, logText); #endif if (RLFEEnterCritSec()) { SendCommand(RLFE_ADD_LOG, 2 + pathLen + 4 + logLen); SendDataWithLen((BYTE *)path, pathLen); SendData(buf, 4); SendData((BYTE *)logText, logLen); RLFELeaveCritSec(); } }
// null terminated string of null terminated strings // name=data from testinfo and all of parent process env, arg for CreateProcess() void * GetEnvFlags ( TestVariant * pTestVariant ) { char temp[BUFFER_SIZE]; size_t len = 0, totalEnvLen = 0; char * envFlags = NULL; Xml::Node *env = (Xml::Node *)pTestVariant->testInfo.data[TIK_ENV]; if (env != NULL) { // use a fixed global array for memory memset(EnvFlags, '\0', MAX_ENV_LEN); *temp = '\0'; for ( Xml::Node * child = env->ChildList; child != NULL; child = child->Next) { sprintf_s(temp, "%s=%s", child->Name, child->Data); if (envFlags == NULL) { sprintf_s(EnvFlags, "%s", temp); envFlags = EnvFlags; } else { strcat_s(envFlags, REMAININGARRAYLEN(EnvFlags, envFlags), temp); } len = strlen(envFlags); envFlags += len+1; } LPTSTR lpszParentEnv = GetEnvironmentStrings(); totalEnvLen = len; ASSERT(totalEnvLen < BUFFER_SIZE); len = 0; while(!((lpszParentEnv[len] == '\0') && (lpszParentEnv[len+1] == '\0'))) { len++; } ASSERT(totalEnvLen+len+2 < MAX_ENV_LEN); memcpy(envFlags, lpszParentEnv, len+2); FreeEnvironmentStrings(lpszParentEnv); envFlags = EnvFlags; } return (void*)envFlags; }
// This function takes care of creating the pipe between RL and RLFE and // starts RLFE. BOOL RLFEConnect( const char *prefix ) { char pipeName[32]; char options[512], *pOpt, *s; char pipeID[9], *pID; DWORD id = 0; pOpt = options; pID = NULL; // Parse RLFE options. while (RLFEOpts && *RLFEOpts) { s = strchr(RLFEOpts, ','); if (s) *s++ = '\0'; if (!_stricmp(RLFEOpts, "min")) pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -min"); else if (!_strnicmp(RLFEOpts, "pipe", 4)) pID = RLFEOpts + 4; RLFEOpts = s; } if (pID == NULL) { id = GetCurrentProcessId(); sprintf_s(pipeID, "%08x", id); pID = pipeID; } sprintf_s(pipeName, "%s%s", PIPE_NAME, pID); if (strlen(pipeName) > 31) { printf("RLFE pipename buffer too small\n"); return FALSE; } pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -pipe %s", pID); if (prefix) pOpt += sprintf_s(pOpt, REMAININGARRAYLEN(options, pOpt), " -prefix \"%s\"", prefix); HPipe = CreateNamedPipe( pipeName, PIPE_ACCESS_OUTBOUND | FILE_FLAG_WRITE_THROUGH, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 2048, 2048, 5 * 1000, NULL); if (HPipe == INVALID_HANDLE_VALUE) { fprintf(stderr, "RLFE pipe creation failed\n"); return FALSE; } if (id) { if (strlen(options) > 511) { printf("RLFE options buffer too small\n"); return FALSE; } if (SpawnRLFE(options)) { CloseHandle(HPipe); return FALSE; } } else { printf("Please launch RLFE manually with -pipe %s\n", pID); } if (!ConnectNamedPipe(HPipe, NULL)) { CloseHandle(HPipe); fprintf(stderr, "RLFE failed to connected\n"); return FALSE; } FConnected = TRUE; return TRUE; }
BOOL DoOneSimpleTest( CDirectory *pDir, Test * pTest, TestVariant * pTestVariant, const char *optFlags, const char *inCCFlags, const char *inLinkFlags, BOOL fSyncVariationWhenFinished, BOOL fCleanAfter, BOOL fLinkOnly, // relink only BOOL fSuppressNoGPF, DWORD millisecTimeout ) { int rc; char *p = NULL; char cmdbuf[BUFFER_SIZE*2]; char ccFlags[BUFFER_SIZE]; char linkFlags[BUFFER_SIZE]; char nogpfFlags[BUFFER_SIZE]; char optReportBuf[BUFFER_SIZE]; char full[MAX_PATH]; char exebuf[BUFFER_SIZE]; char fullexebuf[BUFFER_SIZE]; char buf[BUFFER_SIZE]; char failDir[BUFFER_SIZE]; char copyName[BUFFER_SIZE]; char tmp_file1[MAX_PATH]; char tmp_file2[MAX_PATH]; time_t start_variation; UINT elapsed_variation; BOOL fFailed; void *envFlags = GetEnvFlags(pTestVariant); // Avoid conditionals by copying/creating ccFlags appropriately. if (inCCFlags) sprintf_s(ccFlags, " %s", inCCFlags); else ccFlags[0] = '\0'; switch (TargetMachine) { case TM_WVM: case TM_WVMX86: case TM_WVM64: strcat_s(ccFlags, " /BC "); break; } if (inLinkFlags) strcpy_s(linkFlags, inLinkFlags); else linkFlags[0] = '\0'; sprintf_s(optReportBuf, "%s%s%s", optFlags, *linkFlags ? ";" : "", linkFlags); // Figure out the exe name and path strcpy_s(exebuf, pTest->name); p = strrchr(exebuf, '.'); if (p != NULL) { strcpy_s(p + 1, REMAININGARRAYLEN(exebuf, p + 1), "exe"); } else { strcat_s(exebuf, ".exe"); } sprintf_s(fullexebuf, "%s\\%s", pDir->GetDirectoryPath(), exebuf); start_variation = time(NULL); // Build up the compile command string. sprintf_s(cmdbuf, "%s %s%s %s", REGR_CL, optFlags, ccFlags, EXTRA_CC_FLAGS); for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next) { strcat_s(cmdbuf, " "); strcat_s(cmdbuf, pFile->string); // If we're only relinking, hammer the extension to .obj if (fLinkOnly) { p = strrchr(cmdbuf, '.'); sprintf_s(p, REMAININGARRAYLEN(cmdbuf, p), ".obj"); } } // Build the link option string. if (LINKFLAGS && LINKFLAGS[0] != '\0') { strcat_s(linkFlags, " "); strcat_s(linkFlags, LINKFLAGS); } FillNoGPFFlags(nogpfFlags, fSuppressNoGPF); strcat_s(linkFlags, nogpfFlags); switch (TargetMachine) { case TM_X86: case TM_IA64: case TM_AMD64: case TM_AMD64SYS: case TM_AM33: case TM_ARM: case TM_ARM64: case TM_THUMB: case TM_M32R: case TM_MIPS: case TM_SH3: case TM_SH4: case TM_SH5M: case TM_SH5C: case TM_WVMX86: if (*linkFlags) { strcat_s(cmdbuf, " /link "); strcat_s(cmdbuf, linkFlags); } break; case TM_WVM: strcat_s(cmdbuf, " /c "); break; case TM_PPCWCE: if (*linkFlags) { strcat_s(cmdbuf, " "); strcat_s(cmdbuf, linkFlags); } break; } sprintf_s(buf, "%s (%s)", pTest->name, optReportBuf); ThreadInfo[ThreadId].SetCurrentTest(pDir->GetDirectoryName(), buf, pDir->IsBaseline()); UpdateTitleStatus(); // Remove exe if it's already there. We have to keep trying to delete it // until it's gone, or else the link will fail (if it is somehow still in // use). DeleteFileRetryMsg(fullexebuf); if (FTest) { Message("%s", cmdbuf); if (pTestVariant->testInfo.data[TIK_BASELINE]) { Message(" (baseline %s)", pTestVariant->testInfo.data[TIK_BASELINE]); } return 0; } // Do the compile. Message("Compiling:"); Message(" %s", cmdbuf); rc = ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf); // Some machines require separate linking of the // compiler and/or assembler output. if (rc == 0) { switch (TargetMachine) { case TM_WVM: // Build up the linker command string. strcpy_s(cmdbuf, LINKER); for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next) { strcat_s(cmdbuf, " "); strcat_s(cmdbuf, pFile->string); p = strrchr(cmdbuf, '.'); strcpy_s(p + 1, REMAININGARRAYLEN(cmdbuf, p + 1), "obj"); } if (linkFlags) { strcat_s(cmdbuf, " "); strcat_s(cmdbuf, linkFlags); } // Do the link. Message("Linking:"); Message(" %s", cmdbuf); ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf); break; default: break; } } // See if the compile succeeded by checking for the existence // of the executable. if ((rc != 0) || GetFileAttributes(fullexebuf) == INVALID_FILE_ATTRIBUTES) { LogOut("ERROR: Test failed to compile or link (%s):", optReportBuf); LogOut(" %s", cmdbuf); fFailed = TRUE; goto logFailure; } // Run the resulting exe. if (TargetVM) { strcpy_s(buf, TargetVM); strcat_s(buf, " "); strcat_s(buf, exebuf); // Copy the VM command to cmdbuf, so we get a useful error message // in the log file if test fails. strcpy_s(cmdbuf, buf); } else { strcpy_s(buf, exebuf); } // We need some temporary files. // Note: these are full pathnames, not relative pathnames. Also, note that // mytmpnam creates the file to be used. To avoid losing that file, and // risking another program using it, don't delete the file before use. // We currently delete the file before running the test, so we can see if // the test ever creates it. We should probably create the temp files in // the same directory as the test, since we guarantee that no other copies // of RL are running in the same directory. if (mytmpnam(pDir->GetDirectoryPath(), TMP_PREFIX, tmp_file1) == NULL || mytmpnam(pDir->GetDirectoryPath(), TMP_PREFIX, tmp_file2) == NULL) { Fatal("Unable to create temporary files"); } ThreadInfo[ThreadId].AddToTmpFileList(tmp_file1); ThreadInfo[ThreadId].AddToTmpFileList(tmp_file2); if (FVerbose) Message("INFO: tmp file 1 = %s, tmp file 2 = %s", tmp_file1, tmp_file2); Message("Running the test (%s)", buf); strcat_s(buf, " > "); strcat_s(buf, tmp_file1); // Make sure the output file isn't there. DeleteFileIfFound(tmp_file1); fFailed = FALSE; // Check for timeout. { int retval = ExecuteCommand(pDir->GetDirectoryPath(), buf, millisecTimeout, envFlags); if (retval == WAIT_TIMEOUT) { ASSERT(millisecTimeout != INFINITE); LogOut("ERROR: Test timed out after %ul seconds", millisecTimeout / 1000); fFailed = TRUE; goto logFailure; } } // Check the output. if (pTestVariant->testInfo.data[TIK_BASELINE]) { int spiff_ret; // Check to see if the exe ran at all. if (GetFileAttributes(tmp_file1) == INVALID_FILE_ATTRIBUTES) { LogOut("ERROR: Test failed to run. Couldn't find file '%s' (%s):", tmp_file1, optReportBuf); LogOut(" %s", cmdbuf); fFailed = TRUE; } else { sprintf_s(full, "%s\\%s", pDir->GetFullPathFromSourceOrDirectory(), pTestVariant->testInfo.data[TIK_BASELINE]); if (DoCompare(tmp_file1, full, pTestVariant->testInfo.hasData[TIK_EOL_NORMALIZATION])) { // Output differs, run spiff to see if it's just minor // floating point anomalies. DeleteFileIfFound(tmp_file2); sprintf_s(buf, "spiff -m -n -s \"command spiff\" %s %s > %s", tmp_file1, full, tmp_file2); spiff_ret = ExecuteCommand(pDir->GetDirectoryPath(), buf); if (GetFileAttributes(tmp_file2) == INVALID_FILE_ATTRIBUTES) { LogError("ERROR: spiff failed to run"); fFailed = TRUE; } else if (spiff_ret) { LogOut("ERROR: Test failed to run correctly. spiff returned %d (%s):", spiff_ret, optReportBuf); LogOut(" %s", cmdbuf); fFailed = TRUE; } } } } else { if (!CheckForPass(tmp_file1, optReportBuf, cmdbuf)) { fFailed = TRUE; } } logFailure: if (fFailed) { if (FCopyOnFail) { if (FVerbose) Message("INFO: Copying '%s' failure", optReportBuf); sprintf_s(failDir, "%s\\fail.%s", pDir->GetDirectoryPath(), optReportBuf); if ((GetFileAttributes(failDir) == INVALID_FILE_ATTRIBUTES) && !CreateDirectory(failDir, NULL)) { Message("ERROR: Couldn't create directory '%s'", failDir); } else { for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next) { sprintf_s(copyName, "%s\\%s", failDir, pFile->string); p = strrchr(copyName, '.') + 1; strcpy_s(p, REMAININGARRAYLEN(copyName, p + 1), "obj"); sprintf_s(buf, "%s\\%s", pDir->GetDirectoryPath(), pFile->string); p = strrchr(buf, '.') + 1; strcpy_s(p, REMAININGARRAYLEN(buf, p + 1), "obj"); if (!CopyFile(buf, copyName, FALSE)) { Message("ERROR: Couldn't copy '%s' to '%s'", buf, copyName); } } sprintf_s(copyName, "%s\\%s", failDir, exebuf); if (!CopyFile(fullexebuf, copyName, FALSE)) { Message("ERROR: Couldn't copy '%s' to '%s'", fullexebuf, copyName); } } } } if (FRLFE) { RLFETestStatus(pDir); } if (FVerbose) Message("INFO: cleaning up test run"); // Remove the exe. if (!FNoDelete) { DeleteFileRetryMsg(fullexebuf); } // Don't trash fullexebuf! strcpy_s(buf, fullexebuf); p = strrchr(buf, '.') + 1; // Remove the pdb(s) (if it exists). strcpy_s(p, REMAININGARRAYLEN(buf, p), "pdb"); DeleteFileIfFound(buf); DeleteMultipleFiles(pDir, "*.pdb"); // Remove the ilk (if it exists). strcpy_s(p, REMAININGARRAYLEN(buf, p), "ilk"); DeleteFileIfFound(buf); // Remove the objs. if (!FNoDelete) { for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next) { sprintf_s(buf, "%s\\%s", pDir->GetDirectoryPath(), pFile->string); p = strrchr(buf, '.') + 1; if (fCleanAfter) { strcpy_s(p, REMAININGARRAYLEN(buf, p), "obj"); DeleteFileRetryMsg(buf); } if (REGR_ASM) { strcpy_s(p, REMAININGARRAYLEN(buf, p), "asm"); DeleteFileRetryMsg(buf); } } } elapsed_variation = (int)(time(NULL) - start_variation); if (Timing & TIME_VARIATION) { Message("RL: Variation elapsed time (%s, %s, %s): %02d:%02d", pDir->GetDirectoryName(), pTest->name, optReportBuf, elapsed_variation / 60, elapsed_variation % 60); } if (FSyncVariation) { if (FRLFE && fFailed) RLFEAddLog(pDir, RLFES_FAILED, pTest->name, optReportBuf, ThreadOut->GetText()); if (fSyncVariationWhenFinished) FlushOutput(); } ThreadInfo[ThreadId].DeleteTmpFileList(); return fFailed ? -1 : 0; }