Mail Archives: djgpp/2015/10/04/06:37:02
Am 01.10.2015 15:56, schrieb Ozkan Sezer (sezeroz AT gmail DOT com) [via djgpp AT delorie DOT com]:
> On 10/1/15, Juan Manuel Guerrero (juan DOT guerrero AT gmx DOT de) [via
> djgpp AT delorie DOT com]<djgpp AT delorie DOT com> wrote:
>> On Thursday, October 1, 2015 at 9:35:24 AM UTC+2, Ozkan Sezer
>> (sezeroz AT gmail DOT com) [via djgpp AT delorie DOT com] wrote:
>>> On 9/27/15, Ozkan Sezer<sezeroz AT gmail DOT com> wrote:
>>>> On 9/26/15, Juan Manuel Guerrero (juan DOT guerrero AT gmx DOT de) [via
>>>> djgpp AT delorie DOT com]<djgpp AT delorie DOT com> wrote:
>>>>> On Friday, September 25, 2015 at 7:21:47 PM UTC+2, Ozkan Sezer
>>>>> (sezeroz AT gmail DOT com) [via djgpp AT delorie DOT com] wrote:
>>>>>> On 9/25/15, Ozkan Sezer<sezeroz AT gmail DOT com> wrote:
>>>>>>> AFAICS, dlclose()ing of a dxe doesn't remove its dependency dxes
>>>>>>> along
>>>>>>> with it, which will result in unnecessarily occupied memory which
>>>>>>> may
>>>>>>> prove fatal upon multiple dlopen()/dlclose() of a dxe with deps.
>>>>>>> This
>>>>>>> needs addressing.
>>>>>>>
>>>>>>
>>>>>> My last argument was inaccurate and misleading. Here's better:
>>>>>>
>>>>>> One has a.dxe and b.dxe; a.dxe depends on b.dxe. Do dlopen a.dxe
>>>>>> and b.dxe is opened implicitly. Do dlcose a.dxe, and b.dxe stays
>>>>>> open still occupying its memory. The memory occupied by the unused
>>>>>> b.dxe might be needed by the app but will be unavailable to it.
>>>>>> Further dlopen calls for a.dxe will increment the refcount for b.dxe
>>>>>> which never gets decremented.
>>>>>
>>>>>
>>>>> Can you provide a minimal sample code to demonstrate the issue?
>>>>>
>>>>> Regards,
>>>>> Juan M. Guerrero
>>>>>
>>>>
>>>> =======================================
>>>>
>>>> $ cat 12.c
>>>> extern int my_func2();
>>>> int my_func1() {
>>>> return my_func2();
>>>> }
>>>> $ gcc -c 12.c
>>>> $ dxe3gen -o a.dxe -P b.dxe -U 12.o
>>>> $ dxe3gen --show-exp a.dxe
>>>> _my_func1
>>>> $ dxe3gen --show-dep a.dxe
>>>> b.dxe
>>>>
>>>> =======================================
>>>>
>>>> $ cat 13.c
>>>> int my_func2() {
>>>> return -1;
>>>> }
>>>> $ gcc -c 13.c
>>>> $ dxe3gen -o b.dxe 13.o
>>>> $ dxe3gen --show-exp b.dxe
>>>> _my_func2
>>>>
>>>> =======================================
>>>>
>>>> $ cat 11.c
>>>> #include<dlfcn.h>
>>>> #include<stdio.h>
>>>>
>>>> void *my_dxe1;
>>>> int (*my_f)();
>>>>
>>>> int main (void) {
>>>> my_dxe1 = dlopen("a.dxe",0);
>>>> if (!my_dxe1) {
>>>> printf("dlopen() failed\n");
>>>> return 1;
>>>> }
>>>> dlclose(my_dxe1);
>>>>
>>>> my_f = dlsym(RTLD_DEFAULT,"_my_func1");
>>>> if(!my_f) {
>>>> printf("a.dxe not loaded\n");
>>>> }
>>>> else {
>>>> printf("a.dxe:my_func1(): %p\n",my_f);
>>>> }
>>>>
>>>> my_f = dlsym(RTLD_DEFAULT,"_my_func2");
>>>> if(!my_f) {
>>>> printf("b.dxe not loaded\n");
>>>> }
>>>> else {
>>>> printf("b.dxe:my_func2(): %p\n",my_f);
>>>> printf("b.dxe:my_func2() returns: %d\n",my_f());
>>>> }
>>>>
>>>> return 0;
>>>> }
>>>>
>>>> $ gcc -Wall -W 11.c
>>>>
>>>> =======================================
>>>>
>>>> $ a.exe> a.log
>>>> $ cat a.log
>>>> a.dxe not loaded
>>>> b.dxe:my_func2(): 95830
>>>> b.dxe:my_func2() returns: -1
>>>>
>>>
>>> PING? Any ideas? (Sorry that I brought the issue
>>> but have no patch for it myself.)
>>
>>
>> An inspection of your sample code and dldemo.cpp shows that it seems to be
>> that it is the user's responsibility to explicitly dlclose every dlopen'ed
>> modules.
>
> The thing is, the dependency dxe, i.e. b.dxe in my example,
> is implicitly dlopen()ed and I won't ever have the handle for it.
>
>> This is what an inspection of dldemo.cpp shows.
>> This may not be what you expected from unix but I assume that no DJGPP
>> developer has really promised that the behaviour would be identical to unix
>> behaviour.
>> Neither less I will inspect the issue during week-end but I do not promise
>> that a fix will be possible.
>>
>
> Thanks.
>
> --
> O.S.
Below is a patch that will implement ref-counting for implicitly loaded modules
by other ones. Please not that this ref-counting only works for dlopen/dlclose.
There may be other loading mechanisms that suffer from the same issue and that
will not be fixed by this modification.
The patch is intended for the main branch but should work on v2_05_1 as well.
Regards,
Juan M. Guerrero
2015-10-03 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/src/libc/dxe/dlopen.c: Added reference counting support for implicitly loaded DXE modules by dlopen.
diff -aprNU5 djgpp.orig/src/libc/dxe/dlopen.c djgpp/src/libc/dxe/dlopen.c
--- djgpp.orig/src/libc/dxe/dlopen.c 2015-10-03 15:18:20 -29907
+++ djgpp/src/libc/dxe/dlopen.c 2015-10-04 11:40:00 -29907
@@ -36,14 +36,16 @@
#ifndef ELOOP
#define ELOOP EMLINK
#endif
+#define __DEBUG_DXE3__ 0 /* Prints struct __dxe_handle members. Always commited as 0. */
+
/* private stack */
-typedef struct stk_node {
+typedef struct __stk_node {
const char *name;
- struct stk_node *next;
+ struct __stk_node *next;
} stk_node;
/* Exported symbols table entry */
typedef struct
{
@@ -57,22 +59,29 @@ typedef struct
unsigned short n_rel_relocs;
unsigned short n_abs_relocs;
char name [1]; /* expanded as needed */
} __attribute__((packed)) unres_table_entry;
+/* This is a linked list of implizitly loaded dxe modules. */
+typedef struct __linked_list {
+ struct __dxe_handle *handle; /* Pointer to next implicitly open module by this module */
+ struct __linked_list *next; /* Next entry in list */
+} dxe_handle_list;
+
/* This is the private dxe_h structure */
typedef struct __dxe_handle
{
- struct __dxe_handle *next; /* Pointer to next module in chain */
- char fname[FILENAME_MAX]; /* Full module pathname */
- int mode; /* Module open mode */
- int inuse; /* In-use counter */
- int n_exp_syms; /* Number of entries in export table */
- exp_table_entry **exp_table; /* Exported symbols table */
- char *header; /* The resident portion of header */
- char *section; /* code+data+bss section */
- long _fini; /* finalization */
+ struct __dxe_handle *next; /* Pointer to next module in chain */
+ char fname[FILENAME_MAX]; /* Full module pathname */
+ int mode; /* Module open mode */
+ int in_use; /* In-use counter */
+ int n_exp_syms; /* Number of entries in export table */
+ exp_table_entry **exp_table; /* Exported symbols table */
+ char *header; /* The resident portion of header */
+ char *section; /* code+data+bss section */
+ long _fini; /* Finalization */
+ dxe_handle_list *implicit_handle_list; /* Linked list of implicitly open module by this module or NULL */
} dxe_handle, *dxe_h;
/* Last-resort symbol resolver */
void *(*_dlsymresolver) (const char *symname) = NULL;
/* Last-error unresolved symbol count */
@@ -110,10 +119,12 @@ void *dlopen(const char *filename, int m
char *discardable;
stk_node *node;
static stk_node *stk_top = NULL;
+ dxe_handle_list *implicitly_open_handle_list;
+
#ifndef __GNUC__
static int cleanup = 0;
#endif
_dl_unresolved_count = 0;
@@ -180,11 +191,11 @@ found:
/* Look through the loaded modules list */
for (cur = dxe_chain; cur; cur = cur->next)
if (!strcmp(realfn, cur->fname))
{
- cur->inuse++;
+ cur->in_use++;
return cur;
}
fh = OPEN(filename, OPENFLAGS);
if (fh < 0) return NULL;
@@ -202,13 +213,14 @@ found:
return NULL;
}
/* O.k, fill the module handle structure */
strcpy(dxe.fname, realfn);
- dxe.inuse = 1;
+ dxe.in_use = 1;
dxe.mode = mode;
dxe.n_exp_syms = dxehdr.n_exp_syms;
+ dxe.implicit_handle_list = NULL;
/* Read DXE tables and the data section */
hdrsize = dxehdr.symbol_offset - sizeof(dxehdr);
discardsize = dxehdr.dep_size + dxehdr.unres_size + dxehdr.nrelocs * sizeof(long);
if ((dxe.header = malloc(hdrsize + dxehdr.sec_size)) == NULL)
@@ -240,11 +252,11 @@ found:
/* Fill the unfilled portion of code+data+bss segment with zeros */
memset(dxe.section + dxehdr.sec_f_size, 0, dxehdr.sec_size - dxehdr.sec_f_size);
/* Load the dependencies */
scan = discardable;
- for (i = 0; i < dxehdr.n_deps; i++)
+ for (implicitly_open_handle_list = NULL, i = 0; i < dxehdr.n_deps; i++)
{
stk_node tmp;
tmp.name = realfn;
tmp.next = stk_top;
stk_top = &tmp;
@@ -252,14 +264,35 @@ found:
if (dlopen(scan, RTLD_GLOBAL) == NULL)
{
stk_top = tmp.next;
goto unrecoverable;
}
+ else
+ {
+ dxe_handle_list *next_handle_list;
+
+ stk_top = tmp.next;
- stk_top = tmp.next;
+ scan = strchr(scan, 0) + 1;
- scan = strchr(scan, 0) + 1;
+ /* Register all implicitly open modules by this one. */
+ if ((next_handle_list = malloc(sizeof(dxe_handle_list))) == NULL)
+ {
+ errno = ENOMEM;
+ goto midwayerror;
+ }
+ next_handle->handle = dxe_chain;
+ next_handle->next = NULL;
+
+ if (implicitly_open_handle_list)
+ {
+ implicitly_open_handle_list->next = next_handle_list;
+ implicitly_open_handle_list = implicitly_open_handle_list->next;
+ }
+ else
+ dxe.implicit_handle_list = implicitly_open_handle_list = next_handle_list;
+ }
}
/* Allright, now we're ready to resolve all unresolved symbols */
_dl_unresolved_count = dxehdr.n_unres_syms;
_dl_unresolved_symbol[0] = 0;
@@ -325,10 +358,50 @@ found:
errno = ENOMEM;
goto midwayerror;
}
memcpy(dxe_chain, &dxe, sizeof(dxe_handle));
+#if defined(__DEBUG_DXE3__) && __DEBUG_DXE3__ == 1
+ {
+ FILE *f = fopen("c:/tmp/dxe_chain.txt", "a");
+
+ if (f)
+ {
+ fprintf(f, "dxe_chain : 0x%p\n"
+ " next : 0x%p\n"
+ " fname : %s\n"
+ " mode : %s\n"
+ " in_use : %d\n"
+ " n_exp_syms : %d\n"
+ " exp_table : 0x%p\n",
+ dxe_chain, dxe_chain->next, dxe_chain->fname,
+ dxe_chain->mode == RTLD_LAZY ? "RTLD_LAZY" :
+ dxe_chain->mode == RTLD_NOW ? "RTLD_NOW" :
+ dxe_chain->mode == RTLD_LOCAL ? "RTLD_LOCAL" :
+ dxe_chain->mode == RTLD_GLOBAL ? "RTLD_GLOBAL" : "unknown",
+ dxe_chain->in_use, dxe_chain->n_exp_syms, dxe_chain->exp_table);
+ for (i = 0; i < dxe_chain->n_exp_syms; i++)
+ fprintf(f, " exp_table[%d]->offset : %ld\n"
+ " exp_table[%d]->name : %s\n",
+ i, dxe_chain->exp_table[i]->offset, i, dxe_chain->exp_table[i]->name);
+ fprintf(f, " header : 0x%p\n"
+ " section : 0x%p\n"
+ " _fini : %ld\n",
+ dxe_chain->header, dxe_chain->section, dxe_chain->_fini);
+ if ((implicitly_open_handle_list = dxe_chain->implicit_handle_list))
+ for (; implicitly_open_handle_list; implicitly_open_handle_list = implicitly_open_handle_list->next)
+ fprintf(f, " implicitly_open_handle_list: 0x%p\n"
+ " handle : 0x%p\n"
+ " handle->fname : %s\n\n",
+ implicitly_open_handle_list, implicitly_open_handle_list->handle, implicitly_open_handle_list->handle->fname);
+ else
+ fprintf(f, " implicitly_open_handle_list: 0x00000000\n\n");
+ fclose(f);
+ }
+ }
+#endif
+
#ifndef __GNUC__
if (!cleanup)
{
cleanup = !0;
atexit(_closeall);
@@ -348,11 +421,11 @@ midwayerror:
int dlclose(void *dxe)
{
if (!dxe)
return -1;
- if (--((dxe_h)dxe)->inuse)
+ if (--((dxe_h)dxe)->in_use)
return 0;
/* finalization */
if (((dxe_h)dxe)->_fini != -1)
((void (*) (void))(((dxe_h)dxe)->_fini + (long)((dxe_h)dxe)->section))();
@@ -361,10 +434,21 @@ int dlclose(void *dxe)
{
dxe_h *cur;
for (cur = &dxe_chain; *cur; cur = &(*cur)->next)
if (*cur == dxe)
{
+ /* Un-register all implicitly loaded modules by this module. */
+ dxe_handle_list *implicitly_open_handle_list = (*cur)->implicit_handle_list;
+ while (implicitly_open_handle_list)
+ {
+ dxe_handle_list *next_handle_list = implicitly_open_handle->next;
+
+ dlclose(implicitly_open_handle_list->handle);
+ free(implicitly_open_handle_list);
+ implicitly_open_handle_list = next_handle_list;
+ }
+
*cur = ((dxe_h)dxe)->next;
break;
}
}
- Raw text -