public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: lib/portage/, /, lib/portage/tests/process/
@ 2023-01-15 22:11 Sam James
  0 siblings, 0 replies; only message in thread
From: Sam James @ 2023-01-15 22:11 UTC (permalink / raw
  To: gentoo-commits

commit:     196caf376c5783c9123277711cdbd8e9711de436
Author:     Florian Schmaus <flow <AT> gentoo <DOT> org>
AuthorDate: Sun Jan 15 18:56:10 2023 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Jan 15 22:11:19 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=196caf37

lib/portage/process.py: show diag message if exec failed with E2BIG

Signed-off-by: Florian Schmaus <flow <AT> gentoo.org>
Closes: https://github.com/gentoo/portage/pull/978
Signed-off-by: Sam James <sam <AT> gentoo.org>

 NEWS                                               |  2 ++
 lib/portage/process.py                             | 29 ++++++++++++++++
 lib/portage/tests/process/test_spawn_fail_e2big.py | 40 ++++++++++++++++++++++
 3 files changed, 71 insertions(+)

diff --git a/NEWS b/NEWS
index b149ecc4d..a173795b3 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ Features:
 
 * cleanups: Use flynt on the codebase to upgrade to Python f-strings everywhere.
 
+* process: Show diagnostic message if exec failed with E2BIG
+
 Bug fixes:
 * ebuild: the PATH variable exported to ebuilds has been changed:
   The PATH setting from /etc/profile.env is appended to portage-internal

diff --git a/lib/portage/process.py b/lib/portage/process.py
index 5ba6c7867..6760f617c 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -437,6 +437,35 @@ def spawn(
             except SystemExit:
                 raise
             except Exception as e:
+                if isinstance(e, OSError) and e.errno == errno.E2BIG:
+                    # If exec() failed with E2BIG, then this is
+                    # potentially because the environment variables
+                    # grew to large. The following will gather some
+                    # stats about the environment and print a
+                    # diagnostic message to help identifying the
+                    # culprit. See also
+                    # - https://bugs.gentoo.org/721088
+                    # - https://bugs.gentoo.org/830187
+                    def encoded_length(s):
+                        return len(os.fsencode(s))
+
+                    env_size = 0
+                    env_largest_name = None
+                    env_largest_size = 0
+                    for env_name, env_value in env.items():
+                        env_name_size = encoded_length(env_name)
+                        env_value_size = encoded_length(env_value)
+                        # Add two for '=' and the terminating null byte.
+                        total_size = env_name_size + env_value_size + 2
+                        if total_size > env_largest_size:
+                            env_largest_name = env_name
+                            env_largest_size = total_size
+                        env_size += total_size
+
+                    writemsg(
+                        f"ERROR: Executing {mycommand} failed with E2BIG. Child process environment size: {env_size} bytes. Largest environment variable: {env_largest_name} ({env_largest_size} bytes)\n"
+                    )
+
                 # We need to catch _any_ exception so that it doesn't
                 # propagate out of this function and cause exiting
                 # with anything other than os._exit()

diff --git a/lib/portage/tests/process/test_spawn_fail_e2big.py b/lib/portage/tests/process/test_spawn_fail_e2big.py
new file mode 100644
index 000000000..d3be51670
--- /dev/null
+++ b/lib/portage/tests/process/test_spawn_fail_e2big.py
@@ -0,0 +1,40 @@
+# Copyright 2023 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+import platform
+import tempfile
+
+from pathlib import Path
+
+import portage.process
+
+from portage import shutil
+from portage.const import BASH_BINARY
+from portage.tests import TestCase
+
+
+class SpawnE2bigTestCase(TestCase):
+    def testSpawnE2big(self):
+        if platform.system() != "Linux":
+            self.skipTest("not Linux")
+
+        env = dict()
+        env["VERY_LARGE_ENV_VAR"] = "X" * 1024 * 256
+
+        tmpdir = tempfile.mkdtemp()
+        try:
+            logfile = tmpdir / Path("logfile")
+            echo_output = "Should never appear"
+            retval = portage.process.spawn(
+                [BASH_BINARY, "-c", "echo", echo_output], env=env, logfile=logfile
+            )
+
+            with open(logfile) as f:
+                logfile_content = f.read()
+                self.assertIn(
+                    "Largest environment variable: VERY_LARGE_ENV_VAR (262164 bytes)",
+                    logfile_content,
+                )
+            self.assertEqual(retval, 1)
+        finally:
+            shutil.rmtree(tmpdir)


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-01-15 22:11 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-15 22:11 [gentoo-commits] proj/portage:master commit in: lib/portage/, /, lib/portage/tests/process/ Sam James

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox