On 11/1/19 5:27 AM, Nicolas Iooss wrote:
libselinux currently uses "gcc -aux-info" in order to generate glue code
for its Python bindings that throws an exception when a function returns
a negative integer value. This causes issues when another compiler than
gcc is used (such as clang or icc), as option -aux-info is specific to
gcc.
Replace "gcc -aux-info" with a command that parses the content of header
files using "sed". As this is more fragile (because the declaration of
functions is not normalized), add a new target to the Makefile in order
to test that the new method does not produce different results with
"make CC=gcc test".
When reverting commit cfe487409307 ("libselinux: mark all exported
function "extern""), "make test" now fails as expected:
bash -e exception.sh test
Error ensuring that all exported functions that return an int are handled by exception.sh.
Here are functions that were not found in "gcc -aux-info" but that were collected by "sed":
Here are functions in "gcc -aux-info" that may be missing "extern" in header file:
selinuxfs_exists
make: *** [Makefile:202: test] Error 1
Original thread: https://lore.kernel.org/selinux/20191012172357.GB19655@xxxxxxxxxxxxxxxxx/T/#ma78bd7fe71fb5784387a8c0cebd867d6c02ee6e4
I'm not excited about moving to a more fragile method of generating this
glue code. Would it perhaps suffice for us to pre-generate the files and
keep them in-tree (or package them as part of the tar file
distributions) so that downstream users without gcc can just use the
generated files?
Signed-off-by: Nicolas Iooss <nicolas.iooss@xxxxxxx>
Cc: Michael Shigorin <mike@xxxxxxxxxxxx>
---
libselinux/Makefile | 1 +
libselinux/src/Makefile | 5 ++++-
libselinux/src/exception.sh | 38 +++++++++++++++++++++++++++++++------
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/libselinux/Makefile b/libselinux/Makefile
index 16531fe95bf5..c0ae884f8ede 100644
--- a/libselinux/Makefile
+++ b/libselinux/Makefile
@@ -67,3 +67,4 @@ clean-rubywrap:
$(MAKE) -C src clean-rubywrap $@
test:
+ $(MAKE) -C src test
diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
index 63d6b0eda270..c12230a17b1d 100644
--- a/libselinux/src/Makefile
+++ b/libselinux/src/Makefile
@@ -198,7 +198,10 @@ clean: clean-pywrap clean-rubywrap
distclean: clean
rm -f $(GENERATED) $(SWIGFILES)
+test:
+ bash -e exception.sh test
+
indent:
../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch]))
-.PHONY: all clean clean-pywrap clean-rubywrap pywrap rubywrap swigify install install-pywrap install-rubywrap distclean
+.PHONY: all clean clean-pywrap clean-rubywrap pywrap rubywrap swigify install install-pywrap install-rubywrap distclean test indent
diff --git a/libselinux/src/exception.sh b/libselinux/src/exception.sh
index d6c8c71713ad..adbb632c2f04 100755
--- a/libselinux/src/exception.sh
+++ b/libselinux/src/exception.sh
@@ -1,11 +1,12 @@
+#!/bin/bash -e
function except() {
-case $1 in
+case "$1" in
selinux_file_context_cmp) # ignore
;;
*)
echo "
%exception $1 {
- \$action
+ \$action
if (result < 0) {
PyErr_SetFromErrno(PyExc_OSError);
SWIG_fail;
@@ -15,10 +16,35 @@ echo "
;;
esac
}
-if ! ${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h
+
+if [ $# -eq 1 ] && [ "$1" = "test" ]
then
- # clang does not support -aux-info so fall back to gcc
- gcc -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h
+ # Ensure that "gcc -aux-info" produces the same list of functions as the sed command.
+ # The main difference between these way of producing the list of exported
+ # functions is that "gcc -aux-info" automatically inserts "extern" to all
+ # declarations and writes each one on a single line.
+ # clang does not support -aux-info, so skip the test if generating the aux file failed.
+ if ${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/selinux/selinux.h
+ then
+ FCT_FROM_AUX="$(awk '/<stdin>.*extern int/ { print $6 }' temp.aux | sort -u)"
+ FCT_FROM_SED="$(sed -n 's/^extern \+int \+\([0-9A-Za-z_]\+\) *(.*$/\1/p' < ../include/selinux/selinux.h | sort -u)"
+ if [ "$FCT_FROM_AUX" != "$FCT_FROM_SED" ]
+ then
+ echo >&2 'Error ensuring that all exported functions that return an int are handled by exception.sh.'
+ echo >&2 'Here are functions that were not found in "gcc -aux-info" but that were collected by "sed":'
+ comm -13 <(echo "$FCT_FROM_AUX") <(echo "$FCT_FROM_SED")
+ echo >&2 'Here are functions in "gcc -aux-info" that may be missing "extern" in header file:'
+ comm -23 <(echo "$FCT_FROM_AUX") <(echo "$FCT_FROM_SED")
+ exit 1
+ fi
+ fi
+ rm -f -- temp.aux -.o
+ exit
fi
-for i in `awk '/<stdin>.*extern int/ { print $6 }' temp.aux`; do except $i ; done
+
+# shellcheck disable=SC2013
+for i in $(sed -n 's/^extern \+int \+\([0-9A-Za-z_]\+\) *(.*$/\1/p' < ../include/selinux/selinux.h)
+do
+ except "$i"
+done
rm -f -- temp.aux -.o