summaryrefslogtreecommitdiffstats
path: root/third_party/tcmalloc/chromium/src/windows
diff options
context:
space:
mode:
authorglider@chromium.org <glider@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-21 10:55:10 +0000
committerglider@chromium.org <glider@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-21 10:55:10 +0000
commit5eac6029cdecb6e15a014f8185f0bac5e118418f (patch)
tree4027035c21cc7b68c448805bc580a8197d499bb8 /third_party/tcmalloc/chromium/src/windows
parent8741cfecae9a11360850b01e998cfbf9cc443f92 (diff)
downloadchromium_src-5eac6029cdecb6e15a014f8185f0bac5e118418f.zip
chromium_src-5eac6029cdecb6e15a014f8185f0bac5e118418f.tar.gz
chromium_src-5eac6029cdecb6e15a014f8185f0bac5e118418f.tar.bz2
Revert 47789 - The newer version of tcmalloc should fix the problems with running tcmalloc under Valgrind.
Review URL: http://codereview.chromium.org/1735024 TBR=willchan,antonm Review URL: http://codereview.chromium.org/2138002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47909 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tcmalloc/chromium/src/windows')
-rw-r--r--third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c13
-rw-r--r--third_party/tcmalloc/chromium/src/windows/config.h8
-rw-r--r--third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h14
-rw-r--r--third_party/tcmalloc/chromium/src/windows/nm-pdb.c9
-rw-r--r--third_party/tcmalloc/chromium/src/windows/patch_functions.cc328
5 files changed, 158 insertions, 214 deletions
diff --git a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
index 5c65a03..97b614b 100644
--- a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
+++ b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
@@ -48,12 +48,6 @@
#define SEARCH_CAP (1024*1024)
#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
-void usage() {
- fprintf(stderr, "usage: "
- "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n");
- fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n");
-}
-
int main(int argc, char *argv[]) {
DWORD error;
HANDLE process;
@@ -80,11 +74,10 @@ int main(int argc, char *argv[]) {
}
filename = argv[i+1];
i++; /* to skip over filename too */
- } else if (strcmp(argv[i], "--help") == 0) {
- usage();
- exit(0);
} else {
- usage();
+ fprintf(stderr, "usage: "
+ "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n");
+ fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n");
exit(1);
}
}
diff --git a/third_party/tcmalloc/chromium/src/windows/config.h b/third_party/tcmalloc/chromium/src/windows/config.h
index b5d9bb6..99de82c 100644
--- a/third_party/tcmalloc/chromium/src/windows/config.h
+++ b/third_party/tcmalloc/chromium/src/windows/config.h
@@ -261,12 +261,10 @@
// ---------------------------------------------------------------------
// Extra stuff not found in config.h.in
-// This must be defined before the windows.h is included. We need at
-// least 0x0400 for mutex.h to have access to TryLock, and at least
-// 0x0501 for patch_functions.cc to have access to GetModuleHandleEx.
-// (This latter is an optimization we could take out if need be.)
+// This must be defined before the windows.h is included. It's needed
+// for mutex.h, to give access to the TryLock method.
#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0501
+# define _WIN32_WINNT 0x0400
#endif
// We want to make sure not to ever try to #include heap-checker.h
diff --git a/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h
index 663b7f9..4b97b15 100644
--- a/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h
+++ b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h
@@ -61,8 +61,7 @@
#endif
#ifdef __cplusplus
-#include <new> // for std::nothrow_t
-
+#include <new> // for nothrow_t
extern "C" {
#endif
// Returns a human-readable version string. If major, minor,
@@ -93,15 +92,16 @@ extern "C" {
#ifdef __cplusplus
PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW;
PERFTOOLS_DLL_DECL void* tc_new(size_t size);
- PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
- const std::nothrow_t&) __THROW;
PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW;
- PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
- const std::nothrow_t&) __THROW;
PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
+ PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW;
+
+ PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
+ const std::nothrow_t&) __THROW;
PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
const std::nothrow_t&) __THROW;
- PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW;
+ PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
+ const std::nothrow_t&) __THROW;
PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
const std::nothrow_t&) __THROW;
}
diff --git a/third_party/tcmalloc/chromium/src/windows/nm-pdb.c b/third_party/tcmalloc/chromium/src/windows/nm-pdb.c
index 9beb21d..726d345 100644
--- a/third_party/tcmalloc/chromium/src/windows/nm-pdb.c
+++ b/third_party/tcmalloc/chromium/src/windows/nm-pdb.c
@@ -180,10 +180,6 @@ static void ShowSymbolInfo(HANDLE process, ULONG64 module_base) {
#endif
}
-void usage() {
- fprintf(stderr, "usage: nm-pdb [-C|--demangle] <module or filename>\n");
-}
-
int main(int argc, char *argv[]) {
DWORD error;
HANDLE process;
@@ -199,15 +195,12 @@ int main(int argc, char *argv[]) {
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) {
symopts |= SYMOPT_UNDNAME;
- } else if (strcmp(argv[i], "--help") == 0) {
- usage();
- exit(0);
} else {
break;
}
}
if (i != argc - 1) {
- usage();
+ fprintf(stderr, "usage: nm-pdb [-C|--demangle] <module or filename>\n");
exit(1);
}
filename = argv[i];
diff --git a/third_party/tcmalloc/chromium/src/windows/patch_functions.cc b/third_party/tcmalloc/chromium/src/windows/patch_functions.cc
index deb841b..c1ed37f 100644
--- a/third_party/tcmalloc/chromium/src/windows/patch_functions.cc
+++ b/third_party/tcmalloc/chromium/src/windows/patch_functions.cc
@@ -83,7 +83,6 @@
#endif
#include <windows.h>
-#include <stdio.h>
#include <malloc.h> // for _msize and _expand
#include <Psapi.h> // for EnumProcessModules, GetModuleInformation, etc.
#include <set>
@@ -97,6 +96,8 @@
// The maximum number of modules we allow to be in one executable
const int kMaxModules = 8182;
+// The maximum size of a module's basename
+const int kMaxModuleNameSize = 256;
// These are hard-coded, unfortunately. :-( They are also probably
// compiler specific. See get_mangled_names.cc, in this directory,
@@ -144,15 +145,13 @@ class LibcInfo {
LibcInfo() {
memset(this, 0, sizeof(*this)); // easiest way to initialize the array
}
+ bool SameAs(const LibcInfo& that) const;
+ bool SameAsModuleEntry(const ModuleEntryCopy& module_entry) const;
+
+ bool patched() const { return is_valid() && module_name_[0] != '\0'; }
+ const char* module_name() const { return is_valid() ? module_name_ : ""; }
- bool patched() const { return is_valid(); }
void set_is_valid(bool b) { is_valid_ = b; }
- // According to http://msdn.microsoft.com/en-us/library/ms684229(VS.85).aspx:
- // "The load address of a module (lpBaseOfDll) is the same as the HMODULE
- // value."
- HMODULE hmodule() const {
- return reinterpret_cast<HMODULE>(const_cast<void*>(module_base_address_));
- }
// Populates all the windows_fn_[] vars based on our module info.
// Returns false if windows_fn_ is all NULL's, because there's
@@ -168,6 +167,7 @@ class LibcInfo {
memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_));
this->module_base_address_ = that.module_base_address_;
this->module_base_size_ = that.module_base_size_;
+ memcpy(this->module_name_, that.module_name_, sizeof(module_name_));
}
enum {
@@ -207,6 +207,7 @@ class LibcInfo {
const void *module_base_address_;
size_t module_base_size_;
+ char module_name_[kMaxModuleNameSize];
public:
// These shouldn't have to be public, since only subclasses of
@@ -284,8 +285,10 @@ template<int> class LibcInfoWithPatchFunctions : public LibcInfo {
// This is a subset of MODDULEENTRY32, that we need for patching.
struct ModuleEntryCopy {
- LPVOID modBaseAddr; // the same as hmodule
+ LPVOID modBaseAddr;
DWORD modBaseSize;
+ HMODULE hModule;
+ TCHAR szModule[kMaxModuleNameSize];
// This is not part of MODDULEENTRY32, but is needed to avoid making
// windows syscalls while we're holding patch_all_modules_lock (see
// lock-inversion comments at patch_all_modules_lock definition, below).
@@ -294,16 +297,26 @@ struct ModuleEntryCopy {
ModuleEntryCopy() {
modBaseAddr = NULL;
modBaseSize = 0;
+ hModule = NULL;
+ strcpy(szModule, "<executable>");
for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++)
rgProcAddresses[i] = LibcInfo::static_fn(i);
}
- ModuleEntryCopy(const MODULEINFO& mi) {
+ ModuleEntryCopy(HANDLE hprocess, HMODULE hmodule, const MODULEINFO& mi) {
this->modBaseAddr = mi.lpBaseOfDll;
this->modBaseSize = mi.SizeOfImage;
+ this->hModule = hmodule;
+ // TODO(csilvers): we could make more efficient by calling these
+ // lazily (not until the vars are needed, which is often never).
+ // However, there's tricky business with calling windows functions
+ // inside the patch_all_modules_lock (see the lock inversion
+ // comments with the patch_all_modules_lock definition, below), so
+ // it's safest to do it all here, where no lock is needed.
+ ::GetModuleBaseNameA(hprocess, hmodule,
+ this->szModule, sizeof(this->szModule));
for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++)
- rgProcAddresses[i] = (GenericFnPtr)::GetProcAddress(
- reinterpret_cast<const HMODULE>(mi.lpBaseOfDll),
- LibcInfo::function_name(i));
+ rgProcAddresses[i] =
+ (GenericFnPtr)::GetProcAddress(hModule, LibcInfo::function_name(i));
}
};
@@ -466,6 +479,18 @@ const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = {
{ "FreeLibrary", NULL, NULL, (GenericFnPtr)&Perftools_FreeLibrary },
};
+bool LibcInfo::SameAs(const LibcInfo& that) const {
+ return (is_valid() &&
+ module_base_address_ == that.module_base_address_ &&
+ module_base_size_ == that.module_base_size_);
+}
+
+bool LibcInfo::SameAsModuleEntry(const ModuleEntryCopy& module_entry) const {
+ return (is_valid() &&
+ module_base_address_ == module_entry.modBaseAddr &&
+ module_base_size_ == module_entry.modBaseSize);
+}
+
bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) {
// First, store the location of the function to patch before
// patching it. If none of these functions are found in the module,
@@ -527,9 +552,10 @@ bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) {
CHECK(windows_fn_[kFree]);
CHECK(windows_fn_[kRealloc]);
- // OK, we successfully populated. Let's store our member information.
+ // OK, we successfully patched. Let's store our member information.
module_base_address_ = module_entry.modBaseAddr;
module_base_size_ = module_entry.modBaseSize;
+ strcpy(module_name_, module_entry.szModule);
return true;
}
@@ -610,6 +636,14 @@ void WindowsInfo::Unpatch() {
// You should hold the patch_all_modules_lock when calling this.
void PatchOneModuleLocked(const LibcInfo& me_info) {
+ // Double-check we haven't seen this module before.
+ for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
+ if (g_module_libcs[i]->SameAs(me_info)) {
+ fprintf(stderr, "%s:%d: FATAL PERFTOOLS ERROR: %s double-patched somehow.\n",
+ __FILE__, __LINE__, g_module_libcs[i]->module_name());
+ CHECK(false);
+ }
+ }
// If we don't already have info on this module, let's add it. This
// is where we're sad that each libcX has a different type, so we
// can't use an array; instead, we have to use a switch statement.
@@ -652,70 +686,52 @@ void PatchMainExecutableLocked() {
// patch_all_modules_lock, inside PatchAllModules().
static SpinLock patch_all_modules_lock(SpinLock::LINKER_INITIALIZED);
-// last_loaded: The set of modules that were loaded the last time
-// PatchAllModules was called. This is an optimization for only
-// looking at modules that were added or removed from the last call.
-static std::set<HMODULE> *g_last_loaded;
-
// Iterates over all the modules currently loaded by the executable,
-// according to windows, and makes sure they're all patched. Most
-// modules will already be in loaded_modules, meaning we have already
-// loaded and either patched them or determined they did not need to
-// be patched. Others will not, which means we need to patch them
-// (if necessary). Finally, we have to go through the existing
-// g_module_libcs and see if any of those are *not* in the modules
-// currently loaded by the executable. If so, we need to invalidate
-// them. Returns true if we did any work (patching or invalidating),
-// false if we were a noop. May update loaded_modules as well.
-// NOTE: you must hold the patch_all_modules_lock to access loaded_modules.
+// and makes sure they're all patched. For ones that aren't, we patch
+// them in. We also check that every module we had patched in the
+// past is still loaded, and update internal data structures if so.
+// We return true if this PatchAllModules did any work, false else.
bool PatchAllModules() {
std::vector<ModuleEntryCopy> modules;
bool made_changes = false;
const HANDLE hCurrentProcess = GetCurrentProcess();
- DWORD num_modules = 0;
+ MODULEINFO mi;
+ DWORD cbNeeded = 0;
HMODULE hModules[kMaxModules]; // max # of modules we support in one process
- if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules),
- &num_modules)) {
- num_modules = 0;
- }
- // EnumProcessModules actually set the bytes written into hModules,
- // so we need to divide to make num_modules actually be a module-count.
- num_modules /= sizeof(*hModules);
- if (num_modules >= kMaxModules) {
- printf("PERFTOOLS ERROR: Too many modules in this executable to try"
- " to patch them all (if you need to, raise kMaxModules in"
- " patch_functions.cc).\n");
- num_modules = kMaxModules;
+ if (::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules),
+ &cbNeeded)) {
+ for (int i = 0; i < cbNeeded / sizeof(*hModules); ++i) {
+ if (i >= kMaxModules) {
+ printf("PERFTOOLS ERROR: Too many modules in this executable to try"
+ " to patch them all (if you need to, raise kMaxModules in"
+ " patch_functions.cc).\n");
+ break;
+ }
+ if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi)))
+ modules.push_back(ModuleEntryCopy(hCurrentProcess, hModules[i], mi));
+ }
}
- // Now we handle the unpatching of modules we have in g_module_libcs
- // but that were not found in EnumProcessModules. We need to
- // invalidate them. To speed that up, we store the EnumProcessModules
- // output in a set.
- // At the same time, we prepare for the adding of new modules, by
- // removing from hModules all the modules we know we've already
- // patched (or decided don't need to be patched). At the end,
- // hModules will hold only the modules that we need to consider patching.
- std::set<HMODULE> currently_loaded_modules;
+ // Now do the actual patching and unpatching.
{
SpinLockHolder h(&patch_all_modules_lock);
- if (!g_last_loaded) g_last_loaded = new std::set<HMODULE>;
- // At the end of this loop, currently_loaded_modules contains the
- // full list of EnumProcessModules, and hModules just the ones we
- // haven't handled yet.
- for (int i = 0; i < num_modules; ) {
- currently_loaded_modules.insert(hModules[i]);
- if (g_last_loaded->count(hModules[i]) > 0) {
- hModules[i] = hModules[--num_modules]; // replace element i with tail
- } else {
- i++; // keep element i
- }
- }
- // Now we do the unpatching/invalidation.
for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
- if (g_module_libcs[i]->patched() &&
- currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) {
+ if (!g_module_libcs[i]->is_valid())
+ continue;
+ bool still_loaded = false;
+ for (std::vector<ModuleEntryCopy>::iterator it = modules.begin();
+ it != modules.end(); ++it) {
+ if (g_module_libcs[i]->SameAsModuleEntry(*it)) {
+ // Both g_module_libcs[i] and it are still valid. Mark it by
+ // removing it from the vector; mark g_module_libcs[i] by
+ // setting a bool.
+ modules.erase(it);
+ still_loaded = true;
+ break;
+ }
+ }
+ if (!still_loaded) {
// Means g_module_libcs[i] is no longer loaded (no me32 matched).
// We could call Unpatch() here, but why bother? The module
// has gone away, so nobody is going to call into it anyway.
@@ -723,28 +739,14 @@ bool PatchAllModules() {
made_changes = true;
}
}
- // Update the loaded module cache.
- g_last_loaded->swap(currently_loaded_modules);
- }
-
- // Now that we know what modules are new, let's get the info we'll
- // need to patch them. Note this *cannot* be done while holding the
- // lock, since it needs to make windows calls (see the lock-inversion
- // comments before the definition of patch_all_modules_lock).
- MODULEINFO mi;
- for (int i = 0; i < num_modules; i++) {
- if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi)))
- modules.push_back(ModuleEntryCopy(mi));
- }
- // Now we can do the patching of new modules.
- {
- SpinLockHolder h(&patch_all_modules_lock);
- for (std::vector<ModuleEntryCopy>::iterator it = modules.begin();
+ // We've handled all the g_module_libcs. Now let's handle the rest
+ // of the module-entries: those that haven't already been loaded.
+ for (std::vector<ModuleEntryCopy>::const_iterator it = modules.begin();
it != modules.end(); ++it) {
LibcInfo libc_info;
if (libc_info.PopulateWindowsFn(*it)) { // true==module has libc routines
- PatchOneModuleLocked(libc_info);
+ PatchOneModuleLocked(libc_info); // updates num_patched_modules
made_changes = true;
}
}
@@ -757,10 +759,6 @@ bool PatchAllModules() {
made_changes = true;
}
}
- // TODO(csilvers): for this to be reliable, we need to also take
- // into account if we *would* have patched any modules had they not
- // already been loaded. (That is, made_changes should ignore
- // g_last_loaded.)
return made_changes;
}
@@ -768,9 +766,59 @@ bool PatchAllModules() {
} // end unnamed namespace
// ---------------------------------------------------------------------
-// Now that we've done all the patching machinery, let's actually
-// define the functions we're patching in. Mostly these are
-// simple wrappers around the do_* routines in tcmalloc.cc.
+// PatchWindowsFunctions()
+// This is the function that is exposed to the outside world.
+// It should be called before the program becomes multi-threaded,
+// since main_executable_windows.Patch() is not thread-safe.
+// ---------------------------------------------------------------------
+
+void PatchWindowsFunctions() {
+ // This does the libc patching in every module, and the main executable.
+ PatchAllModules();
+ main_executable_windows.Patch();
+}
+
+#if 0
+// It's possible to unpatch all the functions when we are exiting.
+
+// The idea is to handle properly windows-internal data that is
+// allocated before PatchWindowsFunctions is called. If all
+// destruction happened in reverse order from construction, then we
+// could call UnpatchWindowsFunctions at just the right time, so that
+// that early-allocated data would be freed using the windows
+// allocation functions rather than tcmalloc. The problem is that
+// windows allocates some structures lazily, so it would allocate them
+// late (using tcmalloc) and then try to deallocate them late as well.
+// So instead of unpatching, we just modify all the tcmalloc routines
+// so they call through to the libc rountines if the memory in
+// question doesn't seem to have been allocated with tcmalloc. I keep
+// this unpatch code around for reference.
+
+void UnpatchWindowsFunctions() {
+ // We need to go back to the system malloc/etc at global destruct time,
+ // so objects that were constructed before tcmalloc, using the system
+ // malloc, can destroy themselves using the system free. This depends
+ // on DLLs unloading in the reverse order in which they load!
+ //
+ // We also go back to the default HeapAlloc/etc, just for consistency.
+ // Who knows, it may help avoid weird bugs in some situations.
+ main_executable_windows.Unpatch();
+ main_executable.Unpatch();
+ if (libc1.is_valid()) libc1.Unpatch();
+ if (libc2.is_valid()) libc2.Unpatch();
+ if (libc3.is_valid()) libc3.Unpatch();
+ if (libc4.is_valid()) libc4.Unpatch();
+ if (libc5.is_valid()) libc5.Unpatch();
+ if (libc6.is_valid()) libc6.Unpatch();
+ if (libc7.is_valid()) libc7.Unpatch();
+ if (libc8.is_valid()) libc8.Unpatch();
+}
+#endif
+
+// ---------------------------------------------------------------------
+// Now that we've done all the patching machinery, let's end the file
+// by actually defining the functions we're patching in. Mostly these
+// are simple wrappers around the do_* routines in tcmalloc.cc.
//
// In fact, we #include tcmalloc.cc to get at the tcmalloc internal
// do_* functions, the better to write our own hook functions.
@@ -981,107 +1029,19 @@ BOOL WINAPI WindowsInfo::Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress) {
lpBaseAddress);
}
-// g_load_map holds a copy of windows' refcount for how many times
-// each currently loaded module has been loaded and unloaded. We use
-// it as an optimization when the same module is loaded more than
-// once: as long as the refcount stays above 1, we don't need to worry
-// about patching because it's already patched. Likewise, we don't
-// need to unpatch until the refcount drops to 0. load_map is
-// maintained in LoadLibraryExW and FreeLibrary, and only covers
-// modules explicitly loaded/freed via those interfaces.
-static std::map<HMODULE, int>* g_load_map = NULL;
-
HMODULE WINAPI WindowsInfo::Perftools_LoadLibraryExW(LPCWSTR lpFileName,
HANDLE hFile,
DWORD dwFlags) {
- HMODULE rv;
- // Check to see if the modules is already loaded, flag 0 gets a
- // reference if it was loaded. If it was loaded no need to call
- // PatchAllModules, just increase the reference count to match
- // what GetModuleHandleExW does internally inside windows.
- if (::GetModuleHandleExW(0, lpFileName, &rv)) {
- return rv;
- } else {
- // Not already loaded, so load it.
- rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD))
- function_info_[kLoadLibraryExW].origstub_fn)(
- lpFileName, hFile, dwFlags);
- // This will patch any newly loaded libraries, if patching needs
- // to be done.
- PatchAllModules();
-
- return rv;
- }
+ HMODULE rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD))
+ function_info_[kLoadLibraryExW].origstub_fn)(
+ lpFileName, hFile, dwFlags);
+ PatchAllModules();
+ return rv;
}
BOOL WINAPI WindowsInfo::Perftools_FreeLibrary(HMODULE hLibModule) {
BOOL rv = ((BOOL (WINAPI *)(HMODULE))
function_info_[kFreeLibrary].origstub_fn)(hLibModule);
-
- // Check to see if the module is still loaded by passing the base
- // address and seeing if it comes back with the same address. If it
- // is the same address it's still loaded, so the FreeLibrary() call
- // was a noop, and there's no need to redo the patching.
- HMODULE owner = NULL;
- BOOL result = ::GetModuleHandleExW(
- (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
- (LPCWSTR)hLibModule,
- &owner);
- if (result && owner == hLibModule)
- return rv;
-
PatchAllModules(); // this will fix up the list of patched libraries
return rv;
}
-
-
-// ---------------------------------------------------------------------
-// PatchWindowsFunctions()
-// This is the function that is exposed to the outside world.
-// It should be called before the program becomes multi-threaded,
-// since main_executable_windows.Patch() is not thread-safe.
-// ---------------------------------------------------------------------
-
-void PatchWindowsFunctions() {
- // This does the libc patching in every module, and the main executable.
- PatchAllModules();
- main_executable_windows.Patch();
-}
-
-#if 0
-// It's possible to unpatch all the functions when we are exiting.
-
-// The idea is to handle properly windows-internal data that is
-// allocated before PatchWindowsFunctions is called. If all
-// destruction happened in reverse order from construction, then we
-// could call UnpatchWindowsFunctions at just the right time, so that
-// that early-allocated data would be freed using the windows
-// allocation functions rather than tcmalloc. The problem is that
-// windows allocates some structures lazily, so it would allocate them
-// late (using tcmalloc) and then try to deallocate them late as well.
-// So instead of unpatching, we just modify all the tcmalloc routines
-// so they call through to the libc rountines if the memory in
-// question doesn't seem to have been allocated with tcmalloc. I keep
-// this unpatch code around for reference.
-
-void UnpatchWindowsFunctions() {
- // We need to go back to the system malloc/etc at global destruct time,
- // so objects that were constructed before tcmalloc, using the system
- // malloc, can destroy themselves using the system free. This depends
- // on DLLs unloading in the reverse order in which they load!
- //
- // We also go back to the default HeapAlloc/etc, just for consistency.
- // Who knows, it may help avoid weird bugs in some situations.
- main_executable_windows.Unpatch();
- main_executable.Unpatch();
- if (libc1.is_valid()) libc1.Unpatch();
- if (libc2.is_valid()) libc2.Unpatch();
- if (libc3.is_valid()) libc3.Unpatch();
- if (libc4.is_valid()) libc4.Unpatch();
- if (libc5.is_valid()) libc5.Unpatch();
- if (libc6.is_valid()) libc6.Unpatch();
- if (libc7.is_valid()) libc7.Unpatch();
- if (libc8.is_valid()) libc8.Unpatch();
-}
-#endif