Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000982 [1003.1(2013)/Issue7+TC1] System Interfaces Editorial Clarification Requested 2015-08-31 19:41 2019-10-18 15:42
Reporter dalias View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Applied  
Name Rich Felker
Organization musl libc
User Reference
Section dlopen
Page Number 738
Line Number 24875
Interp Status ---
Final Accepted Text Note: 0003277
Summary 0000982: Ambiguity in dlopen's definition of "load order" for symbol resolution
Description Load order is defined as:

"Load order establishes an ordering among symbol definitions, such that the first definition loaded (including definitions from the process image file and any dependent executable object files loaded with it) has priority over executable object files added later (by dlopen())."

However, an ambiguity arises when an object is loaded as RTLD_LOCAL then later converted to RTLD_GLOBAL by a subsequent dlopen. Consider the case where libraries A and B both define a symbol "foo", and the following sequence of dlopen calls:

1. dlopen("A", RTLD_LOCAL)
2. dlopen("B", RTLD_GLOBAL)
3. dlopen("A", RTLD_GLOBAL)

After step 1, "foo" is undefined, because RTLD_LOCAL precludes making A's definition available.

After step 2, "foo" has a definition provided by B, as there is only one definition available.

After step 3, it's not clear what happens. A contains the first-loaded definition of "foo", and a strict literal reading would suggest that the definition in A should therefore have priority. However, as far as I know this neither matches historical implementations (tested against glibc) nor user expectations.

The alternate interpretation is that "loaded" should be read as meaning "loaded and made available". In that case, after step 3, the definition of "foo" would still be provided by B.
Desired Action Clarify the definition of load order to remove the ambiguity when an object originally loaded RTLD_LOCAL is loaded again with RTLD_GLOBAL, or explicitly state that it is unspecified or implementation-defined if there are historical implementations with conflicting behavior.
Tags tc3-2008
Attached Files

- Relationships

-  Notes
(0002846)
shware_systems (reporter)
2015-09-26 06:22
edited on: 2015-09-26 06:25

dlopen() has when RTLD_GLOBAL is specified the returned handle is the one to the global symbol table also returned when the file argument is NULL. When RTLD_LOCAL is specified a module specific handle that may implicitly load other modules also is returned, but this load and table does not affect the separate global table. In the example, the implementations are doing the proper thing, as foo from B is the first definition introduced to the global table. That another table also has a foo label visible does not affect that its load order was second globally so stays hidden. The main effect of loading local and then global is the global symbol merge routine can skip loading the module from storage, as long as it treats the symbol definitions already in memory as if they were freshly loaded.

When the application implicitly loads lib A, then the first dlopen() should return the global handle, and ignore that RTLD_LOCAL was specified. Then A's foo has priority over B's foo, assuming B wasn't also implicity loaded (then dependency order determines which gets loaded first and is visible). Both loads of A are redundant then, iow.

Suggested change, in Return Value:
 Upon successful completion, dlopen() shall return a symbol table handle.

to:
 Upon successful completion, dlopen() shall return a symbol table handle, the global table handle when the file argument is a null pointer, RTLD_GLOBAL is specified or when the file argument is implicitly loaded by the application; and a distinct per file handle when only RTLD_LOCAL is specified for all uses of the file argument.

(0002847)
shware_systems (reporter)
2015-09-26 22:09

Correction, to account for what dlclose() requires. Apologies for any confusion.

Suggested change, in Return Value:
 Upon successful completion, dlopen() shall return a symbol table handle.

to:
 Upon successful completion, dlopen() shall return a symbol table handle, the global table handle when the file argument is a null pointer. When a non-null file argument is used and RTLD_GLOBAL is specified or the referenced library is implicitly loaded by the application, a handle distinct from the global handle or representing a local view shall be returned suitable for use by dlclose() to access the symbols specific to that library in the global table. Use of these handles with dlsym() shall be as if the handle returned when the file argument is null is used. When RTLD_LOCAL is specified, a handle representing a logically separate table shall be returned. It is implementation-defined whether physical storage is allocated to represent this logical view separate from the storage required for the global table.
-----
I believe this does represent existing practice.
(0002848)
dalias (reporter)
2015-09-28 00:26

Neither comment 2846 nor 2847 seems to have anything to do with the issue posted. There is no question of what dlopen returns, and the suggested changes are contrary to both the intent and all historical practice. The question is about which symbol has precedence (as defined by "load order") in the global symbol table, not what dlopen returns.
(0002849)
shware_systems (reporter)
2015-09-28 04:31

The first paragraph explains it, you have 3 separate logical handles in the example, 2 referencing subsets of the global table, 1 a local table. For the global handles search starts at the top of the load order list of the application, for the local it starts with the module. While it's feasible because of the void * typing an implementation can return the same binary value for the third dlopen() the usage has to be as described.
(0002850)
dalias (reporter)
2015-09-28 15:51

I'm sorry if the original text I wrote was not sufficiently clear. The return values of the three dlopen calls are thrown away (and assumed to be successful for the sake of example). The question is about the status of a symbol in the global namespace and how it changes after each call to dlopen; this is what "load order" governs. The status in handles for particular modules is governed by "dependency order" and is not in question.
(0003277)
geoffclare (manager)
2016-06-30 16:02

On page 738 line 24877, after:
If RTLD_GLOBAL has been specified, the executable object file shall maintain the RTLD_GLOBAL status regardless of any previous or future specification of RTLD_LOCAL, as long as the executable object file remains in the address space (see dlclose()).
add:
If there was a previous specification of RTLD_LOCAL, it is unspecified whether relocations after the new specification of RTLD_GLOBAL are made as if the previous specification had been RTLD_GLOBAL or as if the the executable object file had not previously been loaded.

- Issue History
Date Modified Username Field Change
2015-08-31 19:41 dalias New Issue
2015-08-31 19:41 dalias Name => Rich Felker
2015-08-31 19:41 dalias Organization => musl libc
2015-08-31 19:41 dalias Section => dlopen
2015-08-31 19:41 dalias Page Number => unknown
2015-08-31 19:41 dalias Line Number => unknown
2015-09-26 06:22 shware_systems Note Added: 0002846
2015-09-26 06:25 shware_systems Note Edited: 0002846
2015-09-26 22:09 shware_systems Note Added: 0002847
2015-09-28 00:26 dalias Note Added: 0002848
2015-09-28 04:31 shware_systems Note Added: 0002849
2015-09-28 15:51 dalias Note Added: 0002850
2016-06-30 16:02 geoffclare Note Added: 0003277
2016-06-30 16:04 geoffclare Interp Status => ---
2016-06-30 16:04 geoffclare Final Accepted Text => Note: 0003277
2016-06-30 16:04 geoffclare Status New => Resolved
2016-06-30 16:04 geoffclare Resolution Open => Accepted As Marked
2016-06-30 16:04 geoffclare Tag Attached: tc3-2008
2016-06-30 16:07 geoffclare Page Number unknown => 738
2016-06-30 16:07 geoffclare Line Number unknown => 24875
2019-10-18 15:42 geoffclare Status Resolved => Applied


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker