Обсуждение: libpq causes segfault when share library unloaded

Поиск
Список
Период
Сортировка

libpq causes segfault when share library unloaded

От
Jim Studt
Дата:
============================================================================
                        POSTGRESQL BUG REPORT TEMPLATE
============================================================================


Your name               : Jim Studt
Your email address      : jim@federated.com


System Configuration
---------------------
  Architecture (example: Intel Pentium)         : Intel Pentium

  Operating System (example: Linux 2.0.26 ELF)  : Linux 2.2.13

  PostgreSQL version (example: PostgreSQL-6.5.2):   PostgreSQL-6.5.2

  Compiler used (example:  gcc 2.8.0)           : gcc 2.95.2 19991024


Please enter a FULL description of your problem:
------------------------------------------------
libpq will define an environment variable for PGCLIENTENCODING if
none is specified.  If libpq is a shared library that is dynamically
loaded, and it is subsequently unloaded then it leaves an entry in
the environ array pointing into unmapped memory which will cause
a segfault the next time the environment array is traversed.




Please describe a way to repeat the problem.   Please try to provide a
concise reproducible example, if at all possible:
----------------------------------------------------------------------

/*
** program to demonstrate segfault from a putenv in a
** dynamicall loaded library.
** Build with something like:  make breaklibpq LDLIBS=-ldl
** DO NOT link to libpq.
*/

#include <postgresql/libpq-fe.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

main()
{
    typedef PGconn *(*ConnFunc)();
    typedef int(*PQstatusType)();

    void *dl;
    ConnFunc func;
    PGconn *conn;
    PQstatusType statfunc;

    printf("initially getenv(PGCLIENTENCODING) is %08x\n",
       getenv("PGCLIENTENCODING"));

    /* load the libpq dynamically */
    dl = dlopen("libpq.so",RTLD_NOW);
    if ( !dl) {
    fprintf(stderr,"Failed to open libpq: %s\n", dlerror());
    exit(1);
    }

    /* find PQconnectdb */
    func = (ConnFunc)dlsym(dl,"PQconnectdb");
    if ( !func) {
    fprintf(stderr,"Failed to find PQconnectdb in libpq: %s\n",
        dlerror());
    exit(1);
    }

    /* find PQstatus */
    statfunc = (PQstatusType)dlsym(dl,"PQstatus");
    if ( !statfunc) {
    fprintf(stderr,"Failed to find PQstatus in libpq: %s\n",
        dlerror());
    exit(1);
    }

    /* call PQconnectdb */
    conn = (*func)("dbname=template1");
    if ( !conn || (*statfunc)(conn) == CONNECTION_BAD) {
    fprintf(stderr,"Failed to connect to template1\n");
    exit(1);
    }

    printf("after connect getenv(PGCLIENTENCODING) is %08x\n",
       getenv("PGCLIENTENCODING"));

    /* close the library, as reference this will unmap it */
    dlclose(dl);

    /* we should segfault in the upcoming getenv() call */
    printf("after close getenv(PGCLIENTENCODING) is %08x\n",
       getenv("PGCLIENTENCODING"));
}





If you know how this problem might be fixed, list the solution below:
---------------------------------------------------------------------
A library should either find a way to clean up its putenv changes
when unloaded or not make them.  I would lean toward keeping the
client encoding in a global variable for use within libpq (its only
used once over in PQmblen().  If it needs to be exposed to the client
then an API call should be added.

It may be possible to use special linker sections to arrange for
cleanup code when a library is unloaded, like C++ static destructors
use on some systems.  This would probably be a portability nightmare.

--
                                     Jim Studt, President
                                     The Federated Software Group, Inc.

Re: [BUGS] libpq causes segfault when share library unloaded

От
Tom Lane
Дата:
Jim Studt <jim@federated.com> writes:
> libpq will define an environment variable for PGCLIENTENCODING if
> none is specified.  If libpq is a shared library that is dynamically
> loaded, and it is subsequently unloaded then it leaves an entry in
> the environ array pointing into unmapped memory which will cause
> a segfault the next time the environment array is traversed.

Hmm.  Dynamically unloading a library can cause all sorts of problems,
of course, but the particular code you're complaining of is pretty
bletcherous anyway --- it's using a fixed-size buffer which seems mighty
risky.  I'm inclined to make it put the putenv() string into a malloc'd
buffer instead.  Would that solve the problem in your environment?

            regards, tom lane