More flexible presubmit handling

This commit is contained in:
Asher Baker 2019-01-05 21:35:23 +00:00
parent 967fe4d0fb
commit bf10d88fb4

View File

@ -382,6 +382,7 @@ class UploadThread: public IThread
int failed = 0; int failed = 0;
char path[512]; char path[512];
char metapath[512]; char metapath[512];
char presubmitToken[512];
char response[512]; char response[512];
while (dumps->MoreFiles()) { while (dumps->MoreFiles()) {
@ -405,12 +406,19 @@ class UploadThread: public IThread
metapath[0] = '\0'; metapath[0] = '\0';
} }
bool wantsUpload = PresubmitCrashDump(path); presubmitToken[0] = '\0';
PresubmitResponse presubmitResponse = PresubmitCrashDump(path, presubmitToken, sizeof(presubmitToken));
if (wantsUpload) { switch (presubmitResponse) {
bool uploaded = UploadCrashDump(path, metapath, response, sizeof(response)); case kPRLocalError:
failed++;
if (uploaded) { g_pSM->LogError(myself, "Accelerator failed to locally process crash dump");
if (log) fprintf(log, "Failed to locally process crash dump");
break;
case kPRRemoteError:
case kPRUploadCrashDumpAndMetadata:
case kPRUploadMetadataOnly:
if (UploadCrashDump((presubmitResponse == kPRUploadMetadataOnly) ? nullptr : path, metapath, presubmitToken, response, sizeof(response))) {
count++; count++;
g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response); g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response);
if (log) fprintf(log, "Uploaded crash dump: %s\n", response); if (log) fprintf(log, "Uploaded crash dump: %s\n", response);
@ -419,18 +427,22 @@ class UploadThread: public IThread
g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response); g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response);
if (log) fprintf(log, "Failed to upload crash dump: %s\n", response); if (log) fprintf(log, "Failed to upload crash dump: %s\n", response);
} }
} else { break;
case kPRDontUpload:
skip++; skip++;
g_pSM->LogError(myself, "Accelerator crash dump upload skipped by server"); g_pSM->LogError(myself, "Accelerator crash dump upload skipped by server");
if (log) fprintf(log, "Skipped due to server request\n"); if (log) fprintf(log, "Skipped due to server request\n");
break;
} }
if (libsys->PathExists(metapath)) { if (metapath[0]) {
unlink(metapath); unlink(metapath);
} }
unlink(path); unlink(path);
if (log) fflush(log);
dumps->NextEntry(); dumps->NextEntry();
} }
@ -449,7 +461,7 @@ class UploadThread: public IThread
} }
#if defined _LINUX #if defined _LINUX
bool UploadSymbolFile(const google_breakpad::CodeModule *module) { bool UploadSymbolFile(const google_breakpad::CodeModule *module, const char *presubmitToken) {
auto debugFile = module->debug_file(); auto debugFile = module->debug_file();
if (debugFile[0] != '/') { if (debugFile[0] != '/') {
return false; return false;
@ -487,6 +499,16 @@ class UploadThread: public IThread
// printf(">>> %s\n", output.c_str()); // printf(">>> %s\n", output.c_str());
IWebForm *form = webternet->CreateForm(); IWebForm *form = webternet->CreateForm();
const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
if (minidumpAccount && minidumpAccount[0]) form->AddString("UserID", minidumpAccount);
form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
if (presubmitToken && presubmitToken[0]) {
form->AddString("PresubmitToken", presubmitToken);
}
form->AddString("symbol_file", output.c_str()); form->AddString("symbol_file", output.c_str());
MemoryDownloader data; MemoryDownloader data;
@ -517,7 +539,7 @@ class UploadThread: public IThread
} }
#endif #endif
bool UploadModuleFile(const google_breakpad::CodeModule *module) { bool UploadModuleFile(const google_breakpad::CodeModule *module, const char *presubmitToken) {
const auto &codeFile = module->code_file(); const auto &codeFile = module->code_file();
#ifndef WIN32 #ifndef WIN32
@ -531,10 +553,19 @@ class UploadThread: public IThread
if (log) fprintf(log, "Submitting binary for %s\n", codeFile.c_str()); if (log) fprintf(log, "Submitting binary for %s\n", codeFile.c_str());
IWebForm *form = webternet->CreateForm(); IWebForm *form = webternet->CreateForm();
form->AddString("code_file_path", codeFile.c_str());
form->AddString("code_identifier", module->code_identifier().c_str()); const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
form->AddString("debug_file_path", module->debug_file().c_str()); if (minidumpAccount && minidumpAccount[0]) form->AddString("UserID", minidumpAccount);
form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
if (presubmitToken && presubmitToken[0]) {
form->AddString("PresubmitToken", presubmitToken);
}
form->AddString("debug_identifier", module->debug_identifier().c_str()); form->AddString("debug_identifier", module->debug_identifier().c_str());
form->AddString("code_identifier", module->code_identifier().c_str());
form->AddFile("code_file", codeFile.c_str()); form->AddFile("code_file", codeFile.c_str());
MemoryDownloader data; MemoryDownloader data;
@ -616,7 +647,7 @@ class UploadThread: public IThread
std::map<std::string, ModuleType, PathComparator> modulePathMap; std::map<std::string, ModuleType, PathComparator> modulePathMap;
bool InitModuleClassificationMap(const std::string &base) { bool InitModuleClassificationMap(const std::string &base) {
if (!modulePathMap.empty()) { if (!modulePathMap.empty()) {
return false; modulePathMap.clear();
} }
modulePathMap[base] = kMTGame; modulePathMap[base] = kMTGame;
@ -664,7 +695,15 @@ class UploadThread: public IThread
return path.substr(0, file_start); return path.substr(0, file_start);
} }
bool PresubmitCrashDump(const char *path) { enum PresubmitResponse {
kPRLocalError,
kPRRemoteError,
kPRDontUpload,
kPRUploadCrashDumpAndMetadata,
kPRUploadMetadataOnly,
};
PresubmitResponse PresubmitCrashDump(const char *path, char *tokenBuffer, size_t tokenBufferLength) {
google_breakpad::ProcessState processState; google_breakpad::ProcessState processState;
google_breakpad::ProcessResult processResult; google_breakpad::ProcessResult processResult;
google_breakpad::MinidumpProcessor minidumpProcessor(nullptr, nullptr); google_breakpad::MinidumpProcessor minidumpProcessor(nullptr, nullptr);
@ -675,7 +714,7 @@ class UploadThread: public IThread
} }
if (processResult != google_breakpad::PROCESS_OK) { if (processResult != google_breakpad::PROCESS_OK) {
return false; return kPRLocalError;
} }
int requestingThread = processState.requesting_thread(); int requestingThread = processState.requesting_thread();
@ -685,7 +724,7 @@ class UploadThread: public IThread
const google_breakpad::CallStack *stack = processState.threads()->at(requestingThread); const google_breakpad::CallStack *stack = processState.threads()->at(requestingThread);
if (!stack) { if (!stack) {
return false; return kPRLocalError;
} }
int frameCount = stack->frames()->size(); int frameCount = stack->frames()->size();
@ -728,9 +767,8 @@ class UploadThread: public IThread
IWebForm *form = webternet->CreateForm(); IWebForm *form = webternet->CreateForm();
const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount"); const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
if (minidumpAccount) form->AddString("UserID", minidumpAccount); if (minidumpAccount && minidumpAccount[0]) form->AddString("UserID", minidumpAccount);
form->AddString("GameDirectory", g_pSM->GetGameFolderName());
form->AddString("ExtensionVersion", SMEXT_CONF_VERSION); form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
form->AddString("CrashSignature", summaryLine.c_str()); form->AddString("CrashSignature", summaryLine.c_str());
@ -746,7 +784,7 @@ class UploadThread: public IThread
if (!uploaded) { if (!uploaded) {
if (log) fprintf(log, "Presubmit failed: %s (%d)\n", xfer->LastErrorMessage(), xfer->LastErrorCode()); if (log) fprintf(log, "Presubmit failed: %s (%d)\n", xfer->LastErrorMessage(), xfer->LastErrorCode());
return false; return kPRRemoteError;
} }
int responseSize = data.GetSize(); int responseSize = data.GetSize();
@ -761,28 +799,49 @@ class UploadThread: public IThread
if (responseSize < 2) { if (responseSize < 2) {
if (log) fprintf(log, "Presubmit response too short\n"); if (log) fprintf(log, "Presubmit response too short\n");
delete[] response; delete[] response;
return false; return kPRRemoteError;
} }
if (response[0] == 'E') { if (response[0] == 'E') {
if (log) fprintf(log, "Presubmit error: %s\n", &response[2]); if (log) fprintf(log, "Presubmit error: %s\n", &response[2]);
delete[] response; delete[] response;
return false; return kPRRemoteError;
} }
bool submitCrash = (response[0] == 'Y'); PresubmitResponse presubmitResponse = kPRRemoteError;
if (response[0] == 'Y') presubmitResponse = kPRUploadCrashDumpAndMetadata;
else if (response[0] == 'N') presubmitResponse = kPRDontUpload;
else if (response[0] == 'M') presubmitResponse = kPRUploadMetadataOnly;
else return kPRRemoteError;
if (response[1] != '|') { if (response[1] != '|') {
if (log) fprintf(log, "Response delimiter missing\n"); if (log) fprintf(log, "Response delimiter missing\n");
delete[] response; delete[] response;
return false; return kPRRemoteError;
} }
unsigned int responseCount = responseSize - 2; unsigned int responseCount = responseSize - 2;
if (responseCount < moduleCount) { if (responseCount < moduleCount) {
if (log) fprintf(log, "Response module list doesn't match sent list (%d < %d)\n", responseCount, moduleCount); if (log) fprintf(log, "Response module list doesn't match sent list (%d < %d)\n", responseCount, moduleCount);
delete[] response; delete[] response;
return false; return presubmitResponse;
}
// There was a presubmit token included.
if (tokenBuffer && responseCount > moduleCount && response[2 + moduleCount] == '|') {
int tokenStart = 2 + moduleCount + 1;
int tokenEnd = tokenStart;
while (tokenEnd < responseSize && response[tokenEnd] != '|') {
tokenEnd++;
}
size_t tokenLength = tokenEnd - tokenStart;
if (tokenLength < tokenBufferLength) {
strncpy(tokenBuffer, &response[tokenStart], tokenLength);
tokenBuffer[tokenLength] = '\0';
}
if (log) fprintf(log, "Got a presubmit token from server: %s\n", tokenBuffer);
} }
auto mainModule = processState.modules()->GetMainModule(); auto mainModule = processState.modules()->GetMainModule();
@ -800,8 +859,13 @@ class UploadThread: public IThread
bool canBinarySubmit = !binarySubmitOption || (tolower(binarySubmitOption[0]) == 'y' || binarySubmitOption[0] == '1'); bool canBinarySubmit = !binarySubmitOption || (tolower(binarySubmitOption[0]) == 'y' || binarySubmitOption[0] == '1');
for (unsigned int moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) { for (unsigned int moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
bool submitSymbols = (response[2 + moduleIndex] == 'Y'); bool submitSymbols = false;
bool submitBinary = (response[2 + moduleIndex] == 'U'); bool submitBinary = (response[2 + moduleIndex] == 'U');
#if defined _LINUX
submitSymbols = (response[2 + moduleIndex] == 'Y');
#endif
if (!submitSymbols && !submitBinary) { if (!submitSymbols && !submitBinary) {
continue; continue;
} }
@ -833,32 +897,38 @@ class UploadThread: public IThread
} }
if (canBinarySubmit && submitBinary) { if (canBinarySubmit && submitBinary) {
UploadModuleFile(module); UploadModuleFile(module, tokenBuffer);
} }
#if defined _LINUX #if defined _LINUX
if (submitSymbols) { if (submitSymbols) {
UploadSymbolFile(module); UploadSymbolFile(module, tokenBuffer);
} }
#endif #endif
} }
delete[] response; delete[] response;
return submitCrash; return presubmitResponse;
} }
bool UploadCrashDump(const char *path, const char *metapath, char *response, int maxlen) { bool UploadCrashDump(const char *path, const char *metapath, const char *presubmitToken, char *response, int maxlen) {
IWebForm *form = webternet->CreateForm(); IWebForm *form = webternet->CreateForm();
const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount"); const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
if (minidumpAccount) form->AddString("UserID", minidumpAccount); if (minidumpAccount && minidumpAccount[0]) form->AddString("UserID", minidumpAccount);
form->AddString("GameDirectory", g_pSM->GetGameFolderName()); form->AddString("GameDirectory", crashGameDirectory);
form->AddString("ExtensionVersion", SMEXT_CONF_VERSION); form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
form->AddFile("upload_file_minidump", path); if (presubmitToken && presubmitToken[0]) {
form->AddString("PresubmitToken", presubmitToken);
}
if (metapath[0]) { if (path && path[0]) {
form->AddFile("upload_file_minidump", path);
}
if (metapath && metapath[0]) {
form->AddFile("upload_file_metadata", metapath); form->AddFile("upload_file_metadata", metapath);
} }