Linux: __bad_udelay in drivers/hwmon/applesmc.c

Created on 23 Sep 2019  路  16Comments  路  Source: ClangBuiltLinux/linux

Trying to compile kernel 5.3.1 with LLVM/clang-9.0.0 on x86_64

BUILDSTDERR: ERROR: "__bad_udelay" [drivers/hwmon/applesmc.ko] undefined!
BUILDSTDERR: make[1]: *** [scripts/Makefile.modpost:103: modules-modpost] Error 1
BUILDSTDERR: make: *** [Makefile:1306: modules] Error 2
[ARCH] x86_64 [BUG] linux [FIXED][LINUX] 5.8

Most helpful comment

All 16 comments

I don't see this on Linux 5.3.1 with LLVM 9.0.0:

diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index d0a5ffeae8df..ce670a9ed726 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -297,3 +297,5 @@ CONFIG_SECURITY_SELINUX_DISABLE=y
 CONFIG_EFI_STUB=y
 CONFIG_EFI_MIXED=y
 CONFIG_ACPI_BGRT=y
+CONFIG_INPUT=y
+CONFIG_SENSORS_APPLESMC=m

What kernel source and config are you using?

% readelf -p.comment ${KBF}/drivers/hwmon/applesmc.ko

String dump of section '.comment':
  [     1]  ClangBuiltLinux clang version 9.0.0 (git://github.com/llvm/llvm-project 0399d5a9682b3cef71c653373e38890c63c4c365) (based on LLVM 9.0.0)
  [    8a]  ClangBuiltLinux clang version 9.0.0 (git://github.com/llvm/llvm-project 0399d5a9682b3cef71c653373e38890c63c4c365) (based on LLVM 9.0.0)

Here are the sources:
https://github.com/OpenMandrivaAssociation/kernel-release/tree/clang
I've already disabled CONFIG_SENSORS_APPLESMC

Here is the failed build with full logs
https://abf.openmandriva.org/build_lists/610442

I've already disabled CONFIG_SENSORS_APPLESMC

Then it would be impossible to have the error "__bad_udelay" [drivers/hwmon/applesmc.ko] undefined! since the .ko would not be built.

That linkage failure occurs though when there's an issue in __builtin_constant_p. cc @gwelymernans

grep -n udelay drivers/hwmon/applesmc.c
162:        udelay(us);
184:        udelay(us);
196:        udelay(APPLESMC_RETRY_WAIT);
245:        udelay(APPLESMC_MIN_WAIT);

shows a few places where maybe udelay is not given an ICE.

This is related to your use of -O3:

% make -j$(nproc) -s CC=clang O=out distclean allyesconfig drivers/hwmon/applesmc.ko && nm out/drivers/hwmon/applesmc.ko | grep __bad_udelay
WARNING: modpost: missing MODULE_LICENSE() in drivers/hwmon/applesmc.o
see include/linux/module.h for more information

% make -j$(nproc) -s CC=clang KCFLAGS=-O3 O=out distclean allyesconfig drivers/hwmon/applesmc.ko && nm out/drivers/hwmon/applesmc.ko | grep __bad_udelay
WARNING: modpost: missing MODULE_LICENSE() in drivers/hwmon/applesmc.o
see include/linux/module.h for more information
                 U __bad_udelay

@nathanchance probably an interesting test case for LLVM.

I'll see what creduce spits out

@tpgxyz if you're setting -O3 or have other non-standard kernel patches, please put that in the initial report.

a() {
  int b = 10;
  for (; b; b <<= 1)
    if (__builtin_constant_p(b))
      __bad_udelay();
    else
      c();
}

creduce results (files). Corresponds to wait_read and send_byte.

super optimizer! https://godbolt.org/z/upRwsr
Clang's loop unroller figured out that the loop will execute 27 iterations before 0x10 <<= i overflows an int32. Unfortunately, it seems that it did not figure out BCP correctly. (cc @jyknight )

So the LLVM bug was closed as WAI, and @stephenhines points out that left-shifting a signed integer is UB.

Both loops should perform bitwise arithmetic on unsigned ints, and have a break like https://github.com/torvalds/linux/blob/9f7582d15f82e86b2041ab22327b7d769e061c1f/drivers/hwmon/applesmc.c#L193-L194 to exit the loop.

Clang may be right here; udelay results in a link error when its parameter is larger than 20000. wait_read iterates up to APPLESMC_MAX_WAIT, which is 0x20000 (HEX!!! == 131072 in decimal).

https://github.com/torvalds/linux/blob/9f7582d15f82e86b2041ab22327b7d769e061c1f/drivers/hwmon/applesmc.c#L45

/* wait up to 128 ms for a status change. */

https://www.kernel.org/doc/Documentation/timers/timers-howto.rst mentions that mdelay is the preferred API to sleep 10ms+

Left-shifting a signed integer isn't necessarily UB, but this particular case is, since you are overflowing the calculation (sign bit changes unexpectedly in this case).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tpgxyz picture tpgxyz  路  4Comments

tpgxyz picture tpgxyz  路  4Comments

nickdesaulniers picture nickdesaulniers  路  4Comments

nathanchance picture nathanchance  路  4Comments

nathanchance picture nathanchance  路  3Comments