Loading...
testing/lib/test_support.cpp dyld-940 dyld-750.6
--- dyld/dyld-940/testing/lib/test_support.cpp
+++ dyld/dyld-750.6/testing/lib/test_support.cpp
@@ -138,10 +138,8 @@
         Console,
         XCTest
     };
-    void emitBegin();
     void runLeaks();
     void dumpLogs();
-    void getLogsString(char** buffer);
     static uint8_t hexCharToUInt(const char hexByte, uint8_t* value);
     static uint64_t hexToUInt64(const char* startHexByte, const char** endHexByte);
     
@@ -156,9 +154,9 @@
 };
 
 // Okay, this is tricky. We need something with roughly he semantics of a weak def, but without using weak defs as their presence
-// may impact certain tests. Instead we do the following:
+// m ay impact certain tests. Instead we do the following:
 //
-// 1. Embed a stuct containing a lock and a pointer to our global state object in each binary
+// 1. Embed a stuct containing a lock and a pointer to our global state object in eahc binary
 // 2. Once per binary we walk the entire image list looking for the first entry that also has state data
 // 3. If it has state we lock its initializaion lock, and if it is not initialized we initialize it
 // 4. We then copy the initalized pointer into our own state, and unlock the initializer lock
@@ -226,7 +224,7 @@
 }
 
 _process::_process() :  executablePath(nullptr), args(nullptr), env(nullptr), stdoutHandler(nullptr), stderrHandler(nullptr),
