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 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 -- 2.23.0