Skip to content

macOS OpenGL initialization / security entitlements #109

@michaelgale

Description

@michaelgale

When building a standalone binary of the CQ-Editor for macOS, the app may or may not crash depending on its launch context. That is:

  1. direct from terminal
  2. inside lldb
  3. macOS launchd when double-clicked in the Finder
  4. also macOS launchd when launched from the terminal with the open command

Each mechanism may or may not trigger macOS gatekeeper security and execute the app inside a "sandbox" with path randomization. This path randomization is usually transparent from the point of view of the python introspection, but at a lower level, the oce core accesses the file system to initialize the OpenGL driver as follows:

  1. In OCC/Core/Graphic3d.py, ShadersFolder() is called which in turn calls the binary object function _Graphic3d.Graphic3d_ShaderProgram_ShadersFolder(*args)
  2. This function is in oce/Graphic3d_ShaderProgram.cxx and it is as follows:
// =======================================================================
// function : ShadersFolder
// purpose  :
// =======================================================================
const TCollection_AsciiString& Graphic3d_ShaderProgram::ShadersFolder()
{
  static Standard_Boolean        THE_IS_DEFINED = Standard_False;
  static TCollection_AsciiString THE_SHADERS_FOLDER;
  if (!THE_IS_DEFINED)
  {
    THE_IS_DEFINED = Standard_True;
    OSD_Environment aDirEnv ("CSF_ShadersDirectory");
    THE_SHADERS_FOLDER = aDirEnv.Value();
    if (THE_SHADERS_FOLDER.IsEmpty())
    {
      OSD_Environment aCasRootEnv ("CASROOT");
      THE_SHADERS_FOLDER = aCasRootEnv.Value();
#ifdef OCE_INSTALL_DATA_DIR
      if (THE_SHADERS_FOLDER.IsEmpty())  {
        THE_SHADERS_FOLDER = OCE_INSTALL_DATA_DIR;
      }
#endif
      if (!THE_SHADERS_FOLDER.IsEmpty())
      {
        THE_SHADERS_FOLDER += "/src/Shaders";
      }
    }

    if (THE_SHADERS_FOLDER.IsEmpty())
    {
      std::cerr << "Both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
                << "At least one should be defined to use standard GLSL programs.\n";
      Standard_Failure::Raise ("CSF_ShadersDirectory and CASROOT are undefined");
      return THE_SHADERS_FOLDER;
    }

    const OSD_Path aDirPath (THE_SHADERS_FOLDER);
    OSD_Directory aDir (aDirPath);
    const TCollection_AsciiString aProgram = THE_SHADERS_FOLDER + "/Declarations.glsl";
    OSD_File aProgramFile (aProgram);
    if (!aDir.Exists()
     || !aProgramFile.Exists())
    {
      std::cerr << "Standard GLSL programs are not found in: " << THE_SHADERS_FOLDER.ToCString() << std::endl;
      Standard_Failure::Raise ("CSF_ShadersDirectory or CASROOT is set incorrectly");
      return THE_SHADERS_FOLDER;
    }
  }
  return THE_SHADERS_FOLDER;
}

Depending on runtime sandboxing, the path that this function infers may turn out to be incorrect or obscured. Therefore, when it tests Exists() at the end of the function it raises the error. It is difficult to tell if this function falls back on the hardcoded OCE_INSTALL_DATA_DIR since that will defined when oce is built. If it is, then it is yet another mechanism to not find the Shaders folder.

At the end of the day, the program crashes because OpenGL does not get initialized since it cannot find its Shaders/etc. resources in oce/src.

The secondary mechanism of failure related to #108 is that the evaluation of security entitlements delays OpenGL driver initialization and creates a fatal race condition during app initialization due to early requests to draw axis lines in the 3D viewer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions