Skip to content

Commit

Permalink
Do not export PMS variables
Browse files Browse the repository at this point in the history
Instead of passing PMS variables as part of the process environment,
we pass them via a file that is later sourced by the ebuild's
bash.

Since, for example, A is usually the greatest contributor to the
process environment, removing it from the process environment
significantly avoids running into MAX_ARG_STRLEN when spawning a new
child process.

This means that A and other PMS variables are no longer exported in
the ebuild and hence unavaiable to child processes. However, A is
mostly used as part of the default_src_unpack function and there A
does not need to be exported.

This started as a change that only unexported A, but was later
extended to most PMS variables as suggested by ulm in
https://bugs.gentoo.org/721088#c23.

Thanks to Zac Medico for helpful input on this change, and to Eli
Schwartz for suggesting that (bash) helpers should simply source the
environment file introduced by this change.

Closes: https://bugs.gentoo.org/721088
Signed-off-by: Florian Schmaus <[email protected]>
  • Loading branch information
Flowdalic committed Dec 30, 2024
1 parent 6f958be commit 67106ed
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 2 deletions.
5 changes: 5 additions & 0 deletions bin/isolated-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ if ___eapi_has_version_functions; then
source "${PORTAGE_BIN_PATH}/eapi7-ver-funcs.sh" || exit 1
fi

if [[ -v PORTAGE_EBUILD_EXTRA_SOURCE ]]; then
source "${PORTAGE_EBUILD_EXTRA_SOURCE}" || exit 1
unset PORTAGE_EBUILD_EXTRA_SOURCE
fi

# We need this next line for "die" and "assert". It expands
# It _must_ preceed all the calls to die and assert.
shopt -s expand_aliases
Expand Down
1 change: 1 addition & 0 deletions lib/portage/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
"digest",
"distcc",
"distlocks",
"dont-export-pms-vars",
"downgrade-backup",
"ebuild-locks",
"fail-clean",
Expand Down
10 changes: 9 additions & 1 deletion lib/portage/eapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2010-2021 Gentoo Authors
# Copyright 2010-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

import collections
Expand Down Expand Up @@ -48,6 +48,10 @@ def eapi_supports_prefix(eapi: str) -> bool:
return _get_eapi_attrs(eapi).prefix


def eapi_exports_pms_vars(eapi: str) -> bool:
return _get_eapi_attrs(eapi).exports_pms_vars


def eapi_exports_AA(eapi: str) -> bool:
return _get_eapi_attrs(eapi).exports_AA

Expand Down Expand Up @@ -157,6 +161,7 @@ def eapi_has_sysroot(eapi: str) -> bool:
"exports_ECLASSDIR",
"exports_KV",
"exports_merge_type",
"exports_pms_vars",
"exports_PORTDIR",
"exports_replace_vars",
"feature_flag_test",
Expand Down Expand Up @@ -198,6 +203,7 @@ class Eapi:
"6",
"7",
"8",
"9",
)

_eapi_val: int = -1
Expand Down Expand Up @@ -236,6 +242,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs:
exports_ECLASSDIR=False,
exports_KV=False,
exports_merge_type=True,
exports_pms_vars=True,
exports_PORTDIR=True,
exports_replace_vars=True,
feature_flag_test=False,
Expand Down Expand Up @@ -275,6 +282,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs:
exports_ECLASSDIR=eapi <= Eapi("6"),
exports_KV=eapi <= Eapi("3"),
exports_merge_type=eapi >= Eapi("4"),
exports_pms_vars=eapi <= Eapi("8"),
exports_PORTDIR=eapi <= Eapi("6"),
exports_replace_vars=eapi >= Eapi("4"),
feature_flag_test=False,
Expand Down
82 changes: 81 additions & 1 deletion lib/portage/package/ebuild/doebuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
from portage.eapi import (
eapi_exports_KV,
eapi_exports_merge_type,
eapi_exports_pms_vars,
eapi_exports_replace_vars,
eapi_has_required_use,
eapi_has_src_prepare_and_src_configure,
Expand Down Expand Up @@ -189,6 +190,57 @@
"RESTRICT",
)

# The following is a set of PMS § 11.1 and § 7.4 without
# - TMPDIR
# - HOME
# because these variables are often assumed to be exported and
# therefore consumed by child processes.
_unexported_pms_vars = frozenset(
# fmt: off
[
# PMS § 11.1 Defined Variables
"P", # NOT-EXPORTED: tendency to break Makefiles when exported
"PF",
"PN",
"CATEGORY",
"PV",
"PR",
"PVR",
"A", # NOT-EXPORTED: largest contributor to process environment when exported
"AA", # NOT-EXPORTED: unused after EAPI 4
"FILESDIR",
"DISTDIR",
"WORKDIR",
"S",
"PORTDIR",
"ECLASSDIR",
"ROOT",
"EROOT",
"SYSROOT",
"ESYSROOT",
"BROOT",
"T",
# "TMPDIR", # EXPORTED: often assumed to be exported and available to child processes
# "HOME", # EXPORTED: often assumed to be exported and available to child processes
"EPREFIX",
"D", # NOT-EXPORTED: tendency to break Makefiles when exported
"ED",
"DESTTREE",
"INSDESTTREE",
"EBUILD_PHASE",
"EBUILD_PHASE_FUNC",
"KV",
"MERGE_TYPE",
"REPLACING_VERSIONS",
"REPLACED_BY_VERSION",
# PMS 7.4 Magic Ebuild-defined Variables
"ECLASS",
"INHERITED",
"DEFINED_PHASES",
]
# fmt: on
)


def _doebuild_spawn(phase, settings, actionmap=None, **kwargs):
"""
Expand Down Expand Up @@ -2133,9 +2185,37 @@ def spawn(
logname_backup = mysettings.configdict["env"].get("LOGNAME")
mysettings.configdict["env"]["LOGNAME"] = logname

eapi = mysettings["EAPI"]

unexported_env_vars = None
if "dont-export-pms-vars" in mysettings.features or not eapi_exports_pms_vars(eapi):
unexported_env_vars = _unexported_pms_vars

if unexported_env_vars:
orig_env = mysettings.environ()
# Copy since we are potentially removing keys from the dict.
env = orig_env.copy()

t = env["T"]
if not os.path.isdir(t):
os.makedirs(t)

ebuildExtraSource = os.path.join(t, ".portage-ebuild-extra-source")
with open(ebuildExtraSource, mode="w") as f:
for var_name in unexported_env_vars:
var_value = orig_env.get(var_name)
if var_value is None:
continue
f.write(f"{var_name}='{var_value}'\n")
del env[var_name]

env["PORTAGE_EBUILD_EXTRA_SOURCE"] = str(ebuildExtraSource)
else:
env = mysettings.environ()

try:
if keywords.get("returnpid") or keywords.get("returnproc"):
return spawn_func(mystring, env=mysettings.environ(), **keywords)
return spawn_func(mystring, env=env, **keywords)

proc = EbuildSpawnProcess(
background=False,
Expand Down

0 comments on commit 67106ed

Please sign in to comment.