[unixODBC-dev] Right way to read odbc.ini file.

ZIGLIO, Frediano, VF-IT Frediano.Ziglio at vodafone.com
Fri Sep 10 13:27:01 BST 2004


> 
> On 10-Sep-2004 ZIGLIO, Frediano, VF-IT wrote:
> > In our driver (FreeTDS ODBC driver) in SQLConnect we read 
> odbc.ini using
> > SQLGetPrivateProfileString from libodbcinst.so. However I noted that
> > this lead to some leaks due to ini cache. SQLGetPrivateProfileString
> > it's also compiled in libodbc.so but it's not exported. 
> This lead to two
> > different caches (but I don't think it's a problem). The 
> real issue it's
> > that when our driver get unloaded (unixODBC calls lt_dlclose)
> > libodbcinst.so get unloaded but cache it's not freed... Perhaps you
> > should use atexit to free the cache at so unload ??
> 
> Just a quick one - atexit won't help. Memory is freed 
> automatically on program
> termination since the process dies. atexit won't help in a scenario
> SQLConnect/SQLDiconnect SQLConnect/SQLDisconnect. Anyway, the 
> cache is a cache
> of the ini file and has nothing to do with the driver but as 
> you say if FreeTDS
> loads libodbcinst, calls SQLGetPrivateProfileString and then 
> unloads libodbcinst
> its possible a ptr to the cache is lost and hence leaking.
> 
> Some platforms support __init and __fini functions in shared 
> objects precisely
> for doing this sort of thing but unfortunately, they all tend 
> to be a little
> different and in any case it is only a few platforms.
> 

I did a test in Linux and using atexit in dynamic library call my
function when I call dlclose. dlopen(3) under Linux tell that you can
use __attribute__((destructor)) to get a function called when you call
dlclose. However I don't think it's a so portable behaviour... either
_fini, __attribute__((destructor)) or atexit... I think a configure test
it's required.

Here you are the test:

test.c:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

typedef void * (*t_test_alloc)();
typedef void (*t_test_free)(void *p);

int main()
{
        t_test_alloc p_test_alloc;
        t_test_free  p_test_free;
        void *p;

        printf("load\n");
        fflush(stdout);
        void *so = dlopen("./so.so", RTLD_NOW);
        if (!so) {
                fprintf(stderr, "dlopen fail\n");
                return 1;
        }

        printf("symbols\n");
        fflush(stdout);
        p_test_alloc = (t_test_alloc) dlsym(so, "test_alloc");
        if (!p_test_alloc) {
                fprintf(stderr, "test_alloc not found\n");
                return 1;
        }

        p_test_free = (t_test_free) dlsym(so, "test_free");
        if (!p_test_free) {
                fprintf(stderr, "test_free not found\n");
                return 1;
        }

        printf("calling alloc\n");
        fflush(stdout);
        p = (*p_test_alloc)();

        printf("calling free\n");
        fflush(stdout);
        (*p_test_free)(p);

        printf("close so\n");
        fflush(stdout);
        dlclose(so);

        printf("exiting...\n");
        fflush(stdout);

        return 0;
}

so.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void *waste = NULL;
static void free_waste()
{
        printf("free_waste\n");
        fflush(stdout);
        free(waste);
}

void * test_alloc()
{
        atexit(free_waste);
        waste = malloc(100);
        printf("test_alloc\n");
        fflush(stdout);
        return strdup("test");
}

void test_free(void *p)
{
        printf("test_free\n");
        fflush(stdout);
        free(p);
}

Makefile:
CFLAGS=-Wall -O2 -g

all: so.so test

so.so: so.c
        gcc ${CFLAGS} -fPIC -DPIC -shared -o so.so so.c

test: test.c
        gcc ${CFLAGS} -o test test.c -ldl

clean:
        rm -rf test so.so

results:
$ ./test
load
symbols
calling alloc
test_alloc
calling free
test_free
close so
free_waste
exiting...

freddy77




More information about the unixODBC-dev mailing list