Skip to content

Conversation

@carlocab
Copy link
Member

@carlocab carlocab commented Oct 12, 2021

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew typecheck with your changes locally?
  • Have you successfully run brew tests with your changes locally?

There are at least five instances where a formula has libraries compiled
with -flat_namespace due to a bug in detecting the macOS version (cf.
Homebrew/homebrew-core#87103, Homebrew/homebrew-core#85974,
Homebrew/homebrew-core#85973).

I think it makes sense to check for this more generally. It is
sometimes intentional, so I've added a check for an allowlist for
those instances. Running this on the current util-linux bottle
produces

❯ brew audit --strict util-linux
util-linux:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/util-linux/2.37.2/lib/libblkid.1.dylib
      /usr/local/Cellar/util-linux/2.37.2/lib/libfdisk.1.dylib
      /usr/local/Cellar/util-linux/2.37.2/lib/libsmartcols.1.dylib
      /usr/local/Cellar/util-linux/2.37.2/lib/libuuid.1.dylib
Error: 1 problem in 1 formula detected

Some things that still need to be done here:

  • fix this check for universal binaries
  • check if we want to restrict this audit to newer versions of macOS
  • fix false positives (try brew audit --strict llvm and compare the
    output of otool -hV on the identified files)

While we're here, let's fix the formatting of the output of these other
audits (cf. #12217).


Here's some background on flat vs two-level namespaces: https://developer.apple.com/library/archive/documentation/Porting/Conceptual/PortingUnix/compiling/compiling.html#//apple_ref/doc/uid/TP40002850-BCIHJBBF

There are at least five instances where a formula has libraries compiled
with `-flat_namespace` due to a bug in detecting the macOS version (cf.
Homebrew/homebrew-core#87103, Homebrew/homebrew-core#85974,
Homebrew/homebrew-core#85973).

I think it makes sense to check for this more generally. It is
sometimes intentional, so I've added a check for an allowlist for
those instances. Running this on the current `util-linux` bottle
produces

    ❯ brew audit --strict util-linux
    util-linux:
      * Libraries were compiled with a flat namespace.
        This can cause linker errors due to name collisions, and
        is often due to a bug in detecting the macOS version.
          /usr/local/Cellar/util-linux/2.37.2/lib/libblkid.1.dylib
          /usr/local/Cellar/util-linux/2.37.2/lib/libfdisk.1.dylib
          /usr/local/Cellar/util-linux/2.37.2/lib/libsmartcols.1.dylib
          /usr/local/Cellar/util-linux/2.37.2/lib/libuuid.1.dylib
    Error: 1 problem in 1 formula detected

Some things that still need to be done here:
- fix this check for universal binaries
- check if we want to restrict this audit check to newer versions of macOS
- fix false positives (try `brew audit --strict llvm` and compare the
  output of `otool -hV` on the identified files)

While we're here, let's fix the formatting of the output of these other
audits (cf. #12217).
@BrewTestBot
Copy link
Contributor

Review period will end on 2021-10-13 at 05:29:49 UTC.

@BrewTestBot BrewTestBot added the waiting for feedback Merging is blocked until sufficient time has passed for review label Oct 12, 2021
@carlocab
Copy link
Member Author

carlocab commented Oct 12, 2021

This still produces a bunch of false positives, which seems like a bug in ruby-macho. Will have to fix that. Fixed. It was a typo. 😅

There was a typo that made it so that all libraries were being included
in `flat_namespace_files`.
Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, nice work!

@carlocab
Copy link
Member Author

For reference, here is a list of formulae I have installed on Big Sur whose libraries have been compiled with -flat_namespace:

berkeley-db
gdbm
gettext
gmp
gpgme
gsl
gts
isl
jq
julia
libassuan
libb2
libev
libksba
libmpc
mpfr
npth
openldap
pcre
pcre2
tcl-tk

Of these, I believe only gts, julia, and tcl-tk are intentional. I concluded this from checking the Catalina bottles whether they were also compiled with -flat_namespace.

@carlocab
Copy link
Member Author

carlocab commented Oct 12, 2021

Oh, here's another to-do. This check doesn't work for weird libraries like this one:

❯ file $(brew --prefix gcc)/lib/gcc/11/libgcc_s.1.dylib
/usr/local/opt/gcc/lib/gcc/11/libgcc_s.1.dylib: Mach-O universal binary with 1 architecture: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64]
/usr/local/opt/gcc/lib/gcc/11/libgcc_s.1.dylib (for architecture x86_64):	Mach-O 64-bit dynamically linked shared library x86_64

The issue is that #universal? returns false (it only contains one slice), but ruby-macho parses this as a FatFile (based on the MachO header), and FatFiles have no header method.

I think I just need to change the if file.universal? check to a case macho.class.

@Bo98
Copy link
Member

Bo98 commented Oct 12, 2021

My run on Mojave:

mono:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/mono/6.12.0.122/lib/libmono-profiler-aot.0.dylib
      /usr/local/Cellar/mono/6.12.0.122/lib/libmono-profiler-coverage.0.dylib
      /usr/local/Cellar/mono/6.12.0.122/lib/libmono-profiler-log.0.dylib
ocaml:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/bigarray.cmxs
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/libasmrun_shared.so
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/libcamlrun_shared.so
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/str.cmxs
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/stublibs/dllcamlstr.so
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/stublibs/dllthreads.so
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/stublibs/dllunix.so
      /usr/local/Cellar/ocaml/4.12.0/lib/ocaml/unix.cmxs
ocaml-num:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/ocaml-num/1.4_2/lib/ocaml/nums.cmxs
      /usr/local/Cellar/ocaml-num/1.4_2/lib/ocaml/stublibs/dllnums.so
tcl-tk:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/tcl-tk/8.6.11_1/lib/tcltls1.7.22/tcltls.dylib
xvid:
  * Libraries were compiled with a flat namespace.
    This can cause linker errors due to name collisions, and
    is often due to a bug in detecting the macOS version.
      /usr/local/Cellar/xvid/1.3.7/lib/libxvidcore.4.dylib

I'm a little concerned at how many exceptions there is going to be. Though equally, one can wonder why some of these need -flat_namespace. For example, the flag was added to xvid for PowerPC in 2003.

@MikeMcQuaid
Copy link
Member

Though equally, one can wonder why some of these need -flat_namespace. For example, the flag was added to xvid for PowerPC in 2003.

This is the type of thing I wonder if we just strip out with superenv (and allow exceptions).

@carlocab
Copy link
Member Author

I'm a little concerned at how many exceptions there is going to be.

I'm concerned about this too. I'm not sure how to handle it though.

Though equally, one can wonder why some of these need -flat_namespace. For example, the flag was added to xvid for PowerPC in 2003.

Agreed. My view is that flat namespaces are good for development and debugging (but then you can use DYLD_FORCE_FLAT_NAMESPACE). Actually using them in production seems like a bit of an anti-pattern to me, especially given that I don't think you can rely on the linker's behaviour regarding how it chooses to resolve collisions.

@Bo98
Copy link
Member

Bo98 commented Oct 12, 2021

This is the type of thing I wonder if we just strip out with superenv (and allow exceptions).

Could do. I'd like to keep superenv exceptions to even more of a minimum as it indicates we are incorrectly stripping something. If it's just one or two that need it then it's probably ok.

@MikeMcQuaid
Copy link
Member

Could do. I'd like to keep superenv exceptions to even more of a minimum as it indicates we are incorrectly stripping something. If it's just one or two that need it then it's probably ok.

Oh, agreed, this just seems like the type of thing where Superenv stripping is going to be easier than patching all these build systems.

@BrewTestBot BrewTestBot added waiting for feedback Merging is blocked until sufficient time has passed for review and removed waiting for feedback Merging is blocked until sufficient time has passed for review labels Oct 12, 2021
@FnControlOption
Copy link
Contributor

I made a patch that emulates the libtool fix for this by removing -flat_namespace and replacing -undefined suppress with -undefined dynamic_lookup:

diff --git a/Library/Homebrew/shims/super/cc b/Library/Homebrew/shims/super/cc
index c629efa9e..d0f731830 100755
--- a/Library/Homebrew/shims/super/cc
+++ b/Library/Homebrew/shims/super/cc
@@ -208,6 +208,12 @@ class Cmd
       args << arg unless tool =~ /^g..-4.[02]/
     when /^-Wl,-z,defs/
       # -Wl,-undefined,error is already the default
+    when "-Wl,-flat_namespace"
+      # remove arg
+    when "-Wl,-undefined"
+      arg2 = enum.next
+      arg2 = "-Wl,dynamic_lookup" if arg2 == "-Wl,suppress"
+      args << arg << arg2
     when /^-W[alp],/, /^-Wno-/, "-Werror=implicit-function-declaration"
       args << arg
     when /^-W.*/

@BrewTestBot BrewTestBot added waiting for feedback Merging is blocked until sufficient time has passed for review and removed waiting for feedback Merging is blocked until sufficient time has passed for review labels Oct 12, 2021
@BrewTestBot
Copy link
Contributor

Review period ended.

- Fix missing space
- use `MachO::Utils.fat_magic?`
- call `#flag?` consistently.

Co-authored-by: Bo Anderson <mail@boanderson.me>
@carlocab
Copy link
Member Author

Let's try this. We can revert and/or strip the -flat_namespace flag if this gets too annoying.

@Homebrew/core, if you see audit failures with the text

       Libraries were compiled with a flat namespace.
       This can cause linker errors due to name collisions, and
       is often due to a bug in detecting the macOS version.

feel free to ping/assign me.

@carlocab carlocab merged commit 556b8f1 into Homebrew:master Oct 18, 2021
@carlocab carlocab deleted the two-level branch October 18, 2021 14:59
@github-actions github-actions bot added the outdated PR was locked due to age label Nov 18, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

outdated PR was locked due to age

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants