rlrun.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // rlrun.c
  6. //
  7. // executable regression worker for rl.c
  8. #include "rl.h"
  9. #define TMP_PREFIX "ex" // 2 characters
  10. #define POGO_PGD "rlpogo.pgd"
  11. // In the RL environment running Pogo tests, some warnings in the optimization
  12. // compile should be errors, since we do the instrumentation and optimization
  13. // compiles back-to-back.
  14. // 4951 "'%s' has been edited since profile data was collected, function profile data not used"
  15. // 4952 "'%s' : no profile data found in program database '%s'"
  16. // 4953 "Inlinee '%s' has been edited since profile data was collected, profile data not used"
  17. // 4961 "No profile data was merged into '%s', profile-guided optimizations disabled"
  18. // 4962 "Profile-guided optimizations disabled because profile data became inconsistent"
  19. // 4963 "'%s' : no profile data found; different compiler options were used in instrumented build"
  20. static const char *PogoForceErrors = "-we4951 -we4952 -we4953 -we4961 -we4962 -we4963";
  21. //
  22. // Global variables set before worker threads start, and only accessed
  23. // (not set) by the worker threads.
  24. //
  25. // sets of options to iterate over
  26. const char *OptFlags[MAXOPTIONS + 1], *PogoOptFlags[MAXOPTIONS + 1];
  27. // use a big global array as scratch pad for passing the child process env vars
  28. #define MAX_ENV_LEN 10000
  29. __declspec(thread) char EnvFlags[MAX_ENV_LEN];
  30. //
  31. // Global variables read and written by the worker threads: these need to
  32. // either be protected by synchronization or use thread-local storage.
  33. //
  34. // currently, none
  35. LOCAL void __cdecl
  36. RunCleanUp()
  37. {
  38. }
  39. void
  40. RunInit()
  41. {
  42. char *opts; // value of EXEC_TESTS_FLAGS environment variable
  43. int numOptions;
  44. int numPogoOptions;
  45. int i;
  46. atexit(RunCleanUp);
  47. // Break EXEC_TESTS up into different sets of flags. The sets should
  48. // be separated by semi-colons. Options don't apply to Pogo testing
  49. // unless prefixed with POGO_TEST_PREFIX. Those options _only_ apply
  50. // to Pogo tests.
  51. opts = EXEC_TESTS_FLAGS;
  52. ASSERTNR(opts);
  53. numOptions = numPogoOptions = 0;
  54. while (opts) {
  55. while (isspace(*opts))
  56. opts++;
  57. if (*opts == '\0')
  58. break;
  59. if (!_strnicmp(opts, POGO_TEST_PREFIX, strlen(POGO_TEST_PREFIX))) {
  60. opts += strlen(POGO_TEST_PREFIX);
  61. PogoOptFlags[numPogoOptions] = opts;
  62. ++numPogoOptions;
  63. if (numPogoOptions == MAXOPTIONS)
  64. Fatal("Too many options in EXEC_TESTS_FLAGS");
  65. }
  66. else {
  67. OptFlags[numOptions] = opts;
  68. ++numOptions;
  69. if (numOptions == MAXOPTIONS)
  70. Fatal("Too many options in EXEC_TESTS_FLAGS");
  71. }
  72. opts = strchr(opts, ';');
  73. if (opts)
  74. *opts++ = '\0';
  75. }
  76. for (i = 0; i < numPogoOptions; i++) {
  77. if (strstr(PogoOptFlags[i], "GL") == NULL) {
  78. Fatal("Pogo without LTCG is not supported");
  79. }
  80. }
  81. OptFlags[numOptions] = NULL;
  82. PogoOptFlags[numPogoOptions] = NULL;
  83. if (FVerbose) {
  84. printf("(Normal) Exec flags:");
  85. for (i = 0; i < numOptions; i++) {
  86. printf(" '%s'", OptFlags[i]);
  87. }
  88. printf("\nPogo Exec flags:");
  89. for (i = 0; i < numPogoOptions; i++) {
  90. printf(" '%s'", PogoOptFlags[i]);
  91. }
  92. printf("\n");
  93. }
  94. }
  95. BOOL
  96. RunStartDir(
  97. char * /*dir -- unused*/
  98. )
  99. {
  100. return TRUE;
  101. }
  102. void
  103. DumpFileToLog(
  104. char* path
  105. )
  106. {
  107. FILE* fp;
  108. char buf[BUFFER_SIZE];
  109. char* p;
  110. fp = fopen_unsafe(path, "r");
  111. if (fp == NULL) {
  112. LogError("ERROR: DumpFileToLog couldn't open file '%s' with error '%s'", path, strerror_unsafe(errno));
  113. }
  114. else {
  115. int fd = _fileno(fp);
  116. struct _stat64 fileStats;
  117. if (fd != -1 && _fstat64(fd, &fileStats) != -1)
  118. {
  119. char creationTime[256];
  120. char accessTime[256];
  121. char currTime[256];
  122. __time64_t now = _time64(NULL);
  123. _ctime64_s(currTime, &now);
  124. _ctime64_s(creationTime, &fileStats.st_ctime);
  125. _ctime64_s(accessTime, &fileStats.st_atime);
  126. auto stripNewline = [](char *buf) {
  127. if (char *ptr = strchr(buf, '\n'))
  128. *ptr = '\0';
  129. };
  130. stripNewline(creationTime);
  131. stripNewline(accessTime);
  132. stripNewline(currTime);
  133. LogOut("ERROR: name of output file: %s; size: %I64d; creation: %s, last access: %s, now: %s", path, fileStats.st_size, creationTime, accessTime, currTime);
  134. }
  135. if (!FNoProgramOutput)
  136. {
  137. bool printlines = !FOnlyAssertOutput;
  138. if (printlines)
  139. {
  140. LogOut("ERROR: bad output file follows ============");
  141. }
  142. while (fgets(buf, BUFFER_SIZE, fp) != NULL) {
  143. // Strip the newline, since LogOut adds one
  144. p = strchr(buf, '\n');
  145. if (p != NULL) {
  146. *p = '\0';
  147. }
  148. if (!printlines && strlen(buf) > 8 && buf[0] == 'A' && buf[1] == 'S' && buf[2] == 'S' && buf[3] == 'E' && buf[4] == 'R' && buf[5] == 'T')
  149. {
  150. printlines = true;
  151. LogOut("ERROR: bad output file follows ============");
  152. }
  153. if (printlines)
  154. {
  155. LogOut("%s", buf);
  156. }
  157. }
  158. if (printlines)
  159. {
  160. LogOut("ERROR: end of bad output file ============");
  161. }
  162. }
  163. fclose(fp);
  164. }
  165. }
  166. // Use a state machine to recognize the word "pass"
  167. BOOL
  168. LookForPass(
  169. char *p
  170. )
  171. {
  172. int state = 0;
  173. for(; *p != '\0'; p++) {
  174. switch(tolower(*p)) {
  175. case 'p':
  176. state = 1;
  177. break;
  178. case 'a':
  179. if (state == 1)
  180. state = 2;
  181. else
  182. state = 0;
  183. break;
  184. case 's':
  185. if (state == 2)
  186. state = 3;
  187. else if (state == 3)
  188. return TRUE;
  189. else
  190. state = 0;
  191. break;
  192. default:
  193. state = 0;
  194. }
  195. }
  196. return FALSE;
  197. }
  198. // Return TRUE if the specified test is Pogo-specific.
  199. BOOL
  200. IsPogoTest(
  201. Test * pTest
  202. )
  203. {
  204. return HasInfo(pTest->defaultTestInfo.data[TIK_TAGS], XML_DELIM, "Pogo");
  205. }
  206. // Return TRUE if the specified test should NOT use nogpfnt.obj.
  207. BOOL
  208. SuppressNoGPF(
  209. Test * pTest
  210. )
  211. {
  212. return HasInfo(pTest->defaultTestInfo.data[TIK_RL_DIRECTIVES], XML_DELIM,
  213. "NoGPF");
  214. }
  215. template <size_t bufSize>
  216. void
  217. FillNoGPFFlags(
  218. char (&nogpfFlags)[bufSize],
  219. BOOL fSuppressNoGPF
  220. )
  221. {
  222. nogpfFlags[0] = '\0';
  223. if (FNogpfnt && TargetInfo[TargetMachine].fUseNoGPF) {
  224. if (!fSuppressNoGPF) {
  225. sprintf_s(nogpfFlags,
  226. " %s\\bin\\%s\\nogpfnt.obj /entry:nogpfntStartup",
  227. REGRESS, TargetInfo[TargetMachine].name);
  228. }
  229. }
  230. }
  231. BOOL
  232. CheckForPass(char * filename, char * optReportBuf, char * cmdbuf, BOOL fDumpOutputFile = TRUE)
  233. {
  234. FILE * fp;
  235. char buf[BUFFER_SIZE];
  236. // Check to see if the exe ran at all.
  237. fp = fopen_unsafe(filename, "r");
  238. if (fp == NULL) {
  239. LogOut("ERROR: Test failed to run. Unable to open file '%s', error '%s' (%s):", filename, strerror_unsafe(errno), optReportBuf);
  240. LogOut(" %s", cmdbuf);
  241. return FALSE;
  242. }
  243. // Parse the output file and verify that all lines must be pass/passed, or empty lines
  244. BOOL pass = FALSE;
  245. while(fgets(buf, BUFFER_SIZE, fp) != NULL)
  246. {
  247. if(!_strcmpi(buf, "pass\n") || !_strcmpi(buf, "passed\n"))
  248. {
  249. // Passing strings were found - pass
  250. pass = TRUE;
  251. }
  252. else if(_strcmpi(buf, "\n") != 0)
  253. {
  254. // Something else other than a newline was found - this is a failure.
  255. pass = FALSE;
  256. break;
  257. }
  258. }
  259. fclose(fp);
  260. if (!pass)
  261. {
  262. LogOut("ERROR: Test failed to run correctly: pass not found in output file (%s):", optReportBuf);
  263. LogOut(" %s", cmdbuf);
  264. if (fDumpOutputFile)
  265. {
  266. DumpFileToLog(filename);
  267. }
  268. }
  269. return pass;
  270. }
  271. void CopyRebaseFile(PCSTR testout, PCSTR baseline)
  272. {
  273. if (FRebase)
  274. {
  275. char rebase[_MAX_PATH];
  276. sprintf_s(rebase, "%s.rebase", baseline);
  277. CopyFile(testout, rebase, FALSE);
  278. }
  279. }
  280. // Handle external test scripts. We support three kinds, makefiles (rl.mak),
  281. // command shell (dotest.cmd), and JScript (*.js).
  282. //
  283. // Standardized makefiles have the following targets:
  284. // clean: delete all generated files
  285. // build: build the test (OPT=compile options)
  286. // run: run the test
  287. // copy: copy the generated files to a subdirectory (COPYDIR=subdir)
  288. //
  289. int
  290. DoOneExternalTest(
  291. CDirectory* pDir,
  292. TestVariant *pTestVariant,
  293. const char *optFlags,
  294. const char *inCCFlags,
  295. const char *inLinkFlags,
  296. const char *testCmd,
  297. ExternalTestKind kind,
  298. BOOL fSyncVariationWhenFinished,
  299. BOOL fCleanBefore,
  300. BOOL fCleanAfter,
  301. BOOL fSuppressNoGPF,
  302. void *envFlags,
  303. DWORD millisecTimeout
  304. )
  305. {
  306. #define NMAKE "nmake -nologo -R -f "
  307. char full[MAX_PATH];
  308. char cmdbuf[BUFFER_SIZE];
  309. char buf[BUFFER_SIZE];
  310. char ccFlags[BUFFER_SIZE];
  311. char linkFlags[BUFFER_SIZE];
  312. char nogpfFlags[BUFFER_SIZE];
  313. char optReportBuf[BUFFER_SIZE];
  314. char nonZeroReturnBuf[BUFFER_SIZE];
  315. const char *reason = NULL;
  316. time_t start_variation;
  317. UINT elapsed_variation;
  318. time_t start_build_variation;
  319. UINT elapsed_build_variation;
  320. LARGE_INTEGER start_run, end_run, frequency;
  321. UINT elapsed_run;
  322. BOOL fFailed = FALSE;
  323. BOOL fDumpOutputFile = FVerbose;
  324. BOOL fFileToDelete = FALSE;
  325. int cmdResult;
  326. static unsigned int testCount = 0;
  327. unsigned int localTestCount = InterlockedIncrement(&testCount);
  328. // Avoid conditionals by copying/creating ccFlags appropriately.
  329. if (inCCFlags)
  330. {
  331. if (pDir->HasTestInfoData(TIK_SOURCE_PATH))
  332. {
  333. sprintf_s(ccFlags, " %s -baselinePath:%s", inCCFlags, pDir->GetDirectoryPath());
  334. }
  335. else
  336. {
  337. sprintf_s(ccFlags, " %s", inCCFlags);
  338. }
  339. }
  340. else
  341. {
  342. ccFlags[0] = '\0';
  343. }
  344. switch (TargetMachine) {
  345. case TM_WVM:
  346. case TM_WVMX86:
  347. case TM_WVM64:
  348. strcat_s(ccFlags, " /BC ");
  349. break;
  350. }
  351. if (inLinkFlags)
  352. strcpy_s(linkFlags, inLinkFlags);
  353. else
  354. linkFlags[0] = '\0';
  355. sprintf_s(optReportBuf, "%s%s%s", optFlags, *linkFlags ? ";" : "", linkFlags);
  356. // Update the status.
  357. sprintf_s(buf, " (%s)", optReportBuf);
  358. ThreadInfo[ThreadId].SetCurrentTest(pDir->GetDirectoryName(),
  359. buf, pDir->IsBaseline());
  360. UpdateTitleStatus();
  361. // Make sure the file that will say pass or fail is not present.
  362. sprintf_s(full, "%s\\testout%d", pDir->GetDirectoryPath(), localTestCount);
  363. DeleteFileIfFound(full);
  364. start_variation = time(NULL);
  365. if (kind == TK_MAKEFILE) {
  366. Message(""); // newline
  367. Message("Processing %s with '%s' flags",
  368. testCmd, optReportBuf);
  369. Message(""); // newline
  370. if (FTest)
  371. {
  372. return 0;
  373. }
  374. if (fCleanBefore) {
  375. // Clean the directory.
  376. sprintf_s(cmdbuf, NMAKE"%s clean", testCmd);
  377. Message(cmdbuf);
  378. ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  379. }
  380. FillNoGPFFlags(nogpfFlags, fSuppressNoGPF);
  381. // Build the test.
  382. start_build_variation = time(NULL);
  383. sprintf_s(cmdbuf, NMAKE"%s build OPT=\"%s %s%s\" LINKFLAGS=\"%s %s %s\"",
  384. testCmd,
  385. optFlags, EXTRA_CC_FLAGS, ccFlags,
  386. LINKFLAGS, linkFlags, nogpfFlags);
  387. if (strlen(cmdbuf) > BUFFER_SIZE - 1)
  388. Fatal("Buffer overrun");
  389. Message(cmdbuf);
  390. fFailed = ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  391. elapsed_build_variation = (int)(time(NULL) - start_build_variation);
  392. if (Timing & TIME_VARIATION) {
  393. Message("RL: Variation elapsed time (build) (%s, %s, %s): %02d:%02d",
  394. pDir->GetDirectoryName(),
  395. "rl.mak",
  396. optReportBuf,
  397. elapsed_build_variation / 60, elapsed_build_variation % 60);
  398. }
  399. if (fFailed) {
  400. reason = "build failure";
  401. goto logFailure;
  402. }
  403. // Run the test.
  404. QueryPerformanceCounter(&start_run);
  405. sprintf_s(cmdbuf, NMAKE"%s run", testCmd);
  406. Message(cmdbuf);
  407. cmdResult = ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf, millisecTimeout);
  408. QueryPerformanceCounter(&end_run);
  409. QueryPerformanceFrequency(&frequency);
  410. elapsed_run = (int) (((end_run.QuadPart - start_run.QuadPart) * 1000UI64) / frequency.QuadPart);
  411. if (Timing & TIME_VARIATION) {
  412. Message("RL: Variation elapsed time (run) (%s, %s, %s): %02d:%02d.%03d",
  413. pDir->GetDirectoryName(),
  414. "rl.mak",
  415. optReportBuf,
  416. elapsed_run / 60000, (elapsed_run % 60000)/1000, elapsed_run % 1000);
  417. }
  418. }
  419. else if (kind == TK_CMDSCRIPT)
  420. {
  421. // Build up the test command string
  422. sprintf_s(cmdbuf, "%s %s %s%s >testout%d", testCmd, optFlags, EXTRA_CC_FLAGS, ccFlags, localTestCount);
  423. Message("Running '%s'", cmdbuf);
  424. if (FTest)
  425. {
  426. return 0;
  427. }
  428. cmdResult = ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf, millisecTimeout, envFlags);
  429. }
  430. else if (kind == TK_JSCRIPT || kind==TK_HTML || kind == TK_COMMAND)
  431. {
  432. char tempExtraCCFlags[MAX_PATH*2] = {0};
  433. // Only append when EXTRA_CC_FLAGS isn't empty.
  434. if (EXTRA_CC_FLAGS[0])
  435. {
  436. // Append test case unique identifier to the end of EXTRA_CC_FLAGS.
  437. if (FAppendTestNameToExtraCCFlags)
  438. {
  439. sprintf_s(tempExtraCCFlags, "%s.%s", EXTRA_CC_FLAGS, pTestVariant->testInfo.data[TIK_FILES]);
  440. }
  441. else
  442. {
  443. strcpy_s(tempExtraCCFlags, EXTRA_CC_FLAGS);
  444. }
  445. }
  446. const char* cmd = JCBinary;
  447. if (kind != TK_JSCRIPT && kind != TK_HTML)
  448. {
  449. cmd = pTestVariant->testInfo.data[TIK_COMMAND];
  450. }
  451. sprintf_s(cmdbuf, "%s %s %s %s %s >%s 2>&1", cmd, optFlags, tempExtraCCFlags, ccFlags, testCmd, full);
  452. Message("Running '%s'", cmdbuf);
  453. if(FTest)
  454. {
  455. DeleteFileIfFound(full);
  456. return 0;
  457. }
  458. cmdResult = ExecuteCommand(pDir->GetFullPathFromSourceOrDirectory(), cmdbuf, millisecTimeout, envFlags);
  459. if (cmdResult && cmdResult != WAIT_TIMEOUT && !pTestVariant->testInfo.data[TIK_BASELINE]) // failure code, not baseline diffing
  460. {
  461. fFailed = TRUE;
  462. sprintf_s(nonZeroReturnBuf, "non-zero (%08X) return value from test command", cmdResult);
  463. reason = nonZeroReturnBuf;
  464. goto logFailure;
  465. }
  466. }
  467. else
  468. {
  469. ASSERTNR(UNREACHED);
  470. cmdResult = NOERROR; // calm compiler warning about uninitialized variable usage
  471. }
  472. // Check for timeout.
  473. if (cmdResult == WAIT_TIMEOUT) {
  474. ASSERT(millisecTimeout != INFINITE);
  475. sprintf_s(nonZeroReturnBuf, "timed out after %u second%s", millisecTimeout / 1000, millisecTimeout == 1000 ? "" : "s");
  476. reason = nonZeroReturnBuf;
  477. fFailed = TRUE;
  478. goto logFailure;
  479. }
  480. // If we have a baseline test, we need to check the baseline file.
  481. if (pTestVariant->testInfo.data[TIK_BASELINE]) {
  482. char baseline_file[_MAX_PATH];
  483. sprintf_s(baseline_file, "%s\\%s", pDir->GetFullPathFromSourceOrDirectory(),
  484. pTestVariant->testInfo.data[TIK_BASELINE]);
  485. if (DoCompare(baseline_file, full, pTestVariant->testInfo.hasData[TIK_EOL_NORMALIZATION])) {
  486. reason = "diffs from baseline";
  487. sprintf_s(optReportBuf, "%s", baseline_file);
  488. fFailed = TRUE;
  489. CopyRebaseFile(full, baseline_file);
  490. }
  491. }
  492. else if ((kind == TK_JSCRIPT || kind == TK_HTML || kind == TK_COMMAND) && !pTestVariant->testInfo.hasData[TIK_BASELINE]) {
  493. if (!CheckForPass(full, optReportBuf, cmdbuf, fDumpOutputFile)) {
  494. fFailed = TRUE;
  495. goto SkipLogFailure;
  496. }
  497. }
  498. logFailure:
  499. if (fFailed) {
  500. LogOut("ERROR: Test failed to run correctly: %s (%s):",
  501. reason, optReportBuf);
  502. LogOut(" %s", cmdbuf);
  503. if (fDumpOutputFile) {
  504. DumpFileToLog(full);
  505. }
  506. }
  507. SkipLogFailure:
  508. if (fFileToDelete && !FNoDelete) {
  509. DeleteFileRetryMsg(full);
  510. }
  511. elapsed_variation = (int)(time(NULL) - start_variation);
  512. if (Timing & TIME_VARIATION) {
  513. Message("RL: Variation elapsed time (%s, %s, %s): %02d:%02d",
  514. pDir->GetDirectoryName(),
  515. kind == TK_MAKEFILE ? "rl.mak" : "dotest.cmd",
  516. optReportBuf,
  517. elapsed_variation / 60, elapsed_variation % 60);
  518. }
  519. if (kind == TK_MAKEFILE) {
  520. // If the test failed and we are asked to copy the failures, do so.
  521. if (fFailed && FCopyOnFail) {
  522. sprintf_s(cmdbuf, NMAKE"%s copy COPYDIR=\"fail.%s.%s\"",
  523. testCmd, optFlags, linkFlags);
  524. Message(cmdbuf);
  525. ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  526. }
  527. // Clean up after ourselves.
  528. if (!FNoDelete && (fFailed || fCleanAfter)) {
  529. sprintf_s(cmdbuf, NMAKE"%s clean", testCmd);
  530. Message(cmdbuf);
  531. ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  532. }
  533. }
  534. if (FSyncVariation) {
  535. if (FRLFE && fFailed) {
  536. RLFEAddLog(pDir, RLFES_FAILED, testCmd,
  537. optReportBuf, ThreadOut->GetText());
  538. }
  539. if (fSyncVariationWhenFinished)
  540. FlushOutput();
  541. }
  542. DeleteFileIfFound(full);
  543. return fFailed ? -1 : 0;
  544. }
  545. // null terminated string of null terminated strings
  546. // name=data from testinfo and all of parent process env, arg for CreateProcess()
  547. void * GetEnvFlags
  548. (
  549. TestVariant * pTestVariant
  550. )
  551. {
  552. char temp[BUFFER_SIZE];
  553. size_t len = 0, totalEnvLen = 0;
  554. char * envFlags = NULL;
  555. Xml::Node *env = (Xml::Node *)pTestVariant->testInfo.data[TIK_ENV];
  556. if (env != NULL) {
  557. // use a fixed global array for memory
  558. memset(EnvFlags, '\0', MAX_ENV_LEN);
  559. *temp = '\0';
  560. for ( Xml::Node * child = env->ChildList; child != NULL; child = child->Next) {
  561. sprintf_s(temp, "%s=%s", child->Name, child->Data);
  562. if (envFlags == NULL) {
  563. sprintf_s(EnvFlags, "%s", temp);
  564. envFlags = EnvFlags;
  565. } else {
  566. strcat_s(envFlags, REMAININGARRAYLEN(EnvFlags, envFlags), temp);
  567. }
  568. len = strlen(envFlags);
  569. envFlags += len+1;
  570. }
  571. LPTSTR lpszParentEnv = GetEnvironmentStrings();
  572. totalEnvLen = len;
  573. ASSERT(totalEnvLen < BUFFER_SIZE);
  574. len = 0;
  575. while(!((lpszParentEnv[len] == '\0') && (lpszParentEnv[len+1] == '\0'))) {
  576. len++;
  577. }
  578. ASSERT(totalEnvLen+len+2 < MAX_ENV_LEN);
  579. memcpy(envFlags, lpszParentEnv, len+2);
  580. FreeEnvironmentStrings(lpszParentEnv);
  581. envFlags = EnvFlags;
  582. }
  583. return (void*)envFlags;
  584. }
  585. int
  586. DoExternalTest(
  587. CDirectory* pDir,
  588. TestVariant * pTestVariant,
  589. char *testCmd,
  590. ExternalTestKind kind,
  591. BOOL fSuppressNoGPF,
  592. DWORD millisecTimeout
  593. )
  594. {
  595. const char *ccFlags = pTestVariant->testInfo.data[TIK_COMPILE_FLAGS];
  596. void *envFlags = GetEnvFlags(pTestVariant);
  597. return DoOneExternalTest(pDir, pTestVariant, pTestVariant->optFlags, ccFlags, NULL,
  598. testCmd, kind, TRUE, TRUE, TRUE, fSuppressNoGPF, envFlags, millisecTimeout);
  599. }
  600. int
  601. DoPogoExternalTest(
  602. CDirectory* pDir,
  603. TestVariant * pTestVariant,
  604. char *testCmd,
  605. ExternalTestKind kind,
  606. BOOL fSuppressNoGPF,
  607. DWORD millisecTimeout
  608. )
  609. {
  610. static const char *pgc = "*.pgc";
  611. static const char *pgd = POGO_PGD;
  612. char pgdFull[MAX_PATH];
  613. char ccFlags[BUFFER_SIZE];
  614. char linkFlags[BUFFER_SIZE];
  615. char cmdbuf[BUFFER_SIZE];
  616. BOOL fFailed;
  617. void *envFlags = GetEnvFlags(pTestVariant);
  618. sprintf_s(pgdFull, "%s\\%s", pDir->GetDirectoryPath(), pgd);
  619. const char * inCCFlags = pTestVariant->testInfo.data[TIK_COMPILE_FLAGS];
  620. const char * optFlags = pTestVariant->optFlags;
  621. DeleteFileIfFound(pgdFull);
  622. DeleteMultipleFiles(pDir, pgc);
  623. fFailed = FALSE;
  624. // Pogo requires LTCG
  625. ASSERT(strstr(optFlags, "GL") != NULL);
  626. if (!kind == TK_MAKEFILE) {
  627. Warning("'%s\\%s' is not a makefile test; Pogo almost certainly won't work", pDir->GetDirectoryPath(), testCmd);
  628. }
  629. sprintf_s(ccFlags, "%s %s", PogoForceErrors, optFlags);
  630. sprintf_s(linkFlags, "-ltcg:pgi -pgd:%s", pgd);
  631. if (DoOneExternalTest(pDir, pTestVariant, ccFlags, inCCFlags, linkFlags,
  632. testCmd, kind, FALSE, TRUE, FALSE, fSuppressNoGPF, envFlags, millisecTimeout)) {
  633. fFailed = TRUE;
  634. goto logFailure;
  635. }
  636. sprintf_s(ccFlags, "%s %s", PogoForceErrors, optFlags);
  637. sprintf_s(linkFlags, "-ltcg:pgo -pgd:%s", pgd);
  638. // Manually erase EXE and DLL files to get makefile to relink.
  639. // Also erase ASM files because some makefiles try to rebuild from
  640. // them.
  641. DeleteMultipleFiles(pDir, "*.exe");
  642. DeleteMultipleFiles(pDir, "*.dll");
  643. DeleteMultipleFiles(pDir, "*.asm");
  644. if (DoOneExternalTest(pDir, pTestVariant, ccFlags, inCCFlags, linkFlags,
  645. testCmd, kind, FALSE, FALSE, TRUE, fSuppressNoGPF, envFlags, millisecTimeout)) {
  646. fFailed = TRUE;
  647. }
  648. logFailure:
  649. if (FSyncVariation) {
  650. if (FRLFE && fFailed) {
  651. sprintf_s(cmdbuf, "%s%s%s", ccFlags,
  652. *linkFlags ? ";" : "", linkFlags);
  653. RLFEAddLog(pDir, RLFES_FAILED, testCmd,
  654. cmdbuf, ThreadOut->GetText());
  655. }
  656. FlushOutput();
  657. }
  658. if (FRLFE)
  659. RLFETestStatus(pDir);
  660. if (!FNoDelete) {
  661. DeleteFileRetryMsg(pgdFull);
  662. DeleteMultipleFiles(pDir, pgc);
  663. }
  664. return fFailed ? -1 : 0;
  665. }
  666. BOOL
  667. DoOneSimpleTest(
  668. CDirectory *pDir,
  669. Test * pTest,
  670. TestVariant * pTestVariant,
  671. const char *optFlags,
  672. const char *inCCFlags,
  673. const char *inLinkFlags,
  674. BOOL fSyncVariationWhenFinished,
  675. BOOL fCleanAfter,
  676. BOOL fLinkOnly, // relink only
  677. BOOL fSuppressNoGPF,
  678. DWORD millisecTimeout
  679. )
  680. {
  681. int rc;
  682. char *p = NULL;
  683. char cmdbuf[BUFFER_SIZE*2];
  684. char ccFlags[BUFFER_SIZE];
  685. char linkFlags[BUFFER_SIZE];
  686. char nogpfFlags[BUFFER_SIZE];
  687. char optReportBuf[BUFFER_SIZE];
  688. char full[MAX_PATH];
  689. char exebuf[BUFFER_SIZE];
  690. char fullexebuf[BUFFER_SIZE];
  691. char buf[BUFFER_SIZE];
  692. char failDir[BUFFER_SIZE];
  693. char copyName[BUFFER_SIZE];
  694. char tmp_file1[MAX_PATH];
  695. char tmp_file2[MAX_PATH];
  696. time_t start_variation;
  697. UINT elapsed_variation;
  698. BOOL fFailed;
  699. void *envFlags = GetEnvFlags(pTestVariant);
  700. // Avoid conditionals by copying/creating ccFlags appropriately.
  701. if (inCCFlags)
  702. sprintf_s(ccFlags, " %s", inCCFlags);
  703. else
  704. ccFlags[0] = '\0';
  705. switch (TargetMachine) {
  706. case TM_WVM:
  707. case TM_WVMX86:
  708. case TM_WVM64:
  709. strcat_s(ccFlags, " /BC ");
  710. break;
  711. }
  712. if (inLinkFlags)
  713. strcpy_s(linkFlags, inLinkFlags);
  714. else
  715. linkFlags[0] = '\0';
  716. sprintf_s(optReportBuf, "%s%s%s", optFlags, *linkFlags ? ";" : "", linkFlags);
  717. // Figure out the exe name and path
  718. strcpy_s(exebuf, pTest->name);
  719. p = strrchr(exebuf, '.');
  720. if (p != NULL)
  721. {
  722. strcpy_s(p + 1, REMAININGARRAYLEN(exebuf, p + 1), "exe");
  723. }
  724. else
  725. {
  726. strcat_s(exebuf, ".exe");
  727. }
  728. sprintf_s(fullexebuf, "%s\\%s", pDir->GetDirectoryPath(), exebuf);
  729. start_variation = time(NULL);
  730. // Build up the compile command string.
  731. sprintf_s(cmdbuf, "%s %s%s %s", REGR_CL,
  732. optFlags, ccFlags, EXTRA_CC_FLAGS);
  733. for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next)
  734. {
  735. strcat_s(cmdbuf, " ");
  736. strcat_s(cmdbuf, pFile->string);
  737. // If we're only relinking, hammer the extension to .obj
  738. if (fLinkOnly)
  739. {
  740. p = strrchr(cmdbuf, '.');
  741. sprintf_s(p, REMAININGARRAYLEN(cmdbuf, p), ".obj");
  742. }
  743. }
  744. // Build the link option string.
  745. if (LINKFLAGS && LINKFLAGS[0] != '\0') {
  746. strcat_s(linkFlags, " ");
  747. strcat_s(linkFlags, LINKFLAGS);
  748. }
  749. FillNoGPFFlags(nogpfFlags, fSuppressNoGPF);
  750. strcat_s(linkFlags, nogpfFlags);
  751. switch (TargetMachine) {
  752. case TM_X86:
  753. case TM_IA64:
  754. case TM_AMD64:
  755. case TM_AMD64SYS:
  756. case TM_AM33:
  757. case TM_ARM:
  758. case TM_ARM64:
  759. case TM_THUMB:
  760. case TM_M32R:
  761. case TM_MIPS:
  762. case TM_SH3:
  763. case TM_SH4:
  764. case TM_SH5M:
  765. case TM_SH5C:
  766. case TM_WVMX86:
  767. if (*linkFlags) {
  768. strcat_s(cmdbuf, " /link ");
  769. strcat_s(cmdbuf, linkFlags);
  770. }
  771. break;
  772. case TM_WVM:
  773. strcat_s(cmdbuf, " /c ");
  774. break;
  775. case TM_PPCWCE:
  776. if (*linkFlags) {
  777. strcat_s(cmdbuf, " ");
  778. strcat_s(cmdbuf, linkFlags);
  779. }
  780. break;
  781. }
  782. sprintf_s(buf, "%s (%s)", pTest->name, optReportBuf);
  783. ThreadInfo[ThreadId].SetCurrentTest(pDir->GetDirectoryName(), buf, pDir->IsBaseline());
  784. UpdateTitleStatus();
  785. // Remove exe if it's already there. We have to keep trying to delete it
  786. // until it's gone, or else the link will fail (if it is somehow still in
  787. // use).
  788. DeleteFileRetryMsg(fullexebuf);
  789. if (FTest)
  790. {
  791. Message("%s", cmdbuf);
  792. if (pTestVariant->testInfo.data[TIK_BASELINE]) {
  793. Message(" (baseline %s)", pTestVariant->testInfo.data[TIK_BASELINE]);
  794. }
  795. return 0;
  796. }
  797. // Do the compile.
  798. Message("Compiling:");
  799. Message(" %s", cmdbuf);
  800. rc = ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  801. // Some machines require separate linking of the
  802. // compiler and/or assembler output.
  803. if (rc == 0)
  804. {
  805. switch (TargetMachine)
  806. {
  807. case TM_WVM:
  808. // Build up the linker command string.
  809. strcpy_s(cmdbuf, LINKER);
  810. for (StringList * pFile = pTest->files;
  811. pFile != NULL;
  812. pFile = pFile->next)
  813. {
  814. strcat_s(cmdbuf, " ");
  815. strcat_s(cmdbuf, pFile->string);
  816. p = strrchr(cmdbuf, '.');
  817. strcpy_s(p + 1, REMAININGARRAYLEN(cmdbuf, p + 1), "obj");
  818. }
  819. if (linkFlags) {
  820. strcat_s(cmdbuf, " ");
  821. strcat_s(cmdbuf, linkFlags);
  822. }
  823. // Do the link.
  824. Message("Linking:");
  825. Message(" %s", cmdbuf);
  826. ExecuteCommand(pDir->GetDirectoryPath(), cmdbuf);
  827. break;
  828. default:
  829. break;
  830. }
  831. }
  832. // See if the compile succeeded by checking for the existence
  833. // of the executable.
  834. if ((rc != 0) || GetFileAttributes(fullexebuf) == INVALID_FILE_ATTRIBUTES) {
  835. LogOut("ERROR: Test failed to compile or link (%s):", optReportBuf);
  836. LogOut(" %s", cmdbuf);
  837. fFailed = TRUE;
  838. goto logFailure;
  839. }
  840. // Run the resulting exe.
  841. if (TargetVM) {
  842. strcpy_s(buf, TargetVM);
  843. strcat_s(buf, " ");
  844. strcat_s(buf, exebuf);
  845. // Copy the VM command to cmdbuf, so we get a useful error message
  846. // in the log file if test fails.
  847. strcpy_s(cmdbuf, buf);
  848. }
  849. else {
  850. strcpy_s(buf, exebuf);
  851. }
  852. // We need some temporary files.
  853. // Note: these are full pathnames, not relative pathnames. Also, note that
  854. // mytmpnam creates the file to be used. To avoid losing that file, and
  855. // risking another program using it, don't delete the file before use.
  856. // We currently delete the file before running the test, so we can see if
  857. // the test ever creates it. We should probably create the temp files in
  858. // the same directory as the test, since we guarantee that no other copies
  859. // of RL are running in the same directory.
  860. if (mytmpnam(pDir->GetDirectoryPath(), TMP_PREFIX, tmp_file1) == NULL ||
  861. mytmpnam(pDir->GetDirectoryPath(), TMP_PREFIX, tmp_file2) == NULL) {
  862. Fatal("Unable to create temporary files");
  863. }
  864. ThreadInfo[ThreadId].AddToTmpFileList(tmp_file1);
  865. ThreadInfo[ThreadId].AddToTmpFileList(tmp_file2);
  866. if (FVerbose)
  867. Message("INFO: tmp file 1 = %s, tmp file 2 = %s", tmp_file1, tmp_file2);
  868. Message("Running the test (%s)", buf);
  869. strcat_s(buf, " > ");
  870. strcat_s(buf, tmp_file1);
  871. // Make sure the output file isn't there.
  872. DeleteFileIfFound(tmp_file1);
  873. fFailed = FALSE;
  874. // Check for timeout.
  875. {
  876. int retval = ExecuteCommand(pDir->GetDirectoryPath(), buf, millisecTimeout, envFlags);
  877. if (retval == WAIT_TIMEOUT) {
  878. ASSERT(millisecTimeout != INFINITE);
  879. LogOut("ERROR: Test timed out after %ul seconds", millisecTimeout / 1000);
  880. fFailed = TRUE;
  881. goto logFailure;
  882. }
  883. }
  884. // Check the output.
  885. if (pTestVariant->testInfo.data[TIK_BASELINE]) {
  886. int spiff_ret;
  887. // Check to see if the exe ran at all.
  888. if (GetFileAttributes(tmp_file1) == INVALID_FILE_ATTRIBUTES) {
  889. LogOut("ERROR: Test failed to run. Couldn't find file '%s' (%s):", tmp_file1, optReportBuf);
  890. LogOut(" %s", cmdbuf);
  891. fFailed = TRUE;
  892. }
  893. else {
  894. sprintf_s(full, "%s\\%s", pDir->GetFullPathFromSourceOrDirectory(),
  895. pTestVariant->testInfo.data[TIK_BASELINE]);
  896. if (DoCompare(tmp_file1, full, pTestVariant->testInfo.hasData[TIK_EOL_NORMALIZATION])) {
  897. // Output differs, run spiff to see if it's just minor
  898. // floating point anomalies.
  899. DeleteFileIfFound(tmp_file2);
  900. sprintf_s(buf, "spiff -m -n -s \"command spiff\" %s %s > %s",
  901. tmp_file1, full, tmp_file2);
  902. spiff_ret = ExecuteCommand(pDir->GetDirectoryPath(), buf);
  903. if (GetFileAttributes(tmp_file2) == INVALID_FILE_ATTRIBUTES) {
  904. LogError("ERROR: spiff failed to run");
  905. fFailed = TRUE;
  906. }
  907. else if (spiff_ret) {
  908. LogOut("ERROR: Test failed to run correctly. spiff returned %d (%s):", spiff_ret, optReportBuf);
  909. LogOut(" %s", cmdbuf);
  910. fFailed = TRUE;
  911. }
  912. }
  913. }
  914. }
  915. else {
  916. if (!CheckForPass(tmp_file1, optReportBuf, cmdbuf)) {
  917. fFailed = TRUE;
  918. }
  919. }
  920. logFailure:
  921. if (fFailed) {
  922. if (FCopyOnFail) {
  923. if (FVerbose)
  924. Message("INFO: Copying '%s' failure", optReportBuf);
  925. sprintf_s(failDir, "%s\\fail.%s",
  926. pDir->GetDirectoryPath(), optReportBuf);
  927. if ((GetFileAttributes(failDir) == INVALID_FILE_ATTRIBUTES) &&
  928. !CreateDirectory(failDir, NULL)) {
  929. Message("ERROR: Couldn't create directory '%s'", failDir);
  930. }
  931. else
  932. {
  933. for (StringList * pFile = pTest->files;
  934. pFile != NULL;
  935. pFile = pFile->next)
  936. {
  937. sprintf_s(copyName, "%s\\%s", failDir, pFile->string);
  938. p = strrchr(copyName, '.') + 1;
  939. strcpy_s(p, REMAININGARRAYLEN(copyName, p + 1), "obj");
  940. sprintf_s(buf, "%s\\%s", pDir->GetDirectoryPath(),
  941. pFile->string);
  942. p = strrchr(buf, '.') + 1;
  943. strcpy_s(p, REMAININGARRAYLEN(buf, p + 1), "obj");
  944. if (!CopyFile(buf, copyName, FALSE)) {
  945. Message("ERROR: Couldn't copy '%s' to '%s'",
  946. buf, copyName);
  947. }
  948. }
  949. sprintf_s(copyName, "%s\\%s", failDir, exebuf);
  950. if (!CopyFile(fullexebuf, copyName, FALSE)) {
  951. Message("ERROR: Couldn't copy '%s' to '%s'",
  952. fullexebuf, copyName);
  953. }
  954. }
  955. }
  956. }
  957. if (FRLFE) {
  958. RLFETestStatus(pDir);
  959. }
  960. if (FVerbose)
  961. Message("INFO: cleaning up test run");
  962. // Remove the exe.
  963. if (!FNoDelete) {
  964. DeleteFileRetryMsg(fullexebuf);
  965. }
  966. // Don't trash fullexebuf!
  967. strcpy_s(buf, fullexebuf);
  968. p = strrchr(buf, '.') + 1;
  969. // Remove the pdb(s) (if it exists).
  970. strcpy_s(p, REMAININGARRAYLEN(buf, p), "pdb");
  971. DeleteFileIfFound(buf);
  972. DeleteMultipleFiles(pDir, "*.pdb");
  973. // Remove the ilk (if it exists).
  974. strcpy_s(p, REMAININGARRAYLEN(buf, p), "ilk");
  975. DeleteFileIfFound(buf);
  976. // Remove the objs.
  977. if (!FNoDelete)
  978. {
  979. for (StringList * pFile = pTest->files;
  980. pFile != NULL;
  981. pFile = pFile->next)
  982. {
  983. sprintf_s(buf, "%s\\%s", pDir->GetDirectoryPath(), pFile->string);
  984. p = strrchr(buf, '.') + 1;
  985. if (fCleanAfter)
  986. {
  987. strcpy_s(p, REMAININGARRAYLEN(buf, p), "obj");
  988. DeleteFileRetryMsg(buf);
  989. }
  990. if (REGR_ASM) {
  991. strcpy_s(p, REMAININGARRAYLEN(buf, p), "asm");
  992. DeleteFileRetryMsg(buf);
  993. }
  994. }
  995. }
  996. elapsed_variation = (int)(time(NULL) - start_variation);
  997. if (Timing & TIME_VARIATION) {
  998. Message("RL: Variation elapsed time (%s, %s, %s): %02d:%02d",
  999. pDir->GetDirectoryName(), pTest->name, optReportBuf,
  1000. elapsed_variation / 60, elapsed_variation % 60);
  1001. }
  1002. if (FSyncVariation) {
  1003. if (FRLFE && fFailed)
  1004. RLFEAddLog(pDir, RLFES_FAILED, pTest->name, optReportBuf, ThreadOut->GetText());
  1005. if (fSyncVariationWhenFinished)
  1006. FlushOutput();
  1007. }
  1008. ThreadInfo[ThreadId].DeleteTmpFileList();
  1009. return fFailed ? -1 : 0;
  1010. }
  1011. int
  1012. DoSimpleTest(
  1013. CDirectory *pDir,
  1014. Test * pTest,
  1015. TestVariant * pTestVariant,
  1016. BOOL fSuppressNoGPF,
  1017. DWORD millisecTimeout
  1018. )
  1019. {
  1020. return DoOneSimpleTest(pDir, pTest, pTestVariant, pTestVariant->optFlags,
  1021. pTestVariant->testInfo.data[TIK_COMPILE_FLAGS],
  1022. pTestVariant->testInfo.data[TIK_LINK_FLAGS],
  1023. TRUE, TRUE, FALSE, fSuppressNoGPF, millisecTimeout);
  1024. }
  1025. int
  1026. DoPogoSimpleTest(
  1027. CDirectory *pDir,
  1028. Test * pTest,
  1029. TestVariant * pTestVariant,
  1030. BOOL fSuppressNoGPF,
  1031. DWORD millisecTimeout
  1032. )
  1033. {
  1034. static const char *pgc = "*.pgc";
  1035. static const char *pgd = POGO_PGD;
  1036. char pgdFull[MAX_PATH];
  1037. char ccFlags[BUFFER_SIZE];
  1038. char linkFlags[BUFFER_SIZE];
  1039. BOOL fFailed;
  1040. sprintf_s(pgdFull, "%s\\%s", pDir->GetDirectoryPath(), pgd);
  1041. const char * inCCFlags = pTestVariant->testInfo.data[TIK_COMPILE_FLAGS];
  1042. const char * optFlags = pTestVariant->optFlags;
  1043. DeleteFileIfFound(pgdFull);
  1044. DeleteMultipleFiles(pDir, pgc);
  1045. fFailed = FALSE;
  1046. // Pogo requires LTCG
  1047. ASSERT(strstr(optFlags, "GL") != NULL);
  1048. sprintf_s(ccFlags, "%s %s", PogoForceErrors, optFlags);
  1049. sprintf_s(linkFlags, "-ltcg:pgi -pgd:%s", pgd);
  1050. if (DoOneSimpleTest(pDir, pTest, pTestVariant, ccFlags, inCCFlags,
  1051. linkFlags, FALSE, FALSE, FALSE, fSuppressNoGPF, millisecTimeout)) {
  1052. fFailed = TRUE;
  1053. goto logFailure;
  1054. }
  1055. if (FTest)
  1056. {
  1057. return 0;
  1058. }
  1059. sprintf_s(ccFlags, "%s %s", PogoForceErrors, optFlags);
  1060. sprintf_s(linkFlags, "-ltcg:pgo -pgd:%s", pgd);
  1061. if (DoOneSimpleTest(pDir, pTest, pTestVariant, ccFlags, inCCFlags,
  1062. linkFlags, FALSE, TRUE, TRUE, fSuppressNoGPF, millisecTimeout)) {
  1063. fFailed = TRUE;
  1064. }
  1065. logFailure:
  1066. if (FSyncVariation) {
  1067. #if 0
  1068. if (FRLFE && fFailed) {
  1069. sprintf_s(cmdbuf, "%s%s%s", ccFlags,
  1070. *linkFlags ? ";" : "", linkFlags);
  1071. RLFEAddLog(pDir, RLFES_FAILED, testCmd,
  1072. cmdbuf, ThreadOut->GetText());
  1073. }
  1074. #endif
  1075. FlushOutput();
  1076. }
  1077. if (!FNoDelete) {
  1078. DeleteFileRetryMsg(pgdFull);
  1079. DeleteMultipleFiles(pDir, pgc);
  1080. }
  1081. return fFailed ? -1 : 0;
  1082. }
  1083. int
  1084. ExecTest
  1085. (
  1086. CDirectory* pDir,
  1087. Test * pTest,
  1088. TestVariant * pTestVariant
  1089. )
  1090. {
  1091. char *p = NULL;
  1092. char full[MAX_PATH];
  1093. DWORD millisecTimeout = DEFAULT_TEST_TIMEOUT;
  1094. const char *strTimeout = pTestVariant->testInfo.data[TIK_TIMEOUT];
  1095. if (strTimeout) {
  1096. char *end;
  1097. _set_errno(0);
  1098. uint32 secTimeout = strtoul(strTimeout, &end, 10);
  1099. millisecTimeout = 1000 * secTimeout;
  1100. // Validation has already occurred so this string should
  1101. // parse fine and the value shouldn't overflow the DWORD.
  1102. ASSERT(errno == 0 && *end == 0);
  1103. ASSERT(millisecTimeout > secTimeout);
  1104. }
  1105. // Check to see if all of the files exist.
  1106. for (StringList * pFile = pTest->files; pFile != NULL; pFile = pFile->next)
  1107. {
  1108. // Get a pointer to the filename sans path, if present.
  1109. p = GetFilenamePtr(pFile->string);
  1110. // If we have no pathname, use the current directory.
  1111. if (p == pFile->string) {
  1112. sprintf_s(full, "%s\\", pDir->GetFullPathFromSourceOrDirectory());
  1113. }
  1114. else {
  1115. // Look for %REGRESS% specifier.
  1116. if (!_strnicmp(pFile->string, "%REGRESS%",
  1117. strlen("%REGRESS%"))) {
  1118. // Temporarily truncate the filename.
  1119. ASSERT(p[-1] == '\\');
  1120. p[-1] = '\0';
  1121. sprintf_s(full, "%s%s\\",
  1122. REGRESS, pFile->string + strlen("%REGRESS%"));
  1123. p[-1] = '\\';
  1124. }
  1125. else {
  1126. *p = '\0';
  1127. }
  1128. }
  1129. strcat_s(full, p);
  1130. if (GetFileAttributes(full) == INVALID_FILE_ATTRIBUTES) {
  1131. LogError("ERROR: '%s' does not exist", full);
  1132. return -1;
  1133. }
  1134. }
  1135. const char* ext = GetFilenameExt(p);
  1136. // Special case dotest.cmd
  1137. if (!_stricmp(p, "dotest.cmd")) {
  1138. // We don't handle these yet.
  1139. ASSERTNR(pTestVariant->testInfo.data[TIK_LINK_FLAGS] == NULL);
  1140. if (IsPogoTest(pTest))
  1141. return DoPogoExternalTest(pDir, pTestVariant, full, TK_CMDSCRIPT, TRUE, millisecTimeout);
  1142. else
  1143. return DoExternalTest(pDir, pTestVariant, full, TK_CMDSCRIPT, TRUE, millisecTimeout);
  1144. }
  1145. // Special case for standardized RL makefiles.
  1146. else if (!_stricmp(p, "rl.mak")) {
  1147. // We don't handle these yet.
  1148. ASSERTNR(pTestVariant->testInfo.data[TIK_LINK_FLAGS] == NULL);
  1149. if (IsPogoTest(pTest))
  1150. return DoPogoExternalTest(pDir, pTestVariant, full, TK_MAKEFILE, FALSE, millisecTimeout);
  1151. else
  1152. return DoExternalTest(pDir, pTestVariant, full, TK_MAKEFILE, SuppressNoGPF(pTest), millisecTimeout);
  1153. }
  1154. // Special case for files ending with ".js", ".html", ".htm" (<command> dealt with separately)
  1155. else if (pTestVariant->testInfo.data[TIK_COMMAND] == NULL
  1156. && !_stricmp(ext, ".js"))
  1157. {
  1158. return DoExternalTest(pDir, pTestVariant, full, TK_JSCRIPT, FALSE, millisecTimeout);
  1159. }
  1160. else if (pTestVariant->testInfo.data[TIK_COMMAND] == NULL
  1161. && (!_stricmp(ext, ".html") || !_stricmp(ext, ".htm")))
  1162. {
  1163. return DoExternalTest(pDir, pTestVariant, full, TK_HTML, FALSE, millisecTimeout);
  1164. }
  1165. // Special case for tests with a <command> argument
  1166. else if (pTestVariant->testInfo.data[TIK_COMMAND] != NULL)
  1167. {
  1168. return DoExternalTest(pDir, pTestVariant, full, TK_COMMAND, FALSE, millisecTimeout);
  1169. }
  1170. // Non-scripted test.
  1171. else {
  1172. if (IsPogoTest(pTest)) {
  1173. // We don't handle these yet.
  1174. ASSERTNR(pTestVariant->testInfo.data[TIK_LINK_FLAGS] == NULL);
  1175. return DoPogoSimpleTest(pDir, pTest, pTestVariant, FALSE, millisecTimeout);
  1176. }
  1177. else
  1178. {
  1179. return DoSimpleTest(pDir, pTest, pTestVariant, SuppressNoGPF(pTest), millisecTimeout);
  1180. }
  1181. }
  1182. }