]> granicus.if.org Git - postgresql/commitdiff
Dump full memory maps around failing Windows reattach code.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Apr 2018 15:16:21 +0000 (11:16 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Apr 2018 15:16:21 +0000 (11:16 -0400)
This morning's results from buildfarm member dory make it pretty
clear that something is getting mapped into the just-freed space,
but not what that something is.  Replace my minimalistic probes
with a full dump of the process address space and module space,
based on Noah's work at
<20170403065106.GA2624300%40tornado.leadboat.com>

This is all (probably) to get reverted once we have fixed the
problem, but for now we need information.

Discussion: https://postgr.es/m/25495.1524517820@sss.pgh.pa.us

src/backend/Makefile
src/backend/port/win32_shmem.c
src/makefiles/Makefile.win32
src/tools/msvc/Mkvcbuild.pm

index 1aaf1ec2f59819f390631fd0b9323430df8a0221..f9215cdbb50e33b934875cd8818ffe23bad75a23 100644 (file)
@@ -79,7 +79,7 @@ libpostgres.a: postgres
 endif # cygwin
 
 ifeq ($(PORTNAME), win32)
-LIBS += -lsecur32
+LIBS += -lsecur32 -lpsapi
 
 postgres: $(OBJS) $(WIN32RES)
        $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) -Wl,--stack=$(WIN32_STACK_RLIMIT) -Wl,--export-all-symbols -Wl,--out-implib=libpostgres.a $(call expand_subsys,$(OBJS)) $(WIN32RES) $(LIBS) -o $@$(X)
index fe9cf3d1d6f9a573ddbd97cea26a76488cf9f26c..7402052ce61522ec63168c53b280b731401aa62b 100644 (file)
@@ -12,6 +12,8 @@
  */
 #include "postgres.h"
 
+#include <psapi.h>
+
 #include "miscadmin.h"
 #include "storage/dsm.h"
 #include "storage/ipc.h"
@@ -24,6 +26,88 @@ static Size UsedShmemSegSize = 0;
 static bool EnableLockPagesPrivilege(int elevel);
 static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
 
+/* Dump all modules loaded into proc */
+static void
+dumpdlls(HANDLE proc)
+{
+       HMODULE         dll[1024];
+       DWORD           size_used = 1;
+       int                     i,
+                               n;
+
+       if (!EnumProcessModules(proc, dll, sizeof(dll), &size_used))
+       {
+               elog(LOG, "EnumProcessModules failed: %lu", GetLastError());
+               return;
+       }
+       n = (int) (size_used / sizeof(*dll));
+       elog(LOG, "EnumProcessModules: %d modules in process 0x%p", n, proc);
+       for (i = 0; i < n; i++)
+       {
+               char            name[MAXPGPATH];
+
+               if (!GetModuleFileNameEx(proc, dll[i], name, sizeof(name)))
+                       sprintf(name, "GetModuleFileNameEx failed: %lu", GetLastError());
+               elog(LOG, "%d: 0x%p %s", i + 1, dll[i], name);
+       }
+}
+
+static const char *
+mi_type(DWORD code)
+{
+       switch (code)
+       {
+               case MEM_IMAGE:
+                       return "img";
+               case MEM_MAPPED:
+                       return "map";
+               case MEM_PRIVATE:
+                       return "prv";
+       }
+       return "???";
+}
+
+static const char *
+mi_state(DWORD code)
+{
+       switch (code)
+       {
+               case MEM_COMMIT:
+                       return "commit";
+               case MEM_FREE:
+                       return "free  ";
+               case MEM_RESERVE:
+                       return "reserv";
+       }
+       return "???";
+}
+
+static void
+dumpmem(const char *reason, HANDLE proc)
+{
+       char       *addr = 0;
+       MEMORY_BASIC_INFORMATION mi;
+
+       elog(LOG, "%s memory map", reason);
+       do
+       {
+               memset(&mi, 0, sizeof(mi));
+               if (!VirtualQueryEx(proc, addr, &mi, sizeof(mi)))
+               {
+                       if (GetLastError() == ERROR_INVALID_PARAMETER)
+                               break;
+                       elog(LOG, "VirtualQueryEx failed: %lu", GetLastError());
+                       break;
+               }
+               elog(LOG, "0x%p+0x%p %s (alloc 0x%p) %s",
+                        mi.BaseAddress, (void *) mi.RegionSize,
+                        mi_type(mi.Type), mi.AllocationBase, mi_state(mi.State));
+               addr += mi.RegionSize;
+       } while (addr > 0);
+
+       dumpdlls(proc);
+}
+
 /*
  * Generate shared memory segment name. Expand the data directory, to generate
  * an identifier unique for this data directory. Then replace all backslashes
@@ -388,19 +472,11 @@ PGSharedMemoryReAttach(void)
 {
        PGShmemHeader *hdr;
        void       *origUsedShmemSegAddr = UsedShmemSegAddr;
-       MEMORY_BASIC_INFORMATION previnfo;
-       MEMORY_BASIC_INFORMATION afterinfo;
-       DWORD           preverr;
-       DWORD           aftererr;
 
        Assert(UsedShmemSegAddr != NULL);
        Assert(IsUnderPostmaster);
 
-       /* Preliminary probe of region we intend to release */
-       if (VirtualQuery(UsedShmemSegAddr, &previnfo, sizeof(previnfo)) != 0)
-               preverr = 0;
-       else
-               preverr = GetLastError();
+       dumpmem("before VirtualFree", GetCurrentProcess());
 
        /*
         * Release memory region reservation that was made by the postmaster
@@ -409,48 +485,14 @@ PGSharedMemoryReAttach(void)
                elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
                         UsedShmemSegAddr, GetLastError());
 
-       /* Verify post-release state */
-       if (VirtualQuery(UsedShmemSegAddr, &afterinfo, sizeof(afterinfo)) != 0)
-               aftererr = 0;
-       else
-               aftererr = GetLastError();
+       dumpmem("after VirtualFree", GetCurrentProcess());
 
        hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
        if (!hdr)
        {
                DWORD           maperr = GetLastError();
-               MEMORY_BASIC_INFORMATION postinfo;
-               DWORD           posterr;
-
-               /* Capture post-failure state */
-               if (VirtualQuery(UsedShmemSegAddr, &postinfo, sizeof(postinfo)) != 0)
-                       posterr = 0;
-               else
-                       posterr = GetLastError();
-
-               if (preverr == 0)
-                       elog(LOG, "VirtualQuery(%p) before free reports region of size %zu, base %p, has state 0x%lx",
-                                UsedShmemSegAddr, previnfo.RegionSize,
-                                previnfo.AllocationBase, previnfo.State);
-               else
-                       elog(LOG, "VirtualQuery(%p) before free failed: error code %lu",
-                                UsedShmemSegAddr, preverr);
 
-               if (aftererr == 0)
-                       elog(LOG, "VirtualQuery(%p) after free reports region of size %zu, base %p, has state 0x%lx",
-                                UsedShmemSegAddr, afterinfo.RegionSize,
-                                afterinfo.AllocationBase, afterinfo.State);
-               else
-                       elog(LOG, "VirtualQuery(%p) after free failed: error code %lu",
-                                UsedShmemSegAddr, aftererr);
-
-               if (posterr == 0)
-                       elog(LOG, "VirtualQuery(%p) after map reports region of size %zu, base %p, has state 0x%lx",
-                                UsedShmemSegAddr, postinfo.RegionSize,
-                                postinfo.AllocationBase, postinfo.State);
-               else
-                       elog(LOG, "VirtualQuery(%p) after map failed: error code %lu",
-                                UsedShmemSegAddr, posterr);
+               dumpmem("after MapViewOfFileEx", GetCurrentProcess());
 
                elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
                         UsedShmemSegID, UsedShmemSegAddr, maperr);
@@ -597,5 +639,7 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
                return false;
        }
 
+       dumpmem("after reserve", hChild);
+
        return true;
 }
index 7abbd01971ad0837c9694e5fc8ba422ac0a82bdd..678371d5f2aa5825a4047459f2af85e3402ec502 100644 (file)
@@ -1,5 +1,7 @@
 # src/makefiles/Makefile.win32
 
+override CPPFLAGS+= -DPSAPI_VERSION=1
+
 ifdef PGXS
 BE_DLLLIBS= -L$(libdir) -lpostgres
 override CPPFLAGS+= -I$(includedir_server)/port/win32
index b2f5fd61853628fdea37cd3d85f2399268aaba55..ceac0add4eb1f3cbef95cfbd22233b1a30bceb8c 100644 (file)
@@ -174,8 +174,10 @@ sub mkvcbuild
                'repl_gram.y',             'syncrep_scanner.l',
                'syncrep_gram.y');
        $postgres->AddDefine('BUILDING_DLL');
+       $postgres->AddDefine('PSAPI_VERSION=1');
        $postgres->AddLibrary('secur32.lib');
        $postgres->AddLibrary('ws2_32.lib');
+       $postgres->AddLibrary('psapi.lib');
        $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
        $postgres->FullExportDLL('postgres.lib');