Godot: 3.2.2 Linux headless version exports invalid Mac app

Created on 29 Jun 2020  路  23Comments  路  Source: godotengine/godot

Godot version:

3.2.2 Linux Headless

OS/device including version:

Ubuntu 18.04 for building, Mac OS Catalina (10.15.5) for running the app

Issue description:

When exporting a Mac build with the Linux headless version of Godot 3.2.2 the result is an .app file that cannot be run.

I'm using my GitHub workflow that runs the Linux headless version of Godot to export projects. After updating the workflow to use Godot 3.2.2, this workflow no longer outputs a valid Mac app. When attempting to run the app on my Mac I receive a dialog that states:

Screen Shot 2020-06-29 at 8 18 42 AM

Exporting the Mac app from the Windows version of Godot 3.2.2 produces an app that can be run without issue.

Steps to reproduce:

  1. Create an empty project
  2. Create a minimal Mac export
  3. Using the Linux Headless version of 3.2.2, export the Mac app from the command line
  4. Attempt to run the app on a Mac, observe the error

Minimal reproduction project:

ActionsTest-master.zip Please note that the standard project is the project directory. You can also try with the mono project in project-mono to see the same result.

If it helps, here is the output app for the standard build: https://drive.google.com/file/d/16aYbNx7ovtIKkqvgd_SAZ7ya-7uo6L93/view?usp=sharing

And here is the output app for the mono build: https://drive.google.com/file/d/1-HJnBxJ3-n8XokI-NBsz0QA3xBncPL7P/view?usp=sharing

This issue originally stated this was a mono-specific issue. After some more troubleshooting it was found that the issue also applies to the standard version.

bug macos regression editor

Most helpful comment

Actually it's just constant size issue, changed it to:

zipfi.external_fa = (uint32_t)(is_executable ? 0100755 : 0100644) << 16L;

(results in following output by zip-info, and is extracted correctly by all apps I have tested):

  Unix file attributes (100755 octal):            -rwxr-xr-x
  MS-DOS file attributes (00 hex):                none

instead of


zipfi.external_fa = (is_executable ? 0100755 : 0100644) << 16L;

(results in following output by zip-info, and have broken files when extracted by Archive Util)

  Unix file attributes (177777 octal):            ?rwsrwsrwt
  MS-DOS file attributes (FF hex):                rdo hid sys lab dir arc lnk exe

or


zipfi.external_fa = (is_executable ? 0755 : 0644) << 16L;

(results in following output by zip-info, and seems to be extracted correctly)

  Unix file attributes (000755 octal):            ?rwxr-xr-x
  MS-DOS file attributes (00 hex):                none

Also, I have checked info-zip source and it's setting attributes as following (result seems to be the same, not sure why it's done it this way):

uint32_t _mode = (is_executable ? 0100755 : 0100644);

zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
zipfi.internal_fa = 0;

All 23 comments

Does the Linux headless non-mono version produce a valid Mac app?

If it helps, here is the output app: https://drive.google.com/file/d/1-HJnBxJ3-n8XokI-NBsz0QA3xBncPL7P/view?usp=sharing

