Skip to content

Commit

Permalink
kbuild: compile-test exported headers to ensure they are self-contained
Browse files Browse the repository at this point in the history
Multiple people have suggested compile-testing UAPI headers to ensure
they can be really included from user-space. "make headers_check" is
obviously not enough to catch bugs, and we often leak unresolved
references to user-space.

Use the new header-test-y syntax to implement it. Please note exported
headers are compile-tested with a completely different set of compiler
flags. The header search path is set to $(objtree)/usr/include since
exported headers should not include unexported ones.

We use -std=gnu89 for the kernel space since the kernel code highly
depends on GNU extensions. On the other hand, UAPI headers should be
written in more standardized C, so they are compiled with -std=c90.
This will emit errors if C++ style comments, the keyword 'inline', etc.
are used. Please use C style comments (/* ... */), '__inline__', etc.
in UAPI headers.

There is additional compiler requirement to enable this test because
many of UAPI headers include <stdlib.h>, <sys/ioctl.h>, <sys/time.h>,
etc. directly or indirectly. You cannot use kernel.org pre-built
toolchains [1] since they lack <stdlib.h>.

I reused CONFIG_CC_CAN_LINK to check the system header availability.
The intention is slightly different, but a compiler that can link
userspace programs provide system headers.

For now, a lot of headers need to be excluded because they cannot
be compiled standalone, but this is a good start point.

[1] https://mirrors.edge.kernel.org/pub/tools/crosstool/index.html

Signed-off-by: Masahiro Yamada <[email protected]>
Reviewed-by: Sam Ravnborg <[email protected]>
  • Loading branch information
masahir0y committed Jul 8, 2019
1 parent 1a927fd commit d6fc9fc
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1378,7 +1378,7 @@ CLEAN_DIRS += $(MODVERDIR) include/ksym
CLEAN_FILES += modules.builtin.modinfo

# Directories & files removed with 'make mrproper'
MRPROPER_DIRS += include/config usr/include include/generated \
MRPROPER_DIRS += include/config include/generated \
arch/$(SRCARCH)/include/generated .tmp_objdiff
MRPROPER_FILES += .config .config.old .version \
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
Expand Down
10 changes: 10 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ config HEADER_TEST
If you are a developer or tester and want to ensure the requested
headers are self-contained, say Y here. Otherwise, choose N.

config UAPI_HEADER_TEST
bool "Compile test UAPI headers"
depends on HEADER_TEST && HEADERS_INSTALL && CC_CAN_LINK
help
Compile test headers exported to user-space to ensure they are
self-contained, i.e. compilable as standalone units.

If you are a developer or tester and want to ensure the exported
headers are self-contained, say Y here. Otherwise, choose N.

config LOCALVERSION
string "Local version - append to kernel release"
help
Expand Down
1 change: 0 additions & 1 deletion usr/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ initramfs_data.cpio.gz
initramfs_data.cpio.bz2
initramfs_data.cpio.lzma
initramfs_list
include
2 changes: 2 additions & 0 deletions usr/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ $(deps_initramfs): klibcdirs
$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/$(datafile_d_y)
$(call if_changed,initfs)

subdir-$(CONFIG_UAPI_HEADER_TEST) += include
3 changes: 3 additions & 0 deletions usr/include/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!.gitignore
!Makefile
132 changes: 132 additions & 0 deletions usr/include/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# SPDX-License-Identifier: GPL-2.0-only

# Unlike the kernel space, exported headers are written in standard C.
# - Forbid C++ style comments
# - Use '__inline__', '__asm__' instead of 'inline', 'asm'
#
# -std=c90 (equivalent to -ansi) catches the violation of those.
# We cannot go as far as adding -Wpedantic since it emits too many warnings.
UAPI_CFLAGS := -std=c90 -Wall -Werror=implicit-function-declaration

override c_flags = $(UAPI_CFLAGS) -Wp,-MD,$(depfile) -I$(objtree)/usr/include

