void ResolutionCandidate::resolveTypeConstructor(CallInfo& info) { SET_LINENO(fn); // Ignore tuple constructors; they were generated // with their type constructors. if (fn->hasFlag(FLAG_PARTIAL_TUPLE) == false) { CallExpr* typeConstructorCall = new CallExpr(astr("_type", fn->name)); for_formals(formal, fn) { if (formal->hasFlag(FLAG_IS_MEME) == false) { if (fn->_this->type->symbol->hasFlag(FLAG_TUPLE)) { if (formal->instantiatedFrom != NULL) { typeConstructorCall->insertAtTail(formal->type->symbol); } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) { typeConstructorCall->insertAtTail(paramMap.get(formal)); } } else { if (strcmp(formal->name, "outer") == 0 || formal->type == dtMethodToken) { typeConstructorCall->insertAtTail(formal); } else if (formal->instantiatedFrom != NULL) { SymExpr* se = new SymExpr(formal->type->symbol); NamedExpr* ne = new NamedExpr(formal->name, se); typeConstructorCall->insertAtTail(ne); } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) { SymExpr* se = new SymExpr(paramMap.get(formal)); NamedExpr* ne = new NamedExpr(formal->name, se); typeConstructorCall->insertAtTail(ne); } } } } info.call->insertBefore(typeConstructorCall); // If instead we call resolveCallAndCallee(typeConstructorCall) // then the line number reported in an error would change // e.g.: domains/deitz/test_generic_class_of_sparse_domain // or: classes/diten/multipledestructor resolveCall(typeConstructorCall); INT_ASSERT(typeConstructorCall->isResolved()); resolveFunction(typeConstructorCall->resolvedFunction()); fn->_this->type = typeConstructorCall->resolvedFunction()->retType; typeConstructorCall->remove(); }
void WTemplate::renderTemplateText(std::ostream& result, const WString& templateText) { std::string text; WApplication *app = WApplication::instance(); if (app && (encodeInternalPaths_ || app->session()->hasSessionIdInUrl())) { WFlags<RefEncoderOption> options; if (encodeInternalPaths_) options |= EncodeInternalPaths; if (app->session()->hasSessionIdInUrl()) options |= EncodeRedirectTrampoline; WString t = templateText; EncodeRefs(t, options); text = t.toUTF8(); } else text = templateText.toUTF8(); std::size_t lastPos = 0; std::vector<WString> args; std::vector<std::string> conditions; int suppressing = 0; for (std::size_t pos = text.find('$'); pos != std::string::npos; pos = text.find('$', pos)) { if (!suppressing) result << text.substr(lastPos, pos - lastPos); lastPos = pos; if (pos + 1 < text.length()) { if (text[pos + 1] == '$') { // $$ -> $ if (!suppressing) result << '$'; lastPos += 2; } else if (text[pos + 1] == '{') { std::size_t startName = pos + 2; std::size_t endName = text.find_first_of(" \r\n\t}", startName); args.clear(); std::size_t endVar = parseArgs(text, endName, args); if (endVar == std::string::npos) { LOG_ERROR("variable syntax error near \"" << text.substr(pos) << "\""); return; } std::string name = text.substr(startName, endName - startName); std::size_t nl = name.length(); if (nl > 2 && name[0] == '<' && name[nl - 1] == '>') { if (name[1] != '/') { std::string cond = name.substr(1, nl - 2); conditions.push_back(cond); if (suppressing || !conditionValue(cond)) ++suppressing; } else { std::string cond = name.substr(2, nl - 3); if (conditions.back() != cond) { LOG_ERROR("mismatching condition block end: " << cond); return; } conditions.pop_back(); if (suppressing) --suppressing; } } else { if (!suppressing) { std::size_t colonPos = name.find(':'); bool handled = false; if (colonPos != std::string::npos) { std::string fname = name.substr(0, colonPos); std::string arg0 = name.substr(colonPos + 1); args.insert(args.begin(), WString::fromUTF8(arg0)); if (resolveFunction(fname, args, result)) handled = true; else args.erase(args.begin()); } if (!handled) resolveString(name, args, result); } } lastPos = endVar + 1; } else { if (!suppressing) result << '$'; // $. -> $. lastPos += 1; } } else { if (!suppressing) result << '$'; // $ at end of template -> $ lastPos += 1; } pos = lastPos; } result << text.substr(lastPos); }
void printTrace() { SymInitialize(GetCurrentProcess(), NULL, TRUE); UINT32 maxframes = 62; UINT_PTR myFrames[62]; ZeroMemory(myFrames, sizeof(UINT_PTR) * maxframes); ULONG BackTraceHash; maxframes = CaptureStackBackTrace(0, maxframes, reinterpret_cast<PVOID*>(myFrames), &BackTraceHash); const UINT_PTR* pFrame = myFrames; const size_t frameSize = maxframes; UINT32 startIndex = 0; int unresolvedFunctionsCount = 0; IMAGEHLP_LINE sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static char stack_line[1024] = ""; bool isPrevFrameInternal = false; DWORD NumChars = 0; const size_t max_line_length = 512; const int resolvedCapacity = 62 * max_line_length; const size_t allocedBytes = resolvedCapacity * sizeof(char); char resolved[resolvedCapacity]; if (resolved) { ZeroMemory(resolved, allocedBytes); } HANDLE hProcess = GetCurrentProcess(); int resolvedLength = 0; // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < frameSize; frame++) { if (pFrame[frame] == 0) break; // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = pFrame[frame]; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + 256 * sizeof(char)]; LPCSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer); // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DWORD displacement = 0; BOOL foundline = SymGetLineFromAddr(hProcess, programCounter, &displacement, &sourceInfo); bool isFrameInternal = false; // show one allocation function for context if (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) { resolvedLength += NumChars; if (resolved) { strncat_s(resolved, resolvedCapacity, stack_line, NumChars); } } isPrevFrameInternal = isFrameInternal; if (!foundline) displacement = (DWORD)displacement64; NumChars = resolveFunction(programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof(stack_line)); if (NumChars > 0 && !isFrameInternal) { resolvedLength += NumChars; if (resolved) { strncat_s(resolved, resolvedCapacity, stack_line, NumChars); } } } // end for loop printLog(resolved); SymCleanup(GetCurrentProcess()); return; }
bool WTemplate::renderTemplateText(std::ostream& result, const WString& templateText) { errorText_ = ""; std::string text; if (encodeTemplateText_) text = encode(templateText.toUTF8()); else text = templateText.toUTF8(); std::size_t lastPos = 0; std::vector<WString> args; std::vector<std::string> conditions; int suppressing = 0; for (std::size_t pos = text.find('$'); pos != std::string::npos; pos = text.find('$', pos)) { if (!suppressing) result << text.substr(lastPos, pos - lastPos); lastPos = pos; if (pos + 1 < text.length()) { if (text[pos + 1] == '$') { // $$ -> $ if (!suppressing) result << '$'; lastPos += 2; } else if (text[pos + 1] == '{') { std::size_t startName = pos + 2; std::size_t endName = text.find_first_of(" \r\n\t}", startName); args.clear(); std::size_t endVar = parseArgs(text, endName, args); if (endVar == std::string::npos) { std::stringstream errorStream; errorStream << "variable syntax error near \"" << text.substr(pos) << "\""; errorText_ = errorStream.str(); LOG_ERROR(errorText_); return false; } std::string name = text.substr(startName, endName - startName); std::size_t nl = name.length(); if (nl > 2 && name[0] == '<' && name[nl - 1] == '>') { if (name[1] != '/') { std::string cond = name.substr(1, nl - 2); conditions.push_back(cond); if (suppressing || !conditionValue(cond)) ++suppressing; } else { std::string cond = name.substr(2, nl - 3); if (conditions.empty() || conditions.back() != cond) { std::stringstream errorStream; errorStream << "mismatching condition block end: " << cond; errorText_ = errorStream.str(); LOG_ERROR(errorText_); return false; } conditions.pop_back(); if (suppressing) --suppressing; } } else { if (!suppressing) { std::size_t colonPos = name.find(':'); bool handled = false; if (colonPos != std::string::npos) { std::string fname = name.substr(0, colonPos); std::string arg0 = name.substr(colonPos + 1); args.insert(args.begin(), WString::fromUTF8(arg0)); if (resolveFunction(fname, args, result)) handled = true; else args.erase(args.begin()); } if (!handled) resolveString(name, args, result); } } lastPos = endVar + 1; } else { if (!suppressing) result << '$'; // $. -> $. lastPos += 1; } } else { if (!suppressing) result << '$'; // $ at end of template -> $ lastPos += 1; } pos = lastPos; } result << text.substr(lastPos); return true; }
/* * Reduce this module with respect to the given interface. * - The interface suggests some of the uses of the functions, * so here we can generate special versions of those functions. * Generate a ComponentInterfaceTransform for clients to rewrite their * code to use the new API */ bool SpecializeComponent(Module& M, ComponentInterfaceTransform& T, SpecializationPolicy &policy, std::list<Function*>& to_add) { int rewrite_count = 0; const ComponentInterface& I = T.getInterface(); // TODO: What needs to be done? // - Should try to handle strings & arrays for (ComponentInterface::FunctionIterator ff = I.begin(), fe = I.end(); ff != fe; ++ff) { StringRef name = ff->first(); Function* func = resolveFunction(M, name); if (func == NULL || func->isDeclaration()) { // We don't specialize declarations because we don't own them continue; } for (ComponentInterface::CallIterator cc = I.call_begin(name), ce = I.call_end(name); cc != ce; ++cc) { const CallInfo* const call = *cc; const unsigned arg_count = call->args.size(); if (func->isVarArg()) { // TODO: I don't know how to specialize variable argument functions yet continue; } if (arg_count != func->getArgumentList().size()) { // Not referring to this function? // NOTE: I can't assert this equality because of the way that approximations occur continue; } SmallBitVector slice(arg_count); bool shouldSpecialize = policy.specializeOn(func, call->args.begin(), call->args.end(), slice); if (!shouldSpecialize) continue; std::vector<Value*> args; std::vector<unsigned> argPerm; args.reserve(arg_count); argPerm.reserve(slice.count()); for (unsigned i = 0; i < arg_count; i++) { if (slice.test(i)) { Type * paramType = func->getFunctionType()->getParamType(i); Value *concreteArg = call->args[i].concretize(M, paramType); args.push_back(concreteArg); assert(concreteArg->getType() == paramType && "Specializing function with concrete argument of wrong type!"); } else { args.push_back(NULL); argPerm.push_back(i); } } Function* nfunc = specializeFunction(func, args); nfunc->setLinkage(GlobalValue::ExternalLinkage); FunctionHandle rewriteTo = nfunc->getName(); T.rewrite(name, call, rewriteTo, argPerm); to_add.push_back(nfunc); rewrite_count++; } } if (rewrite_count > 0) { errs() << rewrite_count << " pending rewrites\n"; } return rewrite_count > 0; }
// Resolve - Creates a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. and // saves it for later retrieval. This is almost identical to Callstack::dump above. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showInternalFrames (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // int CallStack::resolve(BOOL showInternalFrames) { if (m_resolved) { // already resolved, no need to do it again // resolving twice may report an incorrect module for the stack frames // if the memory was leaked in a dynamic library that was already unloaded. return 0; } if (m_status & CALLSTACK_STATUS_STARTUPCRT) { // there is no need to resolve a leak that will not be reported return 0; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } int unresolvedFunctionsCount = 0; IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); bool skipStartupLeaks = !!(g_vld.GetOptions() & VLD_OPT_SKIP_CRTSTARTUP_LEAKS); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; bool isPrevFrameInternal = false; bool isDynamicInitializer = false; DWORD NumChars = 0; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); const size_t max_line_length = MAXREPORTLENGTH + 1; m_resolvedCapacity = m_size * max_line_length; const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR); m_resolved = new WCHAR[m_resolvedCapacity]; if (m_resolved) { ZeroMemory(m_resolved, allocedBytes); } // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; DWORD displacement = 0; // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); BOOL foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker); if (skipStartupLeaks && foundline && !isDynamicInitializer && !(m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) && isCrtStartupModule(sourceInfo.FileName)) { m_status |= CALLSTACK_STATUS_STARTUPCRT; delete[] m_resolved; m_resolved = NULL; m_resolvedCapacity = 0; m_resolvedLength = 0; return 0; } bool isFrameInternal = false; if (foundline && !showInternalFrames) { if (isInternalModule(sourceInfo.FileName)) { // Don't show frames in files internal to the heap. isFrameInternal = true; } } // show one allocation function for context if (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } isPrevFrameInternal = isFrameInternal; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE]; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (skipStartupLeaks && foundline && beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) { isDynamicInitializer = true; } if (!foundline) displacement = (DWORD)displacement64; NumChars = resolveFunction( programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof( stack_line )); if (NumChars > 0 && !isFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } } // end for loop m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT; return unresolvedFunctionsCount; }
// dump - Dumps a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showinternalframes (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const { // The stack was dumped already if (m_resolved) { dumpResolved(); return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; bool isPrevFrameInternal = false; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); // Iterate through each frame in the call stack. for (UINT32 frame = start_frame; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; BOOL foundline = FALSE; DWORD displacement = 0; DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker); bool isFrameInternal = false; if (foundline && !showInternalFrames) { if (isInternalModule(sourceInfo.FileName)) { // Don't show frames in files internal to the heap. isFrameInternal = true; } } // show one allocation function for context if (!isFrameInternal && isPrevFrameInternal) Print(stack_line); isPrevFrameInternal = isFrameInternal; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE]; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (!foundline) displacement = (DWORD)displacement64; DWORD NumChars = resolveFunction(programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof(stack_line)); UNREFERENCED_PARAMETER(NumChars); if (!isFrameInternal) Print(stack_line); } }
/* * Reduce this module with respect to the given interface. * - The interface suggests some of the uses of the functions, * so here we can generate special versions of those functions. * Generate a ComponentInterfaceTransform for clients to rewrite their * code to use the new API */ bool SpecializeComponent(Module& M, ComponentInterfaceTransform& T, SpecializationPolicy &policy, std::list<Function*>& to_add) { errs() << "SpecializeComponent()\n"; int rewrite_count = 0; const ComponentInterface& I = T.getInterface(); // TODO: What needs to be done? // - Should try to handle strings & arrays // Iterate through all functions in the interface of T for (ComponentInterface::FunctionIterator ff = I.begin(), fe = I.end(); ff != fe; ++ff) { StringRef name = ff->first(); Function* func = resolveFunction(M, name); if (func == NULL || func->isDeclaration()) { // We don't specialize declarations because we don't own them continue; } // Now iterate through all calls to func in the interface of T for (ComponentInterface::CallIterator cc = I.call_begin(name), ce = I.call_end(name); cc != ce; ++cc) { const CallInfo* const call = *cc; const unsigned arg_count = call->args.size(); if (func->isVarArg()) { // TODO: I don't know how to specialize variable argument functions yet continue; } if (arg_count != func->getArgumentList().size()) { // Not referring to this function? // NOTE: I can't assert this equality because of the way that approximations occur continue; } /* should we specialize? if yes then each bit in slice will indicate whether the argument is a specializable constant */ SmallBitVector slice(arg_count); bool shouldSpecialize = policy.specializeOn(func, call->args.begin(), call->args.end(), slice); if (!shouldSpecialize) continue; std::vector<Value*> args; std::vector<unsigned> argPerm; args.reserve(arg_count); argPerm.reserve(slice.count()); for (unsigned i = 0; i < arg_count; i++) { if (slice.test(i)) { Type * paramType = func->getFunctionType()->getParamType(i); Value *concreteArg = call->args[i].concretize(M, paramType); args.push_back(concreteArg); assert(concreteArg->getType() == paramType && "Specializing function with concrete argument of wrong type!"); } else { args.push_back(NULL); argPerm.push_back(i); } } /* args is a list of pointers to values -- if the pointer is NULL then that argument is not specialized -- if the pointer is not NULL then the argument will be/has been specialized to that value argsPerm is a list on integers; the indices of the non-special arguments args[i] = NULL iff i is in argsPerm for i < arg_count. */ Function* nfunc = specializeFunction(func, args); nfunc->setLinkage(GlobalValue::ExternalLinkage); FunctionHandle rewriteTo = nfunc->getName(); T.rewrite(name, call, rewriteTo, argPerm); to_add.push_back(nfunc); errs() << "Specialized " << name << " to " << rewriteTo << "\n"; #if 0 for (unsigned i = 0; i < arg_count; i++) { errs() << "i = " << i << ": slice[i] = " << slice[i] << " args[i] = " << args.at(i) << "\n"; } errs() << " argPerm = ["; for (unsigned i = 0; i < argPerm.size(); i++) { errs() << argPerm.at(i) << " "; } errs() << "]\n"; #endif rewrite_count++; } } if (rewrite_count > 0) { errs() << rewrite_count << " pending rewrites\n"; } return rewrite_count > 0; }