buildman: Use bytes for the environment

At present we sometimes see problems in gitlab where the environment has
0x80 characters or sequences which are not valid UTF-8.

Avoid this by using bytes for the environment, both internal to buildman
and when writing out the 'env' file. Add a test to make sure this works
as expected.

Reported-by: Marek Vasut <marex@denx.de>
Fixes: e5fc79ea71 ("buildman: Write the environment out to an 'env' file")
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-04-11 16:27:28 +12:00
parent 8116c78ffd
commit f1a83abe60
3 changed files with 30 additions and 11 deletions

View File

@ -351,10 +351,9 @@ class BuilderThread(threading.Thread):
# Write out the image and function size information and an objdump # Write out the image and function size information and an objdump
env = result.toolchain.MakeEnvironment(self.builder.full_path) env = result.toolchain.MakeEnvironment(self.builder.full_path)
with open(os.path.join(build_dir, 'out-env'), 'w', with open(os.path.join(build_dir, 'out-env'), 'wb') as fd:
encoding='utf-8') as fd:
for var in sorted(env.keys()): for var in sorted(env.keys()):
print('%s="%s"' % (var, env[var]), file=fd) fd.write(b'%s="%s"' % (var, env[var]))
lines = [] lines = []
for fname in BASE_ELF_FILENAMES: for fname in BASE_ELF_FILENAMES:
cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname] cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]

View File

@ -572,6 +572,18 @@ class TestFunctional(unittest.TestCase):
self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done'))) self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done')))
self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env'))) self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env')))
def testEnvironmentUnicode(self):
"""Test there are no unicode errors when the env has non-ASCII chars"""
try:
varname = b'buildman_test_var'
os.environb[varname] = b'strange\x80chars'
self.assertEqual(0, self._RunControl('-o', self._output_dir))
board0_dir = os.path.join(self._output_dir, 'current', 'board0')
self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done')))
self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env')))
finally:
del os.environb[varname]
def testWorkInOutput(self): def testWorkInOutput(self):
"""Test the -w option which should write directly to the output dir""" """Test the -w option which should write directly to the output dir"""
board_list = board.Boards() board_list = board.Boards()

View File

@ -179,27 +179,35 @@ class Toolchain:
output and possibly unicode encoded output of all build tools by output and possibly unicode encoded output of all build tools by
adding LC_ALL=C. adding LC_ALL=C.
Note that os.environb is used to obtain the environment, since in some
cases the environment many contain non-ASCII characters and we see
errors like:
UnicodeEncodeError: 'utf-8' codec can't encode characters in position
569-570: surrogates not allowed
Args: Args:
full_path: Return the full path in CROSS_COMPILE and don't set full_path: Return the full path in CROSS_COMPILE and don't set
PATH PATH
Returns: Returns:
Dict containing the environemnt to use. This is based on the current Dict containing the (bytes) environment to use. This is based on the
environment, with changes as needed to CROSS_COMPILE, PATH and current environment, with changes as needed to CROSS_COMPILE, PATH
LC_ALL. and LC_ALL.
""" """
env = dict(os.environ) env = dict(os.environb)
wrapper = self.GetWrapper() wrapper = self.GetWrapper()
if self.override_toolchain: if self.override_toolchain:
# We'll use MakeArgs() to provide this # We'll use MakeArgs() to provide this
pass pass
elif full_path: elif full_path:
env['CROSS_COMPILE'] = wrapper + os.path.join(self.path, self.cross) env[b'CROSS_COMPILE'] = tools.ToBytes(
wrapper + os.path.join(self.path, self.cross))
else: else:
env['CROSS_COMPILE'] = wrapper + self.cross env[b'CROSS_COMPILE'] = tools.ToBytes(wrapper + self.cross)
env['PATH'] = self.path + ':' + env['PATH'] env[b'PATH'] = tools.ToBytes(self.path) + b':' + env[b'PATH']
env['LC_ALL'] = 'C' env[b'LC_ALL'] = b'C'
return env return env