-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ci: Add a test app for not placing embedded file paths into binaries
Doubles as a test app that building with assertions off doesn't produce warnings. Closes #6306
- Loading branch information
1 parent
74fa526
commit 9ae01e4
Showing
10 changed files
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# The following lines of boilerplate have to be in your project's | ||
# CMakeLists in this exact order for cmake to work correctly | ||
cmake_minimum_required(VERSION 3.5) | ||
|
||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
project(no_embedded_paths) | ||
|
||
idf_build_get_property(idf_path IDF_PATH) | ||
idf_build_get_property(python PYTHON) | ||
idf_build_get_property(elf EXECUTABLE) | ||
|
||
# If the configuration is one that doesn't expect any paths to be found then run this build step | ||
# after building the ELF, will fail if it finds any file paths in binary files | ||
if(CONFIG_OPTIMIZATION_ASSERTIONS_SILENT OR CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED) | ||
add_custom_command( | ||
TARGET ${elf} | ||
POST_BUILD | ||
COMMAND ${python} "${CMAKE_CURRENT_LIST_DIR}/check_for_file_paths.py" "${idf_path}" "${CMAKE_BINARY_DIR}" | ||
) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# No Embedded Paths | ||
|
||
This test app exists to verify that paths (like __FILE__) are not compiled into | ||
any object files in configurations where this should be avoided. | ||
|
||
It doubles up as a build-time check that disabling assertions doesn't lead to | ||
any warnings. | ||
|
||
(These configurations include: assertions disabled, 'silent' asserts, any reproducible | ||
builds configuration.) | ||
|
||
Not embedding paths reduces the binary size, avoids leaking information about | ||
the compilation environment, and is a necessary step to supporet reproducible | ||
builds across projects built in different directories. |
94 changes: 94 additions & 0 deletions
94
tools/test_apps/system/no_embedded_paths/check_for_file_paths.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#!/usr/bin/env python | ||
# | ||
# 'check_for_file_paths.py' is a CI tool that checks all the unlinked object files | ||
# in a CMake build directory for embedded copies of IDF_PATH. | ||
# | ||
# Designed to be run in CI as a check that __FILE__ macros haven't snuck into any source code. | ||
# | ||
# Checking the unlinked object files means we don't rely on anything being actually linked into the binary, | ||
# just anything which could potentially be linked. | ||
# | ||
# Usage: | ||
# ./check_for_file_paths.py <IDF_PATH> <BUILD_DIR> | ||
# | ||
# | ||
# | ||
# Copyright 2019 Espressif Systems (Shanghai) PTE LTD | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
import os | ||
import re | ||
import sys | ||
|
||
from elftools.elf.elffile import ELFFile | ||
|
||
# If an ESP-IDF source file has no option but to include __FILE__ macros, name it here (as re expression). | ||
# | ||
# IMPORTANT: This should only be used for upstream code where there is no other | ||
# option. ESP-IDF code should avoid embedding file names as much as possible to | ||
# limit the binary size and support reproducible builds | ||
# | ||
# Note: once ESP-IDF moves to Python >=3.6 then this can be simplified to use 'glob' and '**' | ||
EXCEPTIONS = [ | ||
r'openssl/.+/ssl_pm.c.obj$', # openssl API requires __FILE__ in error reporting functions, as per upstream API | ||
r'openssl/.+/ssl_bio.c.obj$', | ||
r'unity/.+/unity_runner.c.obj$', # unity is not for production use, has __FILE__ for test information | ||
] | ||
|
||
|
||
def main(): # type: () -> None | ||
idf_path = sys.argv[1] | ||
build_dir = sys.argv[2] | ||
|
||
assert os.path.exists(idf_path) | ||
assert os.path.exists(build_dir) | ||
|
||
print('Checking object files in {} for mentions of {}...'.format(build_dir, idf_path)) | ||
|
||
# note: once ESP-IDF moves to Python >=3.6 then this can be simplified to use 'glob' and f'{build_dir}**/*.obj' | ||
files = [] | ||
for (dirpath, _, filepaths) in os.walk(build_dir): | ||
files += [os.path.join(dirpath, filepath) for filepath in filepaths if filepath.endswith('.obj')] | ||
|
||
print('Found {} object files...'.format(len(files))) | ||
|
||
idf_path_binary = idf_path.encode() # we're going to be checking binary streams (note: probably non-ascii IDF_PATH will not match OK) | ||
|
||
failures = 0 | ||
for obj_file in files: | ||
if not any(re.search(exception, obj_file) for exception in EXCEPTIONS): | ||
failures += check_file(obj_file, idf_path_binary) | ||
if failures > 0: | ||
raise SystemExit('{} source files are embedding file paths, see list above.'.format(failures)) | ||
print('No embedded file paths found') | ||
|
||
|
||
def check_file(obj_file, idf_path): # type: (str, bytes) -> int | ||
failures = 0 | ||
with open(obj_file, 'rb') as f: | ||
elf = ELFFile(f) | ||
for sec in elf.iter_sections(): | ||
# can't find a better way to filter out only sections likely to contain strings, | ||
# and exclude debug sections. .dram matches DRAM_STR, which links to .dram1 | ||
if '.rodata' in sec.name or '.dram' in sec.name: | ||
contents = sec.data() | ||
if idf_path in contents: | ||
print('error: {} contains an unwanted __FILE__ macro'.format(obj_file)) | ||
failures += 1 | ||
break | ||
return failures | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
idf_component_register(SRCS "test_no_embedded_paths_main.c" | ||
INCLUDE_DIRS ".") |
4 changes: 4 additions & 0 deletions
4
tools/test_apps/system/no_embedded_paths/main/test_no_embedded_paths_main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/* This test app only exists for the build stage, so doesn't need to do anything at runtime */ | ||
void app_main(void) | ||
{ | ||
} |
8 changes: 8 additions & 0 deletions
8
tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y | ||
CONFIG_FREERTOS_ASSERT_DISABLE=y | ||
|
||
# compiling as many files as possible here (we don't have 100% coverage of course, due to config options, but | ||
# try to maximize what we can check | ||
CONFIG_BT_ENABLED=y | ||
CONFIG_BT_BLUEDROID_ENABLED=y | ||
CONFIG_BLE_MESH=y |
13 changes: 13 additions & 0 deletions
13
tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts.nimble
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y | ||
CONFIG_FREERTOS_ASSERT_DISABLE=y | ||
|
||
# the other sdkconfig builds Bluedroid, build NimBLE here | ||
# | ||
# (Note: ESP32-S2 will build both these configs as well, but they're identical. This is simpler than | ||
# needing to specify per-target configs for both Bluedroid and Nimble on ESP32, ESP32-C3.) | ||
CONFIG_BT_ENABLED=y | ||
CONFIG_BT_NIMBLE_ENABLED=y | ||
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n | ||
CONFIG_BT_NIMBLE_MESH=y | ||
CONFIG_BLE_MESH=y | ||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 |
7 changes: 7 additions & 0 deletions
7
tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y | ||
|
||
# compiling as many files as possible here (we don't have 100% coverage of course, due to config options, but | ||
# try to maximize what we can check | ||
CONFIG_BT_ENABLED=y | ||
CONFIG_BT_BLUEDROID_ENABLED=y | ||
CONFIG_BLE_MESH=y |
13 changes: 13 additions & 0 deletions
13
tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts.nimble
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y | ||
CONFIG_FREERTOS_ASSERT_DISABLE=y | ||
|
||
# the other sdkconfig builds Bluedroid, build NimBLE here | ||
# | ||
# (Note: ESP32-S2 will build both these configs as well, but they're identical. This is simpler than | ||
# needing to specify per-target configs for both Bluedroid and Nimble on ESP32, ESP32-C3.) | ||
CONFIG_BT_ENABLED=y | ||
CONFIG_BT_NIMBLE_ENABLED=y | ||
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n | ||
CONFIG_BT_NIMBLE_MESH=y | ||
CONFIG_BLE_MESH=y | ||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 |