Skip to content

[BUG] RTLD.LOCAL has wrong value on Linux — should be 0, is 4 (RTLD_NOLOAD) #6410

@SultanovAR

Description

@SultanovAR

Bug description

Actual behavior

Actual behavior:

RTLD.LOCAL = 4 on Linux. This is RTLD_NOLOAD (from <bits/dlfcn.h>), which tells dlopen to not actually load the library — just check if it's already loaded. Using OwnedDLHandle(path, RTLD.NOW | RTLD.LOCAL) passes flags=6 to dlopen, which returns NULL, causing a segfault.

Verified via objdump: mov $0x6,%esi before call dlopen@plt.
Linux <bits/dlfcn.h> values:

RTLD_LAZY    = 0x001
RTLD_NOW     = 0x002
RTLD_NOLOAD  = 0x004  ← this is what RTLD.LOCAL currently maps to
RTLD_GLOBAL  = 0x100
RTLD_LOCAL   = 0x000  ← correct value (it's the default, no bit set)

From the Linux man page (man dlopen):

▎ RTLD_LOCAL
▎ This is the converse of RTLD_GLOBAL, and the default if neither flag is specified.
▎ Symbols defined in this shared object are not made available to resolve references
▎ in subsequently loaded shared objects.
Source: https://man7.org/linux/man-pages/man3/dlopen.3.html
And from <bits/dlfcn.h>:
#define RTLD_LOCAL 0 /* defined in glibc source */
Source: https://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h

Expected behavior

RTLD.LOCAL = 0 on Linux. RTLD_LOCAL is the default dlopen behavior — symbols are not exported to other shared libraries. It requires no flag bit; it's the absence of RTLD_GLOBAL.

Steps to reproduce

  # test_rtld.mojo
  from sys.ffi import OwnedDLHandle, RTLD
  from gpu.host import DeviceContext

  fn main() raises:
      var ctx = DeviceContext()
      var lib = OwnedDLHandle("/tmp/any_valid.so", RTLD.NOW | RTLD.LOCAL)
      print("ok")

Create a dummy .so to load

echo 'void dummy() {}' | gcc -shared -o /tmp/any_valid.so -x c -

This works (RTLD.NOW only, flags=2):

mojo run test_rtld_now.mojo

This segfaults (RTLD.NOW | RTLD.LOCAL, flags=6):

mojo run test_rtld.mojo

Confirmed via objdump that RTLD.NOW | RTLD.LOCAL produces mov $0x6,%esi (RTLD_NOW=2 | RTLD_NOLOAD=4) instead of mov $0x2,%esi (RTLD_NOW=2 | RTLD_LOCAL=0).

objdump -d test_rtld | grep -B5 "call.*dlopen" | grep "mov.*esi"
Output: mov $0x6,%esi

System information

Pixi version: 0.66.0
Platform: linux-64
Virtual packages: __glibc=2.41, __cuda=13.0, __archspec=icelake

Mojo: 0.26.1.0 (release)
mojo-compiler: 0.26.1.0
Channel: https://conda.modular.com/max

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingmojoIssues that are related to mojo

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions