Tcl Source Code

View Ticket
Login
Ticket UUID: 1967630
Title: tclLoadDl.c dlerror() is not thread safe
Type: Bug Created on: 2008-05-20 04:15:19
Submitter: georgeps Assigned to: jan.nijtmans
Subsystem: 40. Dynamic Loading Severity: Minor
Priority: 5 Medium Last modified: 2026-10-28 21:07:40
Status: Closed Closed by: jan.nijtmans
Resolution: Fixed Closed on: 2026-10-28 21:07:40
Version: 9.1.0
Description:
According to the standard for dlerror(), it's not required to be thread-safe.  
http://www.opengroup.org/onlinepubs/009695399/functions/dlerror.html

I also checked several open source libc.  NetBSD and OpenBSD don't use thread-specific storage for dlerror messages, but the GNU/Linux glibc does.

Attached is a patch to fix the problem.  It drains the dlerror() first after entering the critical region.

The Linux usage suggested is slightly different than what BSD seems to suggest.  The glibc dlsym manual suggests using dlerror to indicate the success or failure of a dlsym(), rather than NULL from the return of dlsym(), because apparently dlsym() can return 0/NULL and still have succeeded (with some symbols).  So the logic should probably be changed further based on what the glibc docs say.

This is the example taken from the manual for dlsym:
 dlerror();    /* Clear any existing error */
 cosine = dlsym(handle, "cos");
 if ((error = dlerror()) != NULL)
   ...
  

I also added error handling to TclpFindSymbol().  It appears to be unfinished prior to this, or the usage expectations of it have changed, because in the HEAD it doesn't use the interp argument to report an error like the (outdated?) comments state.
User Comments:
georgeps added on 2008-05-20 11:15:19:

File Added - 278384: tclLoadDl-2.patch

nijtmans added on 2008-05-20 14:59:00:
Logged In: YES 
user_id=61031
Originator: NO

In functions like TclLoadFile and TclpLoadFile, TclpFindSymbol()
is used multiple times and is not expected to modify the interp
result. At least those functions need to be modified to reset
the interp result after the last TclpFindSymbol() call.

Further on, the same modification will be needed in tclLoadDyld.c
as well (if the Mac-implementation is not thread-safe), and the
TclpFindSymbol change is needed in tclLoadNext.c, tclLoadOSF.c,
tclLoadShl.c and tclWinLoad.c as well.

In practice, I doubt that this ever will be a practical
problem, because normally all libraries are loaded in a
single thread at start-up. But - strictly speaking - yes,
I agree that the mutex should be there and TclpFindSymbol
should leave an error-message in interp result as documented.

Regards,
            Jan Nijtmans

serhiy.storchaka added on 2026-10-25 11:49:46:

Reproduced on NetBSD 10.1 and OpenBSD 7.9, where the dlerror() state is process-wide: a failing [load] concurrent with a successful [load] in another thread gets the other thread's message or NULL, and NULL crashes in Tcl_ObjPrintf(). Linux, FreeBSD and macOS keep it per thread.

Proposed fix in branch unix-dlerror-mutex, based on the attached patch: a mutex from dlopen()/dlsym() until dlerror() has been read, and "unknown" for a NULL message. It only covers Tcl's own calls, not dlopen() by other code in the process.


jan.nijtmans added on 2026-10-28 21:07:40:

Fixed in [e0e0341124|trunk], core-9-0-branch and core-8-6-branch

Many thanks!


Attachments: