Patch "tools/nolibc: Fix missing strlen() definition and infinite loop with gcc-12" has been added to the 6.0-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    tools/nolibc: Fix missing strlen() definition and infinite loop with gcc-12

to the 6.0-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     tools-nolibc-fix-missing-strlen-definition-and-infin.patch
and it can be found in the queue-6.0 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 75deb3bd05620447f0faa5307478821fa918f907
Author: Willy Tarreau <w@xxxxxx>
Date:   Sun Oct 9 20:29:36 2022 +0200

    tools/nolibc: Fix missing strlen() definition and infinite loop with gcc-12
    
    [ Upstream commit bfc3b0f05653a28c8d41067a2aa3875d1f982e3e ]
    
    When built at -Os, gcc-12 recognizes an strlen() pattern in nolibc_strlen()
    and replaces it with a jump to strlen(), which is not defined as a symbol
    and breaks compilation. Worse, when the function is called strlen(), the
    function is simply replaced with a jump to itself, hence becomes an
    infinite loop.
    
    One way to avoid this is to always set -ffreestanding, but the calling
    code doesn't know this and there's no way (either via attributes or
    pragmas) to globally enable it from include files, effectively leaving
    a painful situation for the caller.
    
    Alexey suggested to place an empty asm() statement inside the loop to
    stop gcc from recognizing a well-known pattern, which happens to work
    pretty fine. At least it allows us to make sure our local definition
    is not replaced with a self jump.
    
    The function only needs to be renamed back to strlen() so that the symbol
    exists, which implies that nolibc_strlen() which is used on variable
    strings has to be declared as a macro that points back to it before the
    strlen() macro is redifined.
    
    It was verified to produce valid code with gcc 3.4 to 12.1 at different
    optimization levels, and both with constant and variable strings.
    
    In case this problem surfaces again in the future, an alternate approach
    consisting in adding an optimize("no-tree-loop-distribute-patterns")
    function attribute for gcc>=12 worked as well but is less pretty.
    
    Reported-by: kernel test robot <yujie.liu@xxxxxxxxx>
    Link: https://lore.kernel.org/r/202210081618.754a77db-yujie.liu@xxxxxxxxx
    Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc")
    Fixes: 96980b833a21 ("tools/nolibc/string: do not use __builtin_strlen() at -O0")
    Cc: "Paul E. McKenney" <paulmck@xxxxxxxxxx>
    Cc: Alexey Dobriyan <adobriyan@xxxxxxxxx>
    Signed-off-by: Willy Tarreau <w@xxxxxx>
    Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h
index bef35bee9c44..718a405ffbc3 100644
--- a/tools/include/nolibc/string.h
+++ b/tools/include/nolibc/string.h
@@ -125,14 +125,18 @@ char *strcpy(char *dst, const char *src)
 }
 
 /* this function is only used with arguments that are not constants or when
- * it's not known because optimizations are disabled.
+ * it's not known because optimizations are disabled. Note that gcc 12
+ * recognizes an strlen() pattern and replaces it with a jump to strlen(),
+ * thus itself, hence the asm() statement below that's meant to disable this
+ * confusing practice.
  */
 static __attribute__((unused))
-size_t nolibc_strlen(const char *str)
+size_t strlen(const char *str)
 {
 	size_t len;
 
-	for (len = 0; str[len]; len++);
+	for (len = 0; str[len]; len++)
+		asm("");
 	return len;
 }
 
@@ -140,13 +144,12 @@ size_t nolibc_strlen(const char *str)
  * the two branches, then will rely on an external definition of strlen().
  */
 #if defined(__OPTIMIZE__)
+#define nolibc_strlen(x) strlen(x)
 #define strlen(str) ({                          \
 	__builtin_constant_p((str)) ?           \
 		__builtin_strlen((str)) :       \
 		nolibc_strlen((str));           \
 })
-#else
-#define strlen(str) nolibc_strlen((str))
 #endif
 
 static __attribute__((unused))



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux