Re: pgsql: Add putenv support for msvcrt from Visual Studio 2013

From: Christian Ullrich <chris(at)chrullrich(dot)net>
To: Andrew Dunstan <andrew(at)dunslane(dot)net>, Magnus Hagander <magnus(at)hagander(dot)net>
Cc: pgsql-committers <pgsql-committers(at)postgresql(dot)org>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: pgsql: Add putenv support for msvcrt from Visual Studio 2013
Date: 2016-04-25 20:52:54
Message-ID: 2c5f9472-d0cc-df61-78e3-bc48909ffb59@chrullrich.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-committers pgsql-hackers

* Christian Ullrich wrote:

> * Andrew Dunstan wrote:

>> What if both are present? Is a release build prevented from loading a
>> debug dll and vice versa?
>
> Debug and release are simply two separate CRTs. If your process contains
> a module that needs the one, and another that needs the other, you will
> have both loaded at once.

pgwin32_putenv() is the gift that keeps giving.

According to its comment, it is not required that all modules exchanging
calls with postgres.exe have to be built with the same CRT version (100,
110, 120, etc.). Is it?

If not, the logic that remembers negative results from GetModuleHandle()
(i.e. gives up forever on each possible CRT once it does not find it) is
wrong even without considering the debug/release split. If we load a
compiled extension built with a CRT we have not seen yet, _after_ the
first call to pgwin32_putenv(), that module's CRT's view of its
environment will be frozen because we will never attempt to update it.

If that code is in there because it has some noticeable performance
advantage, the negative results could probably be reset in SQL LOAD,
rather than just not remembering them anymore.

This comment is also incomplete then:

/*
* Module loaded, but we did not find the function last time.
* We're not going to find it this time either...
*/

This else branch is also taken if the module handle is set to
INVALID_HANDLE_VALUE because the module was not found in a previous call.

If it can happen that a CRT DLL is unloaded before the process exits,
and we cached the module handle while it was loaded, and later
pgwin32_putenv() is called, that won't end well for the process. This
might be a bit far-fetched; I have to see if I can actually make it happen.

One situation I can think of where this could occur is if an extension
loaded with LOAD creates a COM in-proc server from a DLL built with yet
another CRT, and when that object is released, either FreeLibrary()
(transitively) or CoFreeUnusedLibraries() (directly) boots that CRT (if
they do; it's possible that a CRT, once loaded, stays loaded.)

Finally: A nonzero handle returned from GetModuleHandle() is not
something that needs to be CloseHandle()d. It is not actually a handle,
but a pointer to the base (load) address of the module, although the
documentation for GetModuleHandle() is careful not to admit that.

The value it is compared against to see whether we have seen the module
before should be NULL, not 0.

It's getting a bit late for me today, but I will do the necessary
experimentation and try to come up with a POC patch to fix whatever of
the above I can actually prove to be real. Should anyone know for sure
that I'm completely off track on something, better yet, everything,
please let me know.

I should finish thinking before posting, then I would not have to reply
to myself so often.

--
Christian

In response to

Responses

Browse pgsql-committers by date

  From Date Subject
Next Message Peter Eisentraut 2016-04-25 21:18:01 pgsql: pg_dump: Message style improvements
Previous Message Peter Eisentraut 2016-04-25 20:52:09 Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees.

Browse pgsql-hackers by date

  From Date Subject
Next Message Andres Freund 2016-04-25 20:57:20 Re: [BUGS] Breakage with VACUUM ANALYSE + partitions
Previous Message Peter Eisentraut 2016-04-25 20:52:09 Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees.