Remix.run Logo
dwattttt 3 days ago

The reminder to "never break userspace" is good, but people never bring up the other half of that statement: "we can and will break kernel APIs without warning".

It illustrates that the reminder isn't "never change an API in a way that breaks someone", it's the more nuanced "declare what's stable, and never break those".

delta_p_delta_x 3 days ago | parent | next [-]

Even if the kernel doesn't break userspace, GNU libc does, all the time, so the net effect is that Linux userspace is broken regardless of the kernel maintainers' efforts. Put simply, programs and libraries compiled on/for newer libc are ABI-incompatible or straight-up do not run on older libc, so everything needs to be upgraded in lockstep.

It is a bit ironic and a little funny that Windows solved this problem a couple decades ago with redistributables.

rcxdude 3 days ago | parent | next [-]

GNU libc has pretty good backwards compatibility, though, so if not you want to run on a broad range of versions, link against as old a version of libc as is practical (which does take some effort, annoyingly). It tends to be things like GUI libraries and such which are a bigger PITA, because they do break compatibility and the old versions stop being shipped in distros, and shipping them all with your app can still run into protocol compatibility issues.

o11c 3 days ago | parent | prev | next [-]

You're describing 2 completely different things there.

If your program is built to require myfavoritelibrary version 1.9, and you try to run it against myfavoritelibrary 1.0, no shit it doesn't work. Glibc is no different than any other in this regard.

If your program is built to require myfavoritelibrary version 1.0, and you try to run it on myfavoritelibrary 1.9 ... glibc's binary compatibility story has been very good since the release of 2.2 or so, way back in 2000. (I know from documentation that there were a lot of 2.0 -> 2.1 breakages, some of which might've actually been fixed in 2.1.x point releases, so I'm saying 2.2 to be safe)

It's not quite as perfect as Linux's "we do not break userland" but it's pretty darn close; I would have to hunt down changelogs to find something that actually broke without explicitly relying on "do not rely on this" APIs. Source compatibility is a different story, since deprecated APIs can be removed from the public headers but still present in the binary.

... actually, even Linux has unapologetically broken its promise pretty badly in the past at various times. The 2.4 to 2.6 transition in particular was nasty. I'm also aware of at least one common syscall that broke in a very nasty way in some early versions; you can't just use ENOSYS to detect it but have to set up extra registers in a particular way to induce failure for incompatible versions (but only on some architectures; good luck with your testing!)

---

There's nothing stopping you from installing and using the latest glibc and libgcc at runtime, though you'll have to work around your distro's happy path. Just be careful if you're building against them since you probably don't want to add extra dependencies for everything you build.

By contrast, I have statically-linked binaries from ~2006 that simply do not work anymore, because something in the filesystem has changed and their version of libc can't be fixed the way the dynamically-linked version has.

throwaway2046 3 days ago | parent | next [-]

You can find the history of API/ABI changes in glibc since 2011 in this table:

https://abi-laboratory.pro/?view=timeline&l=glibc

Granted it hasn't been updated since 2023, you can still see the trend with removed symbols in each version.

ben-schaaf 3 days ago | parent [-]

I looked into the changelog for 2.34, which this website claims removed 24 symbols.

* 9 malloc debugging variables were removed, though their symbols actually remain for backwards compatibility they just don't do anything. * vtimes was removed, but the symbol remains for backwards compatibility

Those were the only changelog entries listing removals. None of them cause linking issues. The 9 that did break backwards compatibility are a set of debug tools that don't work for alternate memory allocators and the functionality can be brought back with libc_malloc_debug.so.

Maybe the changelog's incomplete, but this actually seem pretty tame to me.

o11c 2 days ago | parent [-]

The nastiest removal I'm aware of is `crypt`, and even in that case it's just a matter of adding the appropriate `LD_PRELOAD` if you can't relink.

account42 a day ago | parent | prev [-]

> glibc's binary compatibility story has been very good since the release of 2.2 or so, way back in 2000

It has been better than most but they recently broke loading libraries that declared they need an executable stack (even if the library never used it) and there doesn't seem to be a plan to actually fix the backwards compatibility issue.

Retr0id 3 days ago | parent | prev [-]

otoh staticly-linked executables are incredibly stable - it's nice to have that option.

delta_p_delta_x 3 days ago | parent [-]

From what I understand, statically linking in GNU's libc.a without releasing source code is a violation of LGPL. Which would break maybe 95% of companies out there running proprietary software on Linux.

musl libc has a more permissive licence, but I hear it performs worse than GNU libc. One can hope for LLVM libc[1] so the entire toolchain would become Clang/LLVM, from the compiler driver to the C/C++ standard libraries. And then it'd be nice to whole-program-optimise from user code all the way to the libc implementation, rip through dead code, and collapse binary sizes.

[1]: https://libc.llvm.org/

teraflop 3 days ago | parent | next [-]

AFAIK, it's technically legal under the LGPL to statically link glibc as long as you also include a copy of the application's object code, along with instructions for how users can re-link against a different glibc if they wish. You don't need to include the source for those .o files.

But I don't think I've ever seen anybody actually do this.

2 days ago | parent [-]
[deleted]
rcxdude 3 days ago | parent | prev | next [-]

Musl is probably the better choice for static linking anyway, GNU libc relies on dynamic linking for a few important features.

resonious 3 days ago | parent | prev | next [-]

The Windows redistributables are so annoying as a user. I remember countless times applications used to ask me to visit the official Microsoft page for downloading them, and it was quite hard to find the right buttons to press to get the thing. Felt like offloading the burden to the users.

IcyWindows 3 days ago | parent [-]

Many installers do it right and don't require the user to do it themselves.

dijit 3 days ago | parent | prev | next [-]

GNU LibC is notoriously difficult to statically link to anyway. (getaddrinfo for example).

Most people use musl, though some others use uclibc.

Musl is actually great, even if it comes with some performance drawbacks in a few cases.

loeg 3 days ago | parent | prev [-]

You can (equivalently) distribute some specific libc.so with your application. I don't think anyone other than GNU maximalists believes this infects your application with the (L)GPL.

Retr0id 3 days ago | parent | next [-]

You'd need to distribute ld.so also, otherwise you'll run into ld/libc incompatibilities.

loeg 2 days ago | parent [-]

Sure.

account42 a day ago | parent [-]

... and ld.so needs to be at a specific absolute path so you can't just distribute it along with your application, you need to use an actual container for this.

cxr 2 days ago | parent | prev [-]

"GNU maximalist" is an odd choice of wording, since it would seem to imply people who are the most well-informed about the project's licenses, but anyone who thinks that distributing an LGPL library without your own app's corresponding source code is someone who flat out doesn't understand the LGPL.

cxr 2 days ago | parent [-]

A mistake in my own wording crept in here; this should have said:

> one who thinks that distributing an LGPL library without your own app's corresponding source code is forbidden is someone who flat out doesn't understand the LGPL

hackrmn 2 days ago | parent | prev | next [-]

In software engineering the statement "interfaces, not implementations" has been used for a long time (certainly at least Robert "Uncle Bob" C. Martin started teaching), which is a generalization on the "we don't break userspace". In essence it cooks down to declaring an interface without announcing or depending on the implementation. With OOP languages like C++, a code base would aggressively use interfaces as types, never concrete class types (which implement the interface), so that it can make it easier to reason about how and whether the program behaves when one implementation of an interface is swapped for another.

With Linux, which is a C codebase by and large, they load and pass pointers to structures to kernel procedures which can do as they please -- as long as the documentation on said structures (which usually says which fields and how are retained with which values and so on) remains unchanged. That's their "object oriented programming" (yeah, I know Linus would likely have hated the comparison).

chubot 3 days ago | parent | prev | next [-]

Yeah, famously there is no stable public driver API for Linux, which I believe was the motivation for Google’s Fuschia OS

So Linux is opinionated in both directions - towards user space and toward hardware - but in the opposite way

matheusmoreira 2 days ago | parent [-]

It's not just opinionation though. It's the kernel's leverage against the people who would keep their modules out of the git tree instead of contributing them. Those people literally get left behind and they are forced to pay maintainers to chase a continuously moving target. The solution to that is to contribute the code.

brainzap 3 days ago | parent | prev [-]

makes me remember a Evan: we provided a migration path from 2 to 3, but so many internal changed that many plugins broke