-                        crashHandler(nullptr), exitHandler(nullptr), arch(currentArch), suspended(false) {}
+                        crashHandler(nullptr), exitHandler(nullptr), pid(0), arch(currentArch), suspended(false), async(false) {}
 _process::~_process() {
     if (stdoutHandler) { Block_release(stdoutHandler);}
     if (stderrHandler) { Block_release(stderrHandler);}
@@ -242,6 +240,7 @@
 void _process::set_exit_handler(_dyld_test_exit_handler_t EH) { exitHandler = Block_copy(EH); }
 void _process::set_crash_handler(_dyld_test_crash_handler_t CH) { crashHandler = Block_copy(CH); }
 void _process::set_launch_suspended(bool S) { suspended = S; }
+void _process::set_launch_async(bool S) { async = S; }
 void _process::set_launch_arch(cpu_type_t A) { arch = A; }
 
 pid_t _process::launch() {
@@ -377,6 +376,9 @@
     posix_spawnattr_destroy(&attr);
     if (!suspended) {
         kill(pid, SIGCONT);
+    }
+    if (!async) {
+        dispatch_block_wait(oneShotSemaphoreBlock, DISPATCH_TIME_FOREVER);
     }
     Block_release(oneShotSemaphoreBlock);
     dispatch_release(queue);
@@ -453,29 +455,6 @@
     return retval;
 }
 
-void TestState::getLogsString(char** buffer)
-{
-    char *logBuf = NULL;
-    if ( logs.count() ) {
-        size_t idx = 0;
-        size_t bufSize = 0;
-        for (const auto& log : logs) {
-            size_t logSize = strlen(log);
-            bufSize += logSize + 2;  // \t and \n
-            logBuf = (char*)realloc(logBuf, bufSize);
-            strncpy(logBuf+idx, "\t", 1);
-            idx++;
-            strncpy(logBuf+idx, log, logSize);
-            idx += logSize;
-            strncpy(logBuf+idx, "\n", 1);
-            idx++;
-        }
-        logBuf = (char*)realloc(logBuf, bufSize + 1);
-        logBuf[bufSize] = '\0';
-        *buffer = logBuf;
-    }
-}
-
 TestState::TestState() : testName(__progname), logImmediate(false), logOnSuccess(false),  checkForLeaks(false), output(Console) {
     forEachEnvVar(environ, [this](const char* env, const char* val) {
         if (strcmp(env, "TEST_LOG_IMMEDIATE") == 0) {
@@ -495,15 +474,12 @@
             }
         }
     });
-}
-
-void TestState::emitBegin() {
     if (output == BATS) {
         printf("[BEGIN]");
         if (checkForLeaks) {
             printf(" MallocStackLogging=1 MallocDebugReport=none");
         }
-        forEachEnvVar(environ, [](const char* env, const char* val) {
+        forEachEnvVar(environ, [this](const char* env, const char* val) {
             if ((strncmp(env, "DYLD_", 5) == 0) || (strncmp(env, "TEST_", 5) == 0)) {
                 printf(" %s=%s", env, val);
             }
@@ -516,53 +492,57 @@
     }
 }
 
+static std::atomic<TestState*>& getExecutableImageState() {
+    uint32_t imageCnt = _dyld_image_count();
+    for (uint32_t i = 0; i < imageCnt; ++i) {
+        #if __LP64__
+            const struct mach_header_64* mh = (const struct mach_header_64*)_dyld_get_image_header(i);
+        #else
+            const struct mach_header* mh = _dyld_get_image_header(i);
+        #endif
+        if (mh->filetype != MH_EXECUTE) {
+            continue;
+        }
+        size_t size = 0;
+        auto state = (std::atomic<TestState*>*)getsectiondata(mh, "__DATA", "__dyld_test", &size);
+        if (!state) {
+            fprintf(stderr, "Could not find test state in main executable TestState\n");
+            exit(0);
+        }
+        return *state;
+    }
+    fprintf(stderr, "Could not find test state in main executable\n");
+    exit(0);
+}
+
 GrowableArray<std::pair<mach_port_t, _dyld_test_crash_handler_t>>& TestState::getCrashHandlers() {
     return crashHandlers;
 }
 
 TestState* TestState::getState() {
     if (!sState) {
-        uint32_t imageCnt = _dyld_image_count();
-        for (uint32_t i = 0; i < imageCnt; ++i) {
-            #if __LP64__
-                const struct mach_header_64* mh = (const struct mach_header_64*)_dyld_get_image_header(i);
-            #else
-                const struct mach_header* mh = _dyld_get_image_header(i);
-            #endif
-            if (mh->filetype != MH_EXECUTE) {
-                continue;
+        auto& state = getExecutableImageState();
+        if (state == nullptr) {
+            void *temp = malloc(sizeof(TestState));
+            auto newState = new (temp) TestState();
+            TestState* expected = nullptr;
+            if(!state.compare_exchange_strong(expected, newState)) {
+                newState->~TestState();
+                free(temp);
             }
-            size_t size = 0;
-            auto state = (std::atomic<TestState*>*)getsectiondata(mh, "__DATA", "__dyld_test", &size);
-//            fprintf(stderr, "__dyld_test -> 0x%llx\n", state);
-            if (!state) {
-                fprintf(stderr, "Could not find test state in main executable TestState\n");
-                exit(0);
-            }
-            if (*state == nullptr) {
-                void *temp = malloc(sizeof(TestState));
-                auto newState = new (temp) TestState();
-                TestState* expected = nullptr;
-                if(!state->compare_exchange_strong(expected, newState)) {
-                    newState->~TestState();
-                    free(temp);
-                } else {
-                    newState->emitBegin();
-                }
-            }
-            sState.store(*state);
-            break; // don't print [BEGIN] if a second main executeable is dlopen()ed
-        }
+        }
+        sState.store(state);
     }
     assert(sState != nullptr);
     return sState;
 }
+
 __attribute__((noreturn))
 void TestState::runLeaks(void) {
     auto testState = TestState::getState();
-    pid_t currentPid = getpid();
+    pid_t pid = getpid();
     char pidString[32];
-    sprintf(&pidString[0], "%d", currentPid);
+    sprintf(&pidString[0], "%d", pid);
     if (getuid() != 0) {
         printf("Insufficient priviledges, skipping Leak check: %s\n", testState->testName);
         exit(0);
@@ -616,7 +596,7 @@
     if (checkForLeaks) {
         runLeaks();
     } else {
-        _IOlock.withLock([this,&format,&args](){
+        _IOlock.withLock([this,&format,&args,&file,&line](){
             if (output == Console) {
                 printf("[\033[0;32mPASS\033[0m] %s: ", testName);
                 vprintf(format, args);
@@ -643,21 +623,12 @@
                 printf("<plist version=\"1.0\">");
                 printf("<dict>");
                 printf("<key>PASS</key><true />");
-                if (logOnSuccess) {
-                    char *logBuffer = NULL;
-                    getLogsString(&logBuffer);
-                    if ( logBuffer != NULL ) {
-                        printf("<key>LOGS</key><string>%s</string>", logBuffer);
-                        free(logBuffer);
-                    }
-                }
                 printf("</dict>");
                 printf("</plist>");
             }
-            exit(0);
         });
-    }
-    __builtin_unreachable();
+        exit(0);
+    }
 }
 
 void _PASS(const char* file, unsigned line, const char* format, ...)  {
@@ -693,6 +664,7 @@
                 }
             }
         } else if (output == XCTest) {
+            char *buffer;
             printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
             printf("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
             printf("<plist version=\"1.0\">");
@@ -700,22 +672,14 @@
             printf("<key>PASS</key><false />");
             printf("<key>FILE</key><string>%s</string>", file);
             printf("<key>LINE</key><integer>%u</integer>", line);
-            char *buffer;
             vasprintf(&buffer, format, args);
             printf("<key>INFO</key><string>%s</string>", buffer);
             free(buffer);
-            char *logBuffer = NULL;
-            getLogsString(&logBuffer);
-            if ( logBuffer != NULL ) {
-                printf("<key>LOGS</key><string>%s</string>", logBuffer);
-                free(logBuffer);
-            }
             printf("</dict>");
             printf("</plist>");
         }
-        exit(0);
-    });
-    __builtin_unreachable();
+    });
+    exit(0);
 }
 
 void _FAIL(const char* file, unsigned line, const char* format, ...)  {