You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Jonathan Gallimore <jo...@gmail.com> on 2019/04/16 10:02:19 UTC

Building commons-daemon / getenv() issue

Hi,

I've been looking at an issue where using a JNI library built with MSVC 14
with TomEE under Windows 2016 as a service with commons-daemon isn't able
to pick up environment variables set for the service using getenv().

I note from
https://github.com/apache/commons-daemon/tree/master/src/native/windows
that the build chain is VC 6 and Platform SDK for Windows Server 2003 R2 -
the build with that fails with and error on this line for me:
https://github.com/apache/commons-daemon/blob/master/src/native/windows/src/log.c#L61
-
if I change "10000000ULL" to "10000000i64", it compiles and links ok.

Doing a "dumpbin /headers prunsrv.exe" on the 1.1.0 release shows a linker
version of 9.00, and looking at the imports, it uses msvcrt.dll (as opposed
to msvcrt800.dll). I'd like to get my build chain as close as possible to
what's actually used to create the binaries that are distributed. Is there
a more recent buildchain (DDK?) that uses a later compiler/linker, but
still uses msvcrt.dll rather than msvcrtXX.dll?

While digging further into the issue, it appears that different runtime
DLLs effectively get their own copy of the environment, and the JNI library
built with VC14 is using ucrtbase.dll for getenv, while commons-daemon is
adding entries from to the environment using _wputenv in msvcrt.dll. The
attached code demonstrates this. This article looks related as well:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries?view=vs-2019

I have experimented with dynamically loading ucrtbase.dll and calling its
_wputenv() in addition to the _wputenv() call in msvcrt in commons-daemon,
and doing nothing if the library or function isn't present. I need to do
more testing on this, but my setInprocEnvironment()  function looks like
this:

static void setInprocEnvironment()
{
    LPWSTR p, e;
    HINSTANCE hinstUcrtLib;
    WPUTENV wputenv_ucrt;

    if (!SO_ENVIRONMENT)
        return;    /* Nothing to do */

    hinstUcrtLib = LoadLibrary(TEXT("ucrtbase.dll"));

    if (hinstUcrtLib != NULL) {
        wputenv_ucrt = (WPUTENV) GetProcAddress(hinstUcrtLib, "_wputenv");
    }

    for (p = SO_ENVIRONMENT; *p; p++) {
        e = apxExpandStrW(gPool, p);
        _wputenv(e);

        if (wputenv_ucrt != NULL) {
            wputenv_ucrt(e);
        }

        apxFree(e);
        while (*p)
            p++;
    }

    if (hinstUcrtLib != NULL) {
        FreeLibrary(hinstUcrtLib);
    }
}

This does work for my specific use-case, but I don't know if this is a
"good" approach, or something that the community would consider adopting.
I'd be grateful for feedback, and I'm happy to try different approaches and
create patches - I probably just need some pointers.

I did also try calling SetEnvironmentVariableW() (which didn't work,
although its possible I made a mistake, so I can certainly try it again).
Compiling commons-daemon with VC14 did appear to work, but that has the
issue of loading in specific versions of msvcrtXX.dll which sounds rather
undesirable.

Many thanks

Jon

Re: Building commons-daemon / getenv() issue

Posted by Jonathan Gallimore <jo...@gmail.com>.
Just following up on this one - Mark posted some feedback on my original
patch, which I think is now addressed.
https://issues.apache.org/jira/browse/DAEMON-401. If someone is able to
take a look, that would be much appreciated. I'm happy to make any other
changes, or run any necessary test cases.

Thanks!

Jon

On Tue, Apr 16, 2019 at 11:04 AM Jonathan Gallimore <
jonathan.gallimore@gmail.com> wrote:

> My attachment might be scrubbed off by the mailing list. Its available
> here: https://gist.github.com/jgallimore/aa84b1d580a8ba579e960a709ac1d235.
>
> Thanks
>
> Jon
>
> On Tue, Apr 16, 2019 at 11:02 AM Jonathan Gallimore <
> jonathan.gallimore@gmail.com> wrote:
>
>> Hi,
>>
>> I've been looking at an issue where using a JNI library built with MSVC
>> 14 with TomEE under Windows 2016 as a service with commons-daemon isn't
>> able to pick up environment variables set for the service using getenv().
>>
>> I note from
>> https://github.com/apache/commons-daemon/tree/master/src/native/windows
>> that the build chain is VC 6 and Platform SDK for Windows Server 2003 R2 -
>> the build with that fails with and error on this line for me:
>> https://github.com/apache/commons-daemon/blob/master/src/native/windows/src/log.c#L61 -
>> if I change "10000000ULL" to "10000000i64", it compiles and links ok.
>>
>> Doing a "dumpbin /headers prunsrv.exe" on the 1.1.0 release shows a
>> linker version of 9.00, and looking at the imports, it uses msvcrt.dll (as
>> opposed to msvcrt800.dll). I'd like to get my build chain as close as
>> possible to what's actually used to create the binaries that are
>> distributed. Is there a more recent buildchain (DDK?) that uses a later
>> compiler/linker, but still uses msvcrt.dll rather than msvcrtXX.dll?
>>
>> While digging further into the issue, it appears that different runtime
>> DLLs effectively get their own copy of the environment, and the JNI library
>> built with VC14 is using ucrtbase.dll for getenv, while commons-daemon is
>> adding entries from to the environment using _wputenv in msvcrt.dll. The
>> attached code demonstrates this. This article looks related as well:
>> https://docs.microsoft.com/en-us/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries?view=vs-2019
>>
>> I have experimented with dynamically loading ucrtbase.dll and calling its
>> _wputenv() in addition to the _wputenv() call in msvcrt in commons-daemon,
>> and doing nothing if the library or function isn't present. I need to do
>> more testing on this, but my setInprocEnvironment()  function looks like
>> this:
>>
>> static void setInprocEnvironment()
>> {
>>     LPWSTR p, e;
>>     HINSTANCE hinstUcrtLib;
>>     WPUTENV wputenv_ucrt;
>>
>>     if (!SO_ENVIRONMENT)
>>         return;    /* Nothing to do */
>>
>>     hinstUcrtLib = LoadLibrary(TEXT("ucrtbase.dll"));
>>
>>     if (hinstUcrtLib != NULL) {
>>         wputenv_ucrt = (WPUTENV) GetProcAddress(hinstUcrtLib, "_wputenv");
>>     }
>>
>>     for (p = SO_ENVIRONMENT; *p; p++) {
>>         e = apxExpandStrW(gPool, p);
>>         _wputenv(e);
>>
>>         if (wputenv_ucrt != NULL) {
>>             wputenv_ucrt(e);
>>         }
>>
>>         apxFree(e);
>>         while (*p)
>>             p++;
>>     }
>>
>>     if (hinstUcrtLib != NULL) {
>>         FreeLibrary(hinstUcrtLib);
>>     }
>> }
>>
>> This does work for my specific use-case, but I don't know if this is a
>> "good" approach, or something that the community would consider adopting.
>> I'd be grateful for feedback, and I'm happy to try different approaches and
>> create patches - I probably just need some pointers.
>>
>> I did also try calling SetEnvironmentVariableW() (which didn't work,
>> although its possible I made a mistake, so I can certainly try it again).
>> Compiling commons-daemon with VC14 did appear to work, but that has the
>> issue of loading in specific versions of msvcrtXX.dll which sounds rather
>> undesirable.
>>
>> Many thanks
>>
>> Jon
>>
>

Re: Building commons-daemon / getenv() issue

Posted by Jonathan Gallimore <jo...@gmail.com>.
My attachment might be scrubbed off by the mailing list. Its available
here: https://gist.github.com/jgallimore/aa84b1d580a8ba579e960a709ac1d235.

Thanks

Jon

On Tue, Apr 16, 2019 at 11:02 AM Jonathan Gallimore <
jonathan.gallimore@gmail.com> wrote:

> Hi,
>
> I've been looking at an issue where using a JNI library built with MSVC 14
> with TomEE under Windows 2016 as a service with commons-daemon isn't able
> to pick up environment variables set for the service using getenv().
>
> I note from
> https://github.com/apache/commons-daemon/tree/master/src/native/windows
> that the build chain is VC 6 and Platform SDK for Windows Server 2003 R2 -
> the build with that fails with and error on this line for me:
> https://github.com/apache/commons-daemon/blob/master/src/native/windows/src/log.c#L61 -
> if I change "10000000ULL" to "10000000i64", it compiles and links ok.
>
> Doing a "dumpbin /headers prunsrv.exe" on the 1.1.0 release shows a linker
> version of 9.00, and looking at the imports, it uses msvcrt.dll (as opposed
> to msvcrt800.dll). I'd like to get my build chain as close as possible to
> what's actually used to create the binaries that are distributed. Is there
> a more recent buildchain (DDK?) that uses a later compiler/linker, but
> still uses msvcrt.dll rather than msvcrtXX.dll?
>
> While digging further into the issue, it appears that different runtime
> DLLs effectively get their own copy of the environment, and the JNI library
> built with VC14 is using ucrtbase.dll for getenv, while commons-daemon is
> adding entries from to the environment using _wputenv in msvcrt.dll. The
> attached code demonstrates this. This article looks related as well:
> https://docs.microsoft.com/en-us/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries?view=vs-2019
>
> I have experimented with dynamically loading ucrtbase.dll and calling its
> _wputenv() in addition to the _wputenv() call in msvcrt in commons-daemon,
> and doing nothing if the library or function isn't present. I need to do
> more testing on this, but my setInprocEnvironment()  function looks like
> this:
>
> static void setInprocEnvironment()
> {
>     LPWSTR p, e;
>     HINSTANCE hinstUcrtLib;
>     WPUTENV wputenv_ucrt;
>
>     if (!SO_ENVIRONMENT)
>         return;    /* Nothing to do */
>
>     hinstUcrtLib = LoadLibrary(TEXT("ucrtbase.dll"));
>
>     if (hinstUcrtLib != NULL) {
>         wputenv_ucrt = (WPUTENV) GetProcAddress(hinstUcrtLib, "_wputenv");
>     }
>
>     for (p = SO_ENVIRONMENT; *p; p++) {
>         e = apxExpandStrW(gPool, p);
>         _wputenv(e);
>
>         if (wputenv_ucrt != NULL) {
>             wputenv_ucrt(e);
>         }
>
>         apxFree(e);
>         while (*p)
>             p++;
>     }
>
>     if (hinstUcrtLib != NULL) {
>         FreeLibrary(hinstUcrtLib);
>     }
> }
>
> This does work for my specific use-case, but I don't know if this is a
> "good" approach, or something that the community would consider adopting.
> I'd be grateful for feedback, and I'm happy to try different approaches and
> create patches - I probably just need some pointers.
>
> I did also try calling SetEnvironmentVariableW() (which didn't work,
> although its possible I made a mistake, so I can certainly try it again).
> Compiling commons-daemon with VC14 did appear to work, but that has the
> issue of loading in specific versions of msvcrtXX.dll which sounds rather
> undesirable.
>
> Many thanks
>
> Jon
>