App is valid and running on macOS 10.15.5 (it's not signed and do trigger GateKeeper warning).

@neikeq Good call, the headless non-mono version also produces an invalid app for me. That build is here: https://drive.google.com/file/d/16aYbNx7ovtIKkqvgd_SAZ7ya-7uo6L93/view?usp=sharing

I will update the issue to remove references to Mono.

@bruvzg I am also running on Mac OS 10.15.5. Here's a screenshot of what I am experiencing. This is when trying to run the build that I linked in the issue:

Screen Shot 2020-06-29 at 8 18 42 AM

I'm used to seeing the Gatekeeper warning for 3.2.1 and earlier, strange that now it's outright saying it can't be opened.

It's related to missing +x flag when extraction ZIP using specific software (Keka do it correctly, but macOS default Archive Utility do not) apparently file flag changes in #39700 and #33447 do not fully work, probably we should another library to export ZIPs.

CC @pouleyKetchoupp

@firebelley What was the last godot version for which this scenario was working?

Please specifically test on 3.2.2 RC1 if you have a chance, so we'll know if the regression was introduced in #39700

@pouleyKetchoupp This was working in 3.2.1 stable, meaning that the app was recognized as a valid app. It still couldn't be executed because it was lacking the appropriate executable flags.

I just tested with 3.2.2 RC1 and it produced a valid Mac app. I can run the app without issue. Let me know if you'd like me to share that build.

Thanks @firebelley! That means this regression is due to my changes in #39700.

I don't really understand why, but it seems the file type flags I've added are invalid when zipping from a linux system then. A possible hotfix might be to set zip flags differently depending on the platform we're exporting from. I'll try and reproduce it in the coming days to see if I can figure it out.

@bruvzg I agree it would be worth checking with a different zip library, although at this point I have no idea if the problems we're encountering are mostly coming from the library itself or some weirdness in macOS archivers :)

FYI: Godot 3.2.2 stable/release also outputs broken Mac .zip exports on Mac.

zipinfo -l

Quick data points (exporting the non-mono project from OP) with Godot 3.2.1 on Mac:

$ zipinfo -l exports/from_3_2_1/test_export__from_3_2_1.zip 
Archive:  exports/from_3_2_1/test_export__from_3_2_1.zip   15371335   5
-rw-rw-r--  0.0 fat    27154 b-    11424 defN 10-Mar-20 13:28 Project.app/Contents/Resources/icon.icns
-rw----     0.0 fat     1211 t-      452 defN 10-Mar-20 13:28 Project.app/Contents/Info.plist
-rw-rw-r--  0.0 fat        9 t-        9 defN 10-Mar-20 13:28 Project.app/Contents/PkgInfo
-rw----     0.0 fat 42584980 b- 15337049 defN 10-Mar-20 13:28 Project.app/Contents/MacOS/Project
-rw----     0.0 fat   115216 b-    21649 defN  0-000-80 00:00 Project.app/Contents/Resources/Project.pck
5 files, 42728570 bytes uncompressed, 15370583 bytes compressed:  64.0%

vs with Godot 3.2.2 on Mac:

$ zipinfo -l exports/from_3_2_2/test_export__from_3_2_2.zip 
Archive:  exports/from_3_2_2/test_export__from_3_2_2.zip   15643058   5
?rwsrwsrwt  2.0 unx     1211 tx      452 defN 30-Jul-20 05:27 Project.app/Contents/Info.plist
?rwsrwsrwt  2.0 unx 43059220 bx 15508975 defN 30-Jul-20 05:27 Project.app/Contents/MacOS/Project
?rwsrwsrwt  2.0 unx        9 tx        9 defN 30-Jul-20 05:27 Project.app/Contents/PkgInfo
?rwsrwsrwt  2.0 unx   155421 bx   111223 defN 30-Jul-20 05:27 Project.app/Contents/Resources/icon.icns
?rwsrwsrwt  2.0 unx   115216 bx    21647 defN 30-Jul-20 05:27 Project.app/Contents/Resources/Project.pck
5 files, 43331077 bytes uncompressed, 15642306 bytes compressed:  63.9%

Note: According to man zipinfo (in relation to an example output mentioned):

The second and third fields indicate that the file was zipped under Unix with version 1.9 of zip. Since it comes from Unix, the file permissions at the beginning of the line are printed in Unix format.

and :

The fifth field consists of two characters, either of which may take on several values. The first character may be either t or b, indicating that zip believes the file to be text or binary, respectively; [...]

The second character may also take on four values, depending on whether there is an extended local header and/or an _"extra field"_ associated with the file (fully explained in PKWare's APPNOTE.TXT, [...]). If neither exists, the character will be a hyphen (-); if there is an extended local header but no extra field, l; if the reverse, x; and if both exist, X.

zipinfo -v

In addition, the verbose mode of zipinfo provides this additional information for the (should be) executable file:

$ zipinfo -v exports/from_3_2_1/test_export__from_3_2_1.zip

[...]

Central directory entry #4:
---------------------------

  Project.app/Contents/MacOS/Project

  offset of local header from start of archive:     12074 (00002F2Ah) bytes
  file system or operating system of origin:        MS-DOS, OS/2 or NT FAT
  version of encoding software:                     0.0
  minimum file system compatibility required:       MS-DOS, OS/2 or NT FAT
  minimum software version required to extract:     2.0
  compression method:                               deflated
  compression sub-type (deflation):                 normal
  file security status:                             not encrypted
  extended local header:                            no
  file last modified on (DOS date/time):            2020 Mar 10 13:28:14
  32-bit CRC value (hex):                           35c6abea
  compressed size:                                  15337049 bytes
  uncompressed size:                                42584980 bytes
  length of filename:                               34 characters
  length of extra field:                            0 bytes
  length of file comment:                           0 characters
  disk number on which file begins:                 disk 1
  apparent file type:                               binary
  non-MSDOS external file attributes:               81ED00 hex
  MS-DOS file attributes (00 hex):                  none

[...]

(Note: 0x81ED00 is--according to my quick calculations--correct value for (note: octal--I'm using Python syntax here) 0o0100755 << 16.)

and

$ zipinfo -v exports/from_3_2_2/test_export__from_3_2_2.zip
[...]

Central directory entry #2:
---------------------------

  There are an extra -12 bytes preceding this file.

  Project.app/Contents/MacOS/Project

  offset of local header from start of archive:     513 (00000201h) bytes
  file system or operating system of origin:        Unix
  version of encoding software:                     2.0
  minimum file system compatibility required:       MS-DOS, OS/2 or NT FAT
  minimum software version required to extract:     2.0
  compression method:                               deflated
  compression sub-type (deflation):                 normal
  file security status:                             not encrypted
  extended local header:                            no
  file last modified on (DOS date/time):            2020 Jul 30 05:27:46
  32-bit CRC value (hex):                           6a8db63c
  compressed size:                                  15508975 bytes
  uncompressed size:                                43059220 bytes
  length of filename:                               34 characters
  length of extra field:                            0 bytes
  length of file comment:                           0 characters
  disk number on which file begins:                 disk 1
  apparent file type:                               binary
  Unix file attributes (177777 octal):              ?rwsrwsrwt
  MS-DOS file attributes (FF hex):                  rdo hid sys lab dir arc lnk exe

  There is a local extra field with ID 0x5855 (old Info-ZIP Unix/OS2/NT) and
  12 data bytes (GMT modification/access times and Unix UID/GID).

  There is no file comment.

[...]

So, oddly, it seems that original fat ("file"/disk format, _not_ executable format (Yay, Apple, what's old is new again!)) non-unix variant lead to the correct results. I haven't yet checked what 3.2.1 headless on Linux produces.

These are the (.zip for Mac) exported files produced with Godot v3.2.1 & Godot v3.2.2 on Mac:

When the .zip files are expanded via the system archive handler the results (for the executable named Project) are:

$ ls -l exports/from_3_2_1/Project.app/Contents/MacOS/Project 
-rwxr-xr-x  1 user  staff  42584980 10 Mar 14:28 exports/from_3_2_1/Project.app/Contents/MacOS/Project
$ ls -l exports/from_3_2_2/Project.app/Contents/MacOS/Project 
-rw-------  1 user  staff  43059220 30 Jul  2020 exports/from_3_2_2/Project.app/Contents/MacOS/Project

Interestingly, I just noticed the latter says "30 Jul 2020" but here today is actually "30 June 2020",

Additionally, with my own project when I first tried to open the exported app via Finder I noticed the following in /var/log/system.log:

Jun 30 03:27:45 hostname com.apple.launchd.peruser.501[289] ([0x0-0x713713].<ProjectName>[87339]): Job failed to exec(3) for weird reason: 13
Jun 30 03:27:45 hostname.local Finder[402]: 8837325: Attempting to SIGCONT to pid #87339 failed, with errno=#3, or the process failed to actually start
Jun 30 03:27:45 hostname.local Dock[400]: no information back from LS about running process LSASN:{hi=0x0;lo=0x713713}
Jun 30 03:27:45 hostname.local Finder[402]: 8837325: Attempting to SIGCONT to pid #87339 failed, with errno=#3, or the process failed to actually start
Jun 30 03:28:15 --- last message repeated 98 times ---

Apparently permissions errors count as "weird reasons" these days: https://superuser.com/questions/478768/running-app-on-macosx-mountain-lion-job-failed-to-exec3-for-weird-reason-13 :D

A thought that occurs to me:

  • Exporting to .zip works for Godot v3.2.1 when exported _from a Mac_. (Note: I do mean .zip and not .dmg.)

  • As I understand it, the platform-specific code is supposed to be platform-independent, i.e. the "export to zip for Mac" code path should be the same whether it's running on Mac, Linux or Windows.

So, if the Linux/Windows exports didn't work going on the same code path, where does it differ from what's run on Mac?

Ummm, when was the last time (pre-3.2.2) someone verified Mac exports to .zip from Linux didn't work?

Because I just generated 3 exports with Godot v3.2.1 on a Linux machine (which were all identical--matching size, matching md5 and appeared to match at least one .zip I'd generated on the Mac), scp'd them to a Mac and opening one resulted in a correctly permissioned executable within the .app structure and the app ran successfully (when opened via right-click & "Open").

Here's one of the files:

Interestingly, I also generated (via wine on Mac) a .zip export from Godot Windows version and it also worked for me--but didn't seem to match the size (the .pck size is different?)--I'm not 100% sure about this because I wasn't being entirely methodical, so maybe I missed something with the Windows one: :D

If it helps, here is the output app: https://drive.google.com/file/d/1-HJnBxJ3-n8XokI-NBsz0QA3xBncPL7P/view?usp=sharing

I have rechecked this ZIP and it seems to have +x on executable when extracting with both Archive Utility and Keka, but result of Archive Utility contains only 0x00 in all files (size is valid)!

Also checked it on the current 3.2 head, same effect, files full of 0x00 when extracted with Archive Util, normal when extracting with Keka. Reverting #39700 do fix it and extracted files have correct permissions with both Archive Util and Keka.

@pouleyKetchoupp Do you have more details on the "some software" mentioned in "causing the file to lose executable permissions when unzipped with some software" you mentioned in https://github.com/godotengine/godot/pull/39700#issue-437382677?

Some extra info:

  • 3.2.1 - separate code path for DMG and ZIP, ZIP export copy files along with attributes from the template ZIP, this was not working in some cases for unknown reasons and result in non-executable files (probably issues with the template ZIP permissions, but there were multiple issues on Linux and Windows popping up constantly).
  • 3.2.2 - (before #39700) export was changed to use same code path for both DMG and ZIP (extract files from template ZIP to temp folder, sign fully formed .app and compress to new ZIP), primary to support signing, ZIP fs type in header was changed form default to Unix, since default one was not preserving executable flag (specific combination of header flag and ext file attributes was found experimentally, to work with at least Archive util, Keka and macOS default command line unzip (infozip)).

Given the confusion that's resulted from https://github.com/godotengine/godot/issues/527 still being open despite https://github.com/godotengine/godot/pull/33447 & https://github.com/godotengine/godot/issues/527#issuecomment-500594602, would it be good to:

  1. Close #527 (Assuming that pre this regression, Linux+Windows export to Mac did work).
  2. Re-title this issue to be "3.2.2 exports invalid Mac app .zip on all platforms".
  3. Revert #39700 and then close this? (Ideally with a hotfix release?)
  4. Create new dedicated issue(s) for any other outstanding variations on this issue such as that mentioned by @pouleyKetchoupp?

BTW @pouleyKetchoupp during my research I discovered this project which seems to document some of the issues they encountered with Mac + Zip support:

(It was described in https://github.com/sindresorhus/gulp-zip/issues/38#issuecomment-75138908 as "...spent about 6 hours today working with every zip library for node. [It was] The only one that has worked..." )

It's strange. I'm not getting the same results as you do, and my change is only setting some standard "normal file" flag on all files :/
I agree it makes sense to revert #39700 for now though, and if needed we'll make another fix later.

The next thing I'll do is testing again with the official 3.2.2 release to see if my problem could be specific to my compilation of godot somehow.

Here's my previous test case scenario:

Zip export created on Windows 10 (godot master, compiled with vs 2019)
Zip extracted on OSX, version: 10.13.6 (High Sierra)

Before #39700:
Doesn't work with default Archive Utility (file not executable)
Works when extracted using unzip in command line

After #39700:
Works with both Archive Utility & unzip in command line

Actually it's just constant size issue, changed it to:

zipfi.external_fa = (uint32_t)(is_executable ? 0100755 : 0100644) << 16L;

(results in following output by zip-info, and is extracted correctly by all apps I have tested):

  Unix file attributes (100755 octal):            -rwxr-xr-x
  MS-DOS file attributes (00 hex):                none

instead of


zipfi.external_fa = (is_executable ? 0100755 : 0100644) << 16L;

(results in following output by zip-info, and have broken files when extracted by Archive Util)

  Unix file attributes (177777 octal):            ?rwsrwsrwt
  MS-DOS file attributes (FF hex):                rdo hid sys lab dir arc lnk exe

or


zipfi.external_fa = (is_executable ? 0755 : 0644) << 16L;

(results in following output by zip-info, and seems to be extracted correctly)

  Unix file attributes (000755 octal):            ?rwxr-xr-x
  MS-DOS file attributes (00 hex):                none

Also, I have checked info-zip source and it's setting attributes as following (result seems to be the same, not sure why it's done it this way):

uint32_t _mode = (is_executable ? 0100755 : 0100644);

zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
zipfi.internal_fa = 0;

Good catch! That makes a lot of sense. Bit-wise operators on signed integers are undefined and probably made the result compiler specific.

Was this page helpful?
0 / 5 - 0 ratings