Loading...
--- dyld/dyld-750.6/testing/lib/test_support.cpp
+++ dyld/dyld-960/testing/lib/test_support.cpp
@@ -138,8 +138,10 @@
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);
@@ -154,9 +156,9 @@
};
// Okay, this is tricky. We need something with roughly he semantics of a weak def, but without using weak defs as their presence
-// m ay impact certain tests. Instead we do the following:
+// may impact certain tests. Instead we do the following:
//
-// 1. Embed a stuct containing a lock and a pointer to our global state object in eahc binary
+// 1. Embed a stuct containing a lock and a pointer to our global state object in each 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
@@ -224,7 +226,7 @@
}
_process::_process() : executablePath(nullptr), args(nullptr), env(nullptr), stdoutHandler(nullptr), stderrHandler(nullptr),
- crashHandler(nullptr), exitHandler(nullptr), pid(0), arch(currentArch), suspended(false), async(false) {}
+ crashHandler(nullptr), exitHandler(nullptr), arch(currentArch), suspended(false) {}
_process::~_process() {
if (stdoutHandler) { Block_release(stdoutHandler);}
if (stderrHandler) { Block_release(stderrHandler);}
@@ -240,7 +242,6 @@
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() {
@@ -376,9 +377,6 @@
posix_spawnattr_destroy(&attr);
if (!suspended) {
kill(pid, SIGCONT);
- }
- if (!async) {
- dispatch_block_wait(oneShotSemaphoreBlock, DISPATCH_TIME_FOREVER);
}
Block_release(oneShotSemaphoreBlock);
dispatch_release(queue);
@@ -455,6 +453,29 @@
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) {
@@ -474,12 +495,15 @@
}
}
});
+}
+
+void TestState::emitBegin() {
if (output == BATS) {
printf("[BEGIN]");
if (checkForLeaks) {
printf(" MallocStackLogging=1 MallocDebugReport=none");
}
- forEachEnvVar(environ, [this](const char* env, const char* val) {
+ forEachEnvVar(environ, [](const char* env, const char* val) {
if ((strncmp(env, "DYLD_", 5) == 0) || (strncmp(env, "TEST_", 5) == 0)) {
printf(" %s=%s", env, val);
}
@@ -492,57 +516,53 @@
}
}
-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) {
- 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);
- }
- }
- sState.store(state);
+ 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);
+// 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
+ }
}
assert(sState != nullptr);
return sState;
}
-
__attribute__((noreturn))
void TestState::runLeaks(void) {
auto testState = TestState::getState();
- pid_t pid = getpid();
+ pid_t currentPid = getpid();
char pidString[32];
- sprintf(&pidString[0], "%d", pid);
+ sprintf(&pidString[0], "%d", currentPid);
if (getuid() != 0) {
printf("Insufficient priviledges, skipping Leak check: %s\n", testState->testName);
exit(0);
@@ -596,7 +616,7 @@
if (checkForLeaks) {
runLeaks();
} else {
- _IOlock.withLock([this,&format,&args,&file,&line](){
+ _IOlock.withLock([this,&format,&args](){
if (output == Console) {
printf("[\033[0;32mPASS\033[0m] %s: ", testName);
vprintf(format, args);
@@ -623,12 +643,21 @@
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);
});
- exit(0);
- }
+ }
+ __builtin_unreachable();
}
void _PASS(const char* file, unsigned line, const char* format, ...) {
@@ -664,7 +693,6 @@
}
}
} 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\">");
@@ -672,14 +700,22 @@
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);
+ exit(0);
+ });
+ __builtin_unreachable();
}
void _FAIL(const char* file, unsigned line, const char* format, ...) {