# The following are excluded for now because they fail to build.
#
# Do not add a new header to the blacklist without legitimate reason.
# Please consider to fix the header first.
#
# Sorted alphabetically.
header-test- += asm/ipcbuf.h
header-test- += asm/msgbuf.h
header-test- += asm/sembuf.h
header-test- += asm/shmbuf.h
header-test- += asm/signal.h
header-test- += asm/ucontext.h
header-test- += drm/vmwgfx_drm.h
header-test- += linux/am437x-vpfe.h
header-test- += linux/android/binder.h
header-test- += linux/android/binderfs.h
header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
header-test- += linux/coda.h
header-test- += linux/coda_psdev.h
header-test- += linux/dvb/audio.h
header-test- += linux/dvb/osd.h
header-test- += linux/elfcore.h
header-test- += linux/errqueue.h
header-test- += linux/fsmap.h
header-test- += linux/hdlc/ioctl.h
header-test- += linux/ivtv.h
header-test- += linux/jffs2.h
header-test- += linux/kexec.h
header-test- += linux/matroxfb.h
header-test- += linux/netfilter_bridge/ebtables.h
header-test- += linux/netfilter_ipv4/ipt_LOG.h
header-test- += linux/netfilter_ipv6/ip6t_LOG.h
header-test- += linux/nfc.h
header-test- += linux/nilfs2_ondisk.h
header-test- += linux/omap3isp.h
header-test- += linux/omapfb.h
header-test- += linux/patchkey.h
header-test- += linux/phonet.h
header-test- += linux/reiserfs_xattr.h
header-test- += linux/scc.h
header-test- += linux/sctp.h
header-test- += linux/signal.h
header-test- += linux/sysctl.h
header-test- += linux/usb/audio.h
header-test- += linux/v4l2-mediabus.h
header-test- += linux/v4l2-subdev.h
header-test- += linux/videodev2.h
header-test- += linux/vm_sockets.h
header-test- += misc/ocxl.h
header-test- += mtd/mtd-abi.h
header-test- += mtd/mtd-user.h
header-test- += scsi/scsi_bsg_fc.h
header-test- += scsi/scsi_netlink.h
header-test- += scsi/scsi_netlink_fc.h
header-test- += sound/asequencer.h
header-test- += sound/asoc.h
header-test- += sound/asound.h
header-test- += sound/compress_offload.h
header-test- += sound/emu10k1.h
header-test- += sound/sfnt_info.h
header-test- += sound/sof/eq.h
header-test- += sound/sof/fw.h
header-test- += sound/sof/header.h
header-test- += sound/sof/manifest.h
header-test- += sound/sof/trace.h
header-test- += xen/evtchn.h
header-test- += xen/gntdev.h
header-test- += xen/privcmd.h

# More headers are broken in some architectures

ifeq ($(SRCARCH),arc)
header-test- += linux/bpf_perf_event.h
endif

ifeq ($(SRCARCH),ia64)
header-test- += asm/setup.h
header-test- += asm/sigcontext.h
header-test- += asm/perfmon.h
header-test- += asm/perfmon_default_smpl.h
header-test- += linux/if_bonding.h
endif

ifeq ($(SRCARCH),mips)
header-test- += asm/stat.h
endif

ifeq ($(SRCARCH),powerpc)
header-test- += asm/stat.h
header-test- += linux/bpf_perf_event.h
endif

ifeq ($(SRCARCH),riscv)
header-test- += linux/bpf_perf_event.h
endif

ifeq ($(SRCARCH),s390)
header-test- += asm/runtime_instr.h
header-test- += asm/zcrypt.h
endif

ifeq ($(SRCARCH),sparc)
header-test- += asm/stat.h
header-test- += asm/uctx.h
header-test- += asm/fbio.h
header-test- += asm/openpromio.h
endif

# asm-generic/*.h is used by asm/*.h, and should not be included directly
header-test- += asm-generic/%

# The rest are compile-tested
header-test-y += $(filter-out $(header-test-), \
$(patsubst $(obj)/%,%, $(wildcard \
$(addprefix $(obj)/, *.h */*.h */*/*.h */*/*/*.h))))

# For GNU Make <= 4.2.1, $(wildcard $(obj)/*/) matches to not only directories
# but also regular files. Use $(filter %/, ...) just in case.
clean-dirs += $(patsubst $(obj)/%/,%,$(filter %/, $(wildcard $(obj)/*/)))

0 comments on commit d6fc9fc

Please sign in to comment.