Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] config.environ: delay export of A and AA (bug 720180)
Date: Tue, 26 May 2020 04:34:48
Message-Id: 20200526043116.81544-1-zmedico@gentoo.org
1 Since variables like A and AA can contain extremely large values which
2 may trigger E2BIG errors during attempts to execute subprocesses, delay
3 export until the last moment, and unexport when appropriate.
4
5 Bug: https://bugs.gentoo.org/720180
6 Signed-off-by: Zac Medico <zmedico@g.o>
7 ---
8 bin/eapi.sh | 9 +++++
9 bin/isolated-functions.sh | 34 ++++++++++++++++
10 bin/phase-functions.sh | 13 +++++++
11 .../ebuild/_config/special_env_vars.py | 7 +++-
12 lib/portage/package/ebuild/config.py | 39 ++++++++++++++-----
13 5 files changed, 91 insertions(+), 11 deletions(-)
14
15 diff --git a/bin/eapi.sh b/bin/eapi.sh
16 index 29dfb008c..f56468e4a 100644
17 --- a/bin/eapi.sh
18 +++ b/bin/eapi.sh
19 @@ -26,6 +26,15 @@ ___eapi_has_S_WORKDIR_fallback() {
20
21 # VARIABLES
22
23 +___eapi_exports_A() {
24 + # https://bugs.gentoo.org/721088
25 + true
26 +}
27 +
28 +___eapi_exports_AA() {
29 + [[ ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]]
30 +}
31 +
32 ___eapi_has_prefix_variables() {
33 [[ ! ${1-${EAPI-0}} =~ ^(0|1|2)$ || " ${FEATURES} " == *" force-prefix "* ]]
34 }
35 diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh
36 index fde684013..973450d86 100644
37 --- a/bin/isolated-functions.sh
38 +++ b/bin/isolated-functions.sh
39 @@ -107,6 +107,39 @@ __bashpid() {
40 sh -c 'echo ${PPID}'
41 }
42
43 +# @FUNCTION: ___eapi_vars_export
44 +# @DESCRIPTION:
45 +# Export variables for the current EAPI. Calls to this function should
46 +# be delayed until the last moment, since exporting these variables
47 +# may trigger E2BIG errors suring attempts to execute subprocesses.
48 +___eapi_vars_export() {
49 + source "${T}/environment.unexported" || die
50 +
51 + if ___eapi_exports_A; then
52 + export A
53 + fi
54 +
55 + if ___eapi_exports_AA; then
56 + export AA
57 + fi
58 +}
59 +
60 +# @FUNCTION: ___eapi_vars_unexport
61 +# @DESCRIPTION:
62 +# Unexport variables that were exported for the current EAPI. This
63 +# function should be called after an ebuild phase, in order to unexport
64 +# variables that may trigger E2BIG errors during attempts to execute
65 +# subprocesses.
66 +___eapi_vars_unexport() {
67 + if ___eapi_exports_A; then
68 + export -n A
69 + fi
70 +
71 + if ___eapi_exports_AA; then
72 + export -n AA
73 + fi
74 +}
75 +
76 __helpers_die() {
77 if ___eapi_helpers_can_die && [[ ${PORTAGE_NONFATAL} != 1 ]]; then
78 die "$@"
79 @@ -122,6 +155,7 @@ die() {
80
81 set +x # tracing only produces useless noise here
82 local IFS=$' \t\n'
83 + ___eapi_vars_unexport
84
85 if ___eapi_die_can_respect_nonfatal && [[ $1 == -n ]]; then
86 shift
87 diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh
88 index 90e622e75..df2c0d8de 100644
89 --- a/bin/phase-functions.sh
90 +++ b/bin/phase-functions.sh
91 @@ -146,6 +146,7 @@ __filter_readonly_variables() {
92 fi
93 fi
94
95 + ___eapi_vars_unexport
96 "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed"
97 }
98
99 @@ -212,6 +213,7 @@ __ebuild_phase() {
100
101 __ebuild_phase_with_hooks() {
102 local x phase_name=${1}
103 + ___eapi_vars_export
104 for x in {pre_,,post_}${phase_name} ; do
105 __ebuild_phase ${x}
106 done
107 @@ -223,6 +225,7 @@ __dyn_pretend() {
108 __vecho ">>> Remove '$PORTAGE_BUILDDIR/.pretended' to force pretend."
109 return 0
110 fi
111 + ___eapi_vars_export
112 __ebuild_phase pre_pkg_pretend
113 __ebuild_phase pkg_pretend
114 >> "$PORTAGE_BUILDDIR/.pretended" || \
115 @@ -236,6 +239,7 @@ __dyn_setup() {
116 __vecho ">>> Remove '$PORTAGE_BUILDDIR/.setuped' to force setup."
117 return 0
118 fi
119 + ___eapi_vars_export
120 __ebuild_phase pre_pkg_setup
121 __ebuild_phase pkg_setup
122 >> "$PORTAGE_BUILDDIR/.setuped" || \
123 @@ -252,6 +256,7 @@ __dyn_unpack() {
124 install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'"
125 fi
126 cd "${WORKDIR}" || die "Directory change failed: \`cd '${WORKDIR}'\`"
127 + ___eapi_vars_export
128 __ebuild_phase pre_src_unpack
129 __vecho ">>> Unpacking source..."
130 __ebuild_phase src_unpack
131 @@ -386,6 +391,7 @@ __dyn_prepare() {
132
133 trap __abort_prepare SIGINT SIGQUIT
134
135 + ___eapi_vars_export
136 __ebuild_phase pre_src_prepare
137 __vecho ">>> Preparing source in $PWD ..."
138 __ebuild_phase src_prepare
139 @@ -423,6 +429,7 @@ __dyn_configure() {
140
141 trap __abort_configure SIGINT SIGQUIT
142
143 + ___eapi_vars_export
144 __ebuild_phase pre_src_configure
145
146 __vecho ">>> Configuring source in $PWD ..."
147 @@ -456,6 +463,7 @@ __dyn_compile() {
148
149 trap __abort_compile SIGINT SIGQUIT
150
151 + ___eapi_vars_export
152 __ebuild_phase pre_src_compile
153
154 __vecho ">>> Compiling source in $PWD ..."
155 @@ -500,6 +508,7 @@ __dyn_test() {
156 else
157 local save_sp=${SANDBOX_PREDICT}
158 addpredict /
159 + ___eapi_vars_export
160 __ebuild_phase pre_src_test
161
162 __vecho ">>> Test phase: ${CATEGORY}/${PF}"
163 @@ -553,6 +562,7 @@ __dyn_install() {
164 eval "[[ -n \$QA_PRESTRIPPED_${ARCH/-/_} ]] && \
165 export QA_PRESTRIPPED_${ARCH/-/_}"
166
167 + ___eapi_vars_export
168 __ebuild_phase pre_src_install
169
170 if ___eapi_has_prefix_variables; then
171 @@ -695,6 +705,7 @@ __dyn_install() {
172 --filter-path --filter-sandbox --allow-extra-vars > \
173 "${PORTAGE_BUILDDIR}"/build-info/environment
174 assert "__save_ebuild_env failed"
175 + ___eapi_vars_unexport
176 cd "${PORTAGE_BUILDDIR}"/build-info || die
177
178 ${PORTAGE_BZIP2_COMMAND} -f9 environment
179 @@ -1087,11 +1098,13 @@ __ebuild_main() {
180 __save_ebuild_env | __filter_readonly_variables \
181 --filter-features > "$T/environment"
182 assert "__save_ebuild_env failed"
183 + ___eapi_vars_unexport
184 chgrp "${PORTAGE_GRPNAME:-portage}" "$T/environment"
185 chmod g+w "$T/environment"
186 fi
187 [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE"
188 if [[ -n $PORTAGE_IPC_DAEMON ]] ; then
189 + ___eapi_vars_unexport
190 [[ ! -s $SANDBOX_LOG ]]
191 "$PORTAGE_BIN_PATH"/ebuild-ipc exit $?
192 fi
193 diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py b/lib/portage/package/ebuild/_config/special_env_vars.py
194 index 440dd00b2..92824e15f 100644
195 --- a/lib/portage/package/ebuild/_config/special_env_vars.py
196 +++ b/lib/portage/package/ebuild/_config/special_env_vars.py
197 @@ -89,7 +89,7 @@ environ_whitelist += [
198 ]
199
200 environ_whitelist += [
201 - "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
202 + "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
203 ]
204
205 # misc variables inherited from the calling environment
206 @@ -124,6 +124,10 @@ environ_whitelist = frozenset(environ_whitelist)
207
208 environ_whitelist_re = re.compile(r'^(CCACHE_|DISTCC_).*')
209
210 +environ_unexported = frozenset([
211 + 'A', 'AA',
212 +])
213 +
214 # Filter selected variables in the config.environ() method so that
215 # they don't needlessly propagate down into the ebuild environment.
216 environ_filter = []
217 @@ -131,6 +135,7 @@ environ_filter = []
218 # Exclude anything that could be extremely long here (like SRC_URI)
219 # since that could cause execve() calls to fail with E2BIG errors. For
220 # example, see bug #262647.
221 +environ_filter.extend(environ_unexported)
222 environ_filter += [
223 'DEPEND', 'RDEPEND', 'PDEPEND', 'SRC_URI',
224 ]
225 diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py
226 index 47c180c12..a386dc031 100644
227 --- a/lib/portage/package/ebuild/config.py
228 +++ b/lib/portage/package/ebuild/config.py
229 @@ -10,6 +10,7 @@ __all__ = [
230 import copy
231 from itertools import chain
232 import grp
233 +import io
234 import logging
235 import platform
236 import pwd
237 @@ -29,7 +30,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
238 'portage.util.locale:check_locale,split_LC_ALL',
239 )
240 from portage import bsd_chflags, \
241 - load_mod, os, selinux, _unicode_decode
242 + load_mod, os, selinux, _encodings, _unicode_decode
243 from portage.const import CACHE_PATH, \
244 DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \
245 MODULES_FILE_PATH, PORTAGE_BASE_PATH, \
246 @@ -2755,14 +2756,36 @@ class config(object):
247 eapi_attrs = _get_eapi_attrs(eapi)
248 phase = self.get('EBUILD_PHASE')
249 emerge_from = self.get('EMERGE_FROM')
250 + temp_dir = None
251 filter_calling_env = False
252 if self.mycpv is not None and \
253 - not (emerge_from == 'ebuild' and phase == 'setup') and \
254 + 'PORTAGE_BUILDDIR_LOCKED' in self and \
255 phase not in ('clean', 'cleanrm', 'depend', 'fetch'):
256 - temp_dir = self.get('T')
257 - if temp_dir is not None and \
258 - os.path.exists(os.path.join(temp_dir, 'environment')):
259 - filter_calling_env = True
260 + temp_dir = self['T']
261 + # These variables will exported by ebuild.sh if appropriate
262 + # for the current EAPI, but export is delayed since large
263 + # values may trigger E2BIG errors during attempts to spawn
264 + # subprocesses.
265 + unexported = []
266 + for key in special_env_vars.environ_unexported:
267 + # Don't export AA for EAPIs that forbid it.
268 + if key == 'AA' and not eapi_exports_AA(eapi):
269 + continue
270 + value = self.get(key)
271 + if value is not None:
272 + unexported.append((key, value))
273 +
274 + # Write this file even if it's empty, so that ebuild.sh can
275 + # rely on its existence.
276 + with io.open(os.path.join(temp_dir, 'environment.unexported'),
277 + mode='wt', encoding=_encodings['repo.content']) as f:
278 + for key, value in unexported:
279 + f.write('%s="%s"\n' % (key, value.replace('"', '\\"')))
280 +
281 + if temp_dir is not None and \
282 + not (emerge_from == 'ebuild' and phase == 'setup') and \
283 + os.path.exists(os.path.join(temp_dir, 'environment')):
284 + filter_calling_env = True
285
286 environ_whitelist = self._environ_whitelist
287 for x, myvalue in self.iteritems():
288 @@ -2805,10 +2828,6 @@ class config(object):
289 # Filtered by IUSE and implicit IUSE.
290 mydict["USE"] = self.get("PORTAGE_USE", "")
291
292 - # Don't export AA to the ebuild environment in EAPIs that forbid it
293 - if not eapi_exports_AA(eapi):
294 - mydict.pop("AA", None)
295 -
296 if not eapi_exports_merge_type(eapi):
297 mydict.pop("MERGE_TYPE", None)
298
299 --
300 2.25.3

Replies