Index: sanitizer_common.h
===================================================================
--- sanitizer_common.h
+++ sanitizer_common.h
@@ -548,8 +548,8 @@
 // executable or a shared object).
 class LoadedModule {
  public:
-  LoadedModule() : full_name_(nullptr), base_address_(0) {}
-  LoadedModule(const char *module_name, uptr base_address);
+  LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); }
+  void set(const char *module_name, uptr base_address);
   void clear();
   void addAddressRange(uptr beg, uptr end, bool executable);
   bool containsAddress(uptr address) const;
Index: sanitizer_common.cc
===================================================================
--- sanitizer_common.cc
+++ sanitizer_common.cc
@@ -250,10 +250,10 @@
 }
 #endif
 
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+void LoadedModule::set(const char *module_name, uptr base_address) {
+  clear();
   full_name_ = internal_strdup(module_name);
   base_address_ = base_address;
-  ranges_.clear();
 }
 
 void LoadedModule::clear() {
Index: sanitizer_linux_libcdep.cc
===================================================================
--- sanitizer_linux_libcdep.cc
+++ sanitizer_linux_libcdep.cc
@@ -436,9 +436,8 @@
     return 0;
   if (data->filter && !data->filter(module_name.data()))
     return 0;
-  void *mem = &data->modules[data->current_n];
-  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
-                                                   info->dlpi_addr);
+  LoadedModule &cur_module = data->modules[data->current_n];
+  cur_module.set(module_name.data(), info->dlpi_addr);
   data->current_n++;
   for (int i = 0; i < info->dlpi_phnum; i++) {
     const Elf_Phdr *phdr = &info->dlpi_phdr[i];
@@ -446,7 +445,7 @@
       uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
       uptr cur_end = cur_beg + phdr->p_memsz;
       bool executable = phdr->p_flags & PF_X;
-      cur_module->addAddressRange(cur_beg, cur_end, executable);
+      cur_module.addAddressRange(cur_beg, cur_end, executable);
     }
   }
   return 0;
Index: sanitizer_procmaps_common.cc
===================================================================
--- sanitizer_procmaps_common.cc
+++ sanitizer_procmaps_common.cc
@@ -130,7 +130,6 @@
       continue;
     if (filter && !filter(cur_name))
       continue;
-    void *mem = &modules[n_modules];
     // Don't subtract 'cur_beg' from the first entry:
     // * If a binary is compiled w/o -pie, then the first entry in
     //   process maps is likely the binary itself (all dynamic libs
@@ -143,8 +142,9 @@
     //   shadow memory of the tool), so the module can't be the
     //   first entry.
     uptr base_address = (i ? cur_beg : 0) - cur_offset;
-    LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
-    cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+    LoadedModule &cur_module = modules[n_modules];
+    cur_module.set(cur_name, base_address);
+    cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
     n_modules++;
   }
   return n_modules;
Index: sanitizer_procmaps_mac.cc
===================================================================
--- sanitizer_procmaps_mac.cc
+++ sanitizer_procmaps_mac.cc
@@ -176,8 +176,8 @@
         0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
       cur_module = &modules[n_modules - 1];
     } else {
-      void *mem = &modules[n_modules];
-      cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+      cur_module = &modules[n_modules];
+      cur_module->set(cur_name, cur_beg);
       n_modules++;
     }
     cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
Index: sanitizer_symbolizer.h
===================================================================
--- sanitizer_symbolizer.h
+++ sanitizer_symbolizer.h
@@ -137,10 +137,20 @@
   /// Platform-specific function for creating a Symbolizer object.
   static Symbolizer *PlatformInit();
 
-  virtual bool PlatformFindModuleNameAndOffsetForAddress(
-      uptr address, const char **module_name, uptr *module_offset) {
+  bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+                                         uptr *module_offset);
+  LoadedModule *FindModuleForAddress(uptr address);
+  virtual uptr PlatformGetListOfModules(LoadedModule *modules,
+                                        uptr max_modules) {
     UNIMPLEMENTED();
   }
+  // 16K loaded modules should be enough for everyone.
+  static const uptr kMaxNumberOfModuleContexts = 1 << 14;
+  LoadedModule modules_[kMaxNumberOfModuleContexts];
+  uptr n_modules_;
+  // If stale, need to reload the modules before looking up addresses.
+  bool modules_fresh_;
+
   // Platform-specific default demangler, must not return nullptr.
   virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); }
   virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); }
Index: sanitizer_symbolizer.cc
===================================================================
--- sanitizer_symbolizer.cc
+++ sanitizer_symbolizer.cc
@@ -95,8 +95,47 @@
   return last_match_;
 }
 
+bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
+                                                   const char **module_name,
+                                                   uptr *module_offset) {
+  LoadedModule *module = FindModuleForAddress(address);
+  if (module == 0)
+    return false;
+  *module_name = module->full_name();
+  *module_offset = address - module->base_address();
+  return true;
+}
+
+LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
+  bool modules_were_reloaded = false;
+  if (!modules_fresh_) {
+    for (uptr i = 0; i < n_modules_; i++)
+      modules_[i].clear();
+    n_modules_ = PlatformGetListOfModules(modules_, kMaxNumberOfModuleContexts);
+    CHECK_GT(n_modules_, 0);
+    CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
+    modules_fresh_ = true;
+    modules_were_reloaded = true;
+  }
+  for (uptr i = 0; i < n_modules_; i++) {
+    if (modules_[i].containsAddress(address)) {
+      return &modules_[i];
+    }
+  }
+  // Reload the modules and look up again, if we haven't tried it yet.
+  if (!modules_were_reloaded) {
+    // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+    // It's too aggressive to reload the list of modules each time we fail
+    // to find a module for a given address.
+    modules_fresh_ = false;
+    return FindModuleForAddress(address);
+  }
+  return 0;
+}
+
 Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
-    : module_names_(&mu_), tools_(tools), start_hook_(0), end_hook_(0) {}
+    : module_names_(&mu_), n_modules_(0), modules_fresh_(false), tools_(tools),
+      start_hook_(0), end_hook_(0) {}
 
 Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
     : sym_(sym) {
@@ -114,8 +153,7 @@
   const char *module_name;
   uptr module_offset;
   SymbolizedStack *res = SymbolizedStack::New(addr);
-  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
-                                                 &module_offset))
+  if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
     return res;
   // Always fill data about module name and offset.
   res->info.FillModuleInfo(module_name, module_offset);
@@ -133,8 +171,7 @@
   BlockingMutexLock l(&mu_);
   const char *module_name;
   uptr module_offset;
-  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
-                                                 &module_offset))
+  if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
     return false;
   info->Clear();
   info->module = internal_strdup(module_name);
@@ -153,8 +190,8 @@
                                              uptr *module_address) {
   BlockingMutexLock l(&mu_);
   const char *internal_module_name = nullptr;
-  if (!PlatformFindModuleNameAndOffsetForAddress(pc, &internal_module_name,
-                                                 module_address))
+  if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name,
+                                         module_address))
     return false;
 
   if (module_name)
Index: sanitizer_symbolizer_posix_libcdep.cc
===================================================================
--- sanitizer_symbolizer_posix_libcdep.cc
+++ sanitizer_symbolizer_posix_libcdep.cc
@@ -352,9 +352,14 @@
 class POSIXSymbolizer : public Symbolizer {
  public:
   explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> tools)
-      : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {}
+      : Symbolizer(tools) {}
 
  private:
+  uptr PlatformGetListOfModules(LoadedModule *modules,
+                                uptr max_modules) override {
+    return ::GetListOfModules(modules, max_modules, /* filter */ nullptr);
+  }
+
   const char *PlatformDemangle(const char *name) override {
     return DemangleCXXABI(name);
   }
@@ -365,52 +370,6 @@
     CacheBinaryName();
 #endif
   }
-
-  LoadedModule *FindModuleForAddress(uptr address) {
-    bool modules_were_reloaded = false;
-    if (!modules_fresh_) {
-      for (uptr i = 0; i < n_modules_; i++)
-        modules_[i].clear();
-      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
-                                    /* filter */ 0);
-      CHECK_GT(n_modules_, 0);
-      CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
-      modules_fresh_ = true;
-      modules_were_reloaded = true;
-    }
-    for (uptr i = 0; i < n_modules_; i++) {
-      if (modules_[i].containsAddress(address)) {
-        return &modules_[i];
-      }
-    }
-    // Reload the modules and look up again, if we haven't tried it yet.
-    if (!modules_were_reloaded) {
-      // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
-      // It's too aggressive to reload the list of modules each time we fail
-      // to find a module for a given address.
-      modules_fresh_ = false;
-      return FindModuleForAddress(address);
-    }
-    return 0;
-  }
-
-  bool PlatformFindModuleNameAndOffsetForAddress(uptr address,
-                                                 const char **module_name,
-                                                 uptr *module_offset) override {
-    LoadedModule *module = FindModuleForAddress(address);
-    if (module == 0)
-      return false;
-    *module_name = module->full_name();
-    *module_offset = address - module->base_address();
-    return true;
-  }
-
-  // 16K loaded modules should be enough for everyone.
-  static const uptr kMaxNumberOfModuleContexts = 1 << 14;
-  LoadedModule modules_[kMaxNumberOfModuleContexts];
-  uptr n_modules_;
-  // If stale, need to reload the modules before looking up addresses.
-  bool modules_fresh_;
 };
 
 static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
