{"id":18562477,"url":"https://github.com/replit/replit_rtld_loader","last_synced_at":"2025-05-15T17:36:07.205Z","repository":{"id":222555044,"uuid":"748717076","full_name":"replit/replit_rtld_loader","owner":"replit","description":"A dynamic runtime shared library loader for Repls that supports system dependency assistance and handles binary segregation by Nix channel.","archived":false,"fork":false,"pushed_at":"2024-04-16T14:31:59.000Z","size":334,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-02-17T12:45:37.355Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/replit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-26T16:01:00.000Z","updated_at":"2024-07-18T01:19:20.000Z","dependencies_parsed_at":"2024-04-16T15:46:10.912Z","dependency_job_id":"6d57127c-872f-4a69-b734-74d1193ad7cf","html_url":"https://github.com/replit/replit_rtld_loader","commit_stats":null,"previous_names":["replit/replit_rtld_loader"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Freplit_rtld_loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Freplit_rtld_loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Freplit_rtld_loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replit%2Freplit_rtld_loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/replit","download_url":"https://codeload.github.com/replit/replit_rtld_loader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254388492,"owners_count":22063064,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T22:09:52.546Z","updated_at":"2025-05-15T17:36:07.168Z","avatar_url":"https://github.com/replit.png","language":"C","readme":"# Replit RTLD Loader\n\nThe Replit RTLD Loader allows dynamically loaded shared libraries (.so)\nto work seamlessly in Repls. It uses\nthe [rtld-audit API](https://man7.org/linux/man-pages/man7/rtld-audit.7.html)\nto observe a process's library loading activities. When the native loader ld-linux\nfails to find a library, RTLD loader steps in resolves the desired library using\ndirectories in the `REPLIT_LD_LIBRARY_PATH` variable. It is a better alternative\nthan using `LD_LIBRARY_PATH` because rather than overriding the default behavior\nof the system loader, it acts as a fallback.\n\n## Background and Motivation\n\nAt Replit we use Nix to deliver almost all our software to users. However, we noticed\nusers experiencing programs crashing with errors like these:\n\n```\nsymbol lookup error: /nix/store/dg8mpqqykmw9c7l0bgzzb5znkymlbfjw-glibc-2.37-8/lib/libc.so.6: undefined symbol: _dl_audit_symbind_alt, version GLIBC_PRIVATE\n```\n\n```\n/nix/store/dg8mpqqykmw9c7l0bgzzb5znkymlbfjw-glibc-2.37-8/lib/libm.so.6: version `GLIBC_2.38' not found (required by /nix/store/8w6mm5q1n7i7cs1933im5vkbgvjlglfn-python3-3.10.13/lib/libpython3.10.so.1.0)\n```\n\nglibc is the GNU standard C library, a fundamental library used by virtually all programs.\nThese errors mean there is a mismatch between the version of glibc required by a library and the one that's available.\nThis can happen when we have programs and libraries from different Nix channels interacting with each other.\n\nFor example, if a Python program uses libcairo (maybe via pycairo), an entry containing the `libcairo.so` shared library would be added to the `LD_LIBRARY_PATH` variable, telling the system library loader to look for libraries there in addition to the normal places. But if Python is built from a different Nix channel from libcairo, they may depend on different versions of glibc. Python will get to choose its desired glibc version, but if it is incompatible with libcairo because its Nix channel is older than that of libcairo, the program will crash when we try to load libcairo.\n\nWe found the approach of using `LD_LIBRARY_PATH` too heavy-handed: it forced programs to abide by it even if the program already knows where its required its compatible libraries are, via its own [runpath](https://amir.rachum.com/shared-libraries/). A tamer approach is called for. With the RTLD loader, we now use the `REPLIT_LD_LIBRARY_PATH` variable, which will be used to search libraries only after loader fails to find the required libraries within the program's runpath. This plus delivering our software on the latest Nix channel will help us get rid of those glibc version mis-match problems.\n\n## How it Works\n\n1. Activate the loader via the LD_AUDIT variable when running a program, ex: `LD_AUDIT=rtld_loader.so python main.py`\n2. If the system loader fails to locate a library, say `libcairo.so`, it will search the directories within `REPLIT_LD_LIBRARY_PATH`\nfor a library with that name.\n\nHow does it tell the system loader has failed to load a library? We use a `la_objsearch` hook\nin the [rtld_loader API](https://man7.org/linux/man-pages/man7/rtld-audit.7.html). If the `flag` argument\npassed in is equal to `LA_SER_DEFAULT`, that means the system loader has failed to find the requested library\nfrom the `runpath` entries of the binary executable and is instead defaulting to searching the system library\npaths. RTLD loader detects this when it occurs and intercepts the request, searches for the requested library\nvia directories listed in `REPLIT_LD_LIBRARY_PATH`, and returns the full path of the library if it is found.\n\n## Logging\n\nYou can control the loader's log level via the `REPLIT_RTLD_LOG_LEVEL` environment variable. Valid values:\n\n* 0 - off\n* 1 - warnings\n* 2 - info\n* 3 - debug\n\nAlso see env_parser.h and logging.h\n\n## Self Reliance\n\nWe are not using libc at all to avoid any libc conflicts with\nthe running binary. It might be possible compile libc statically into\nrtld_loader.so using musl or similar, but I had a hard time with musl in\nlast attempt. So:\n\n* we call system calls directly for file system access\n* we vendor or DIY string functions","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freplit%2Freplit_rtld_loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freplit%2Freplit_rtld_loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freplit%2Freplit_rtld_loader/lists"}