From 99f0491f04a6a3e9e445fee9e9cf66b02887ea1d Mon Sep 17 00:00:00 2001 From: Ivan Komarov Date: Fri, 23 Feb 2024 17:11:27 +0100 Subject: [PATCH] Fix invalid XNU binaries generated by `apelink` in some edge cases (#1106) * Fix `if...fi` generation in the generated APE shell script A shell will fail with a syntax error on an empty `if` or `else` body. That is, neither of these is allowed: # Empty `if` if [ ... ]; then fi # Empty `else` if [ ... ]; then ... else fi There were two places where `apelink` could generate problematic `if`'s: 1. The XNU shell generation for aarch64 binaries when no loaders (either binary or source) are provided. They can't assimilate, so the resulting `else` body becomes empty. There is actually a code path guarded by the `gotsome` variable that inserts an extra `true` in this case, but the variable was never initialized, so in practice this code path didn't activate in my tests. This is fixed by initializing the variable. 2. The loader extraction code when no loaders are provided and XNU support is requested. This is fixed by adding a simliar code path that prevents an empty body from being generated. * Update the apelink manual after commit d53c335 The `-s` option changed its meaning, but the docs weren't updated. --- tool/build/apelink.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tool/build/apelink.c b/tool/build/apelink.c index 7b1f7d57e..0c9052f34 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -102,7 +102,7 @@ " - 32: freebsd\n" \ " - 64: netbsd\n" \ "\n" \ - " for example, `-s 0b1110001` may be used to\n" \ + " for example, `-V 0b1110001` may be used to\n" \ " produce ELF binaries that only support the\n" \ " truly open unix systems. in this case when\n" \ " a single input executable is supplied, the\n" \ @@ -120,8 +120,8 @@ " also pass strings in a variety of intuitive\n" \ " supported representations. for example, bsd\n" \ " will enable freebsd+netbsd+openbsd and that\n" \ - " string too is a legal input. the -s flag is\n" \ - " also repeatable, e.g. `-s nt -s xnu` to use\n" \ + " string too is a legal input. the -V flag is\n" \ + " also repeatable, e.g. `-V nt -V xnu` to use\n" \ " the union of the two.\n" \ "\n" \ " since the support vector controls the file\n" \ @@ -988,7 +988,7 @@ static void GetOpts(int argc, char *argv[]) { if (ParseSupportVector(optarg, &bits)) { support_vector |= bits; } else { - Die(prog, "unrecognized token passed to -s support vector flag"); + Die(prog, "unrecognized token passed to -V support vector flag"); exit(1); } got_support_vector = true; @@ -2036,7 +2036,7 @@ int main(int argc, char *argv[]) { // let our shell script compile the ape loader on first run. // if (support_vector & _HOSTXNU) { - bool gotsome; + bool gotsome = false; p = stpcpy(p, "else\n"); // if [ -d /Applications ]; then // output native mach-o morph @@ -2136,6 +2136,7 @@ int main(int argc, char *argv[]) { } // extract the ape loader for open platforms + bool gotsome = false; if (inputs.n && (support_vector & _HOSTXNU)) { p = stpcpy(p, "if [ ! -d /Applications ]; then\n"); } @@ -2158,9 +2159,13 @@ int main(int argc, char *argv[]) { "mv -f \"$t.$$\" \"$t\" ||exit\n"); p = stpcpy(p, "exec \"$t\" \"$o\" \"$@\"\n" "fi\n"); + gotsome = true; } } if (inputs.n && (support_vector & _HOSTXNU)) { + if (!gotsome) { + p = stpcpy(p, "true\n"); + } p = stpcpy(p, "fi\n"); }