Index: sanitizer_symbolizer_win.cc
===================================================================
--- sanitizer_symbolizer_win.cc
+++ sanitizer_symbolizer_win.cc
@@ -129,21 +129,6 @@
     return name;
 }
 
-bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name,
-                                       uptr *module_offset) {
-  InitializeDbgHelpIfNeeded();
-
-  IMAGEHLP_MODULE64 mod_info;
-  internal_memset(&mod_info, 0, sizeof(mod_info));
-  mod_info.SizeOfStruct = sizeof(mod_info);
-  if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) {
-    *module_name = mod_info.ImageName;
-    *module_offset = addr - (uptr)mod_info.BaseOfImage;
-    return true;
-  }
-  return false;
-}
-
 // TODO(kuba.brecka): To be merged with POSIXSymbolizer.
 class WinSymbolizer : public Symbolizer {
  public:
@@ -151,10 +136,9 @@
       : Symbolizer(tools) {}
 
  private:
-  bool PlatformFindModuleNameAndOffsetForAddress(
-      uptr addr, const char **module_name, uptr *module_offset) override {
-    return ::FindModuleNameAndOffsetForAddress(addr, module_name,
-                                               module_offset);
+  uptr PlatformGetListOfModules(LoadedModule *modules,
+                                uptr max_modules) override {
+    return ::GetListOfModules(modules, max_modules, /* filter */nullptr);
   }
   const char *PlatformDemangle(const char *name) override { return name; }
   void PlatformPrepareForSandboxing() override { }
Index: sanitizer_win.cc
===================================================================
--- sanitizer_win.cc
+++ sanitizer_win.cc
@@ -349,7 +349,56 @@
 
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                       string_predicate_t filter) {
-  UNIMPLEMENTED();
+  HANDLE cur_process = GetCurrentProcess();
+
+  // Query the list of modules.  Start by assuming there are no more than 256
+  // modules and retry if that's not sufficient.
+  HMODULE *hmodules = 0;
+  uptr modules_buffer_size = sizeof(HMODULE) * 256;
+  DWORD bytes_required;
+  while (!hmodules) {
+    hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
+    CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
+                             &bytes_required));
+    if (bytes_required > modules_buffer_size) {
+      // Either there turned out to be more than 256 hmodules, or new hmodules
+      // could have loaded since the last try.  Retry.
+      UnmapOrDie(hmodules, modules_buffer_size);
+      hmodules = 0;
+      modules_buffer_size = bytes_required;
+    }
+  }
+
+  // |num_modules| is the number of modules actually present,
+  // |count| is the number of modules we return.
+  size_t nun_modules = bytes_required / sizeof(HMODULE),
+         count = 0;
+  for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
+    HMODULE handle = hmodules[i];
+    MODULEINFO mi;
+    if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
+      continue;
+
+    char module_name[MAX_PATH];
+    bool got_module_name =
+        GetModuleFileNameA(handle, module_name, sizeof(module_name));
+    if (!got_module_name)
+      module_name[0] = '\0';
+
+    if (filter && !filter(module_name))
+      continue;
+
+    uptr base_address = (uptr)mi.lpBaseOfDll;
+    uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+    LoadedModule &cur_module = modules[count];
+    cur_module.set(module_name, base_address);
+    // We add the whole module as one single address range.
+    cur_module.addAddressRange(base_address, end_address, /*executable*/ true);
+    count++;
+  }
+  UnmapOrDie(hmodules, modules_buffer_size);
+
+  return count;
 };
 
 #ifndef SANITIZER_GO
Index: tests/sanitizer_procmaps_test.cc
===================================================================
--- tests/sanitizer_procmaps_test.cc
+++ tests/sanitizer_procmaps_test.cc
@@ -37,8 +37,7 @@
   const char *binary_name = last_slash ? last_slash + 1 : argv0;
   MemoryMappingLayout memory_mapping(false);
   const uptr kMaxModules = 100;
-  LoadedModule *modules =
-      (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+  LoadedModule modules[kMaxModules];
   uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
   EXPECT_GT(n_modules, 0U);
   bool found = false;
@@ -51,7 +50,6 @@
     modules[i].clear();
   }
   EXPECT_TRUE(found);
-  free(modules);
 }
 
 }  // namespace __sanitizer