The Wayback Machine - https://web.archive.org/web/20240703064627/https://github.com/python/cpython/issues/92828
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ctypes.CDLL fails on FreeBSD: ld-elf.so.1: Can't find module with TLS index 1 #92828

Open
yurivict opened this issue May 16, 2022 · 5 comments
Open
Labels
OS-freebsd topic-ctypes type-bug An unexpected behavior, bug, or error

Comments

@yurivict
Copy link

This code fails on FreeBSD 13 with Python-3.8:

import os
import sys
import ctypes
from ctypes.util import find_library

_RTLD_NOLOAD = os.RTLD_NOLOAD
_SYSTEM_UINT = ctypes.c_uint64 if sys.maxsize > 2 ** 32 else ctypes.c_uint32
_SYSTEM_UINT_HALF = ctypes.c_uint32 if sys.maxsize > 2 ** 32 else ctypes.c_uint16

class _dl_phdr_info(ctypes.Structure):
    _fields_ = [
        ("dlpi_addr", _SYSTEM_UINT),  # Base address of object
        ("dlpi_name", ctypes.c_char_p),  # path to the library
        ("dlpi_phdr", ctypes.c_void_p),  # pointer on dlpi_headers
        ("dlpi_phnum", _SYSTEM_UINT_HALF),  # number of elements in dlpi_phdr
    ]

def match_library_callback(info, size, data):
    print("match_library_callback")
    # Get the path of the current library
    filepath = info.contents.dlpi_name
    if filepath:
        filepath = filepath.decode("utf-8")

        # Store the library controller if it is supported and selected
        self._make_controller_from_path(filepath)
        return 0

libc_name = find_library("c")
print("libc_name="+libc_name)
libc = ctypes.CDLL(libc_name, mode=_RTLD_NOLOAD)

c_func_signature = ctypes.CFUNCTYPE(
            ctypes.c_int,  # Return type
            ctypes.POINTER(_dl_phdr_info),
            ctypes.c_size_t,
            ctypes.c_char_p,
)
c_match_library_callback = c_func_signature(match_library_callback)
data = ctypes.c_char_p(b"")

libc.dl_iterate_phdr(c_match_library_callback, data) # failing line

It fails with the message:

ld-elf.so.1: Can't find module with TLS index 1

This code is from the Python library threadpoolctl that fails with the same error message.

@vukitoso
Copy link

Did you manage to solve this problem? If so, how?

@ptrajdos
Copy link

ptrajdos commented Aug 6, 2023

Hi,
I've managed to replicate the issue in C (Freebsd 13.2, and GCC: 12.2.0, Clang 14.0.5).
It seems that loading libc via dlopen and then calling dl_iterate_phdr causes the problem.
I hope it will help someone.

Best Regards,
Pawel

#include <link.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

/**
 * mwe.c
 * Compile via: 
 * gcc -rdynamic mwe.c -o mwe -g -D_GNU_SOURCE
 * or
 * clang -rdynamic mwe.c -o mwe -g -D_GNU_SOURCE 
*/
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
	//A simple callback function
 	printf("Name: \"%s\" (%d segments)\n", info->dlpi_name, info->dlpi_phnum);
 	return 0;
}

typedef int (*lib_func)(int (*callback)(struct dl_phdr_info *, size_t, void *), void* data);

int call_from_libc(){
	/**
	 * Calls dl_iterate_phdr indirectly by loading libc via dlopen
	 * */
	void     *handle  = NULL;
	lib_func  func    = NULL;
	handle = dlopen("/lib/libc.so.7",RTLD_NOW|RTLD_NOLOAD);// Put the name of your libc shared object
	if (handle == NULL){
		fprintf(stderr, "Unable to open lib: %s\n", dlerror());
		return -1;
	 }
	func = dlsym(handle, "dl_iterate_phdr");

	if (func == NULL) {
		fprintf(stderr, "Unable to get symbol\n");
		return -1;
	}

	func(callback, NULL);
	return 0;
}

int main(int argc, char *argv[]) {
	printf("Direct call:\n");
 	dl_iterate_phdr(callback, NULL);//It works

	printf("Indirect call:\n");
 	call_from_libc();//It causes 'ld-elf.so.1: Can't find module with TLS index 1'

 	exit(EXIT_SUCCESS);
}

@yurivict
Copy link
Author

yurivict commented Aug 7, 2023

@ptrajdos Thank you very much for this testcase.
I created the FreeBSD bug report with this code.

@yurivict
Copy link
Author

yurivict commented Aug 7, 2023

The answer is:

 Konstantin Belousov freebsd_committer 2023-08-07 00:30:20 PDT

This is expected outcome, since libc only provides stubs to satisfy the static
linker.

In the test program, change the "/lib/libc.so.7" path into RTLD_DEFAULT. It
should work then.

@yurivict
Copy link
Author

yurivict commented Aug 9, 2023

libc in FreeBSD was modified such that the dl_iterate_phdr will be properly resolved.
This problem should be now fixed in FreeBSD 14 (CURRENT), and will be fixed in FreeBSD 13 after a week once this patch will be merged there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS-freebsd topic-ctypes type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants