Received: by 2002:a05:6359:c8b:b0:c7:702f:21d4 with SMTP id go11csp3823389rwb; Sun, 9 Oct 2022 11:43:13 -0700 (PDT) X-Google-Smtp-Source: AMsMyM51TBULxFfQxj6Y+cpT1qsu4J4na9uJriH9wY+x5wIXQqRb3Gyef4uf/WqxQPXg/GysMfHA X-Received: by 2002:a05:6a00:b85:b0:563:4623:ec40 with SMTP id g5-20020a056a000b8500b005634623ec40mr3103547pfj.56.1665340993162; Sun, 09 Oct 2022 11:43:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1665340993; cv=none; d=google.com; s=arc-20160816; b=JtZ6pQ6GC9N7yU1xgZkC1XEuDqe+n9Em7aNNSDuzqGNEsuee/JYTMsGsi83J/Gukj3 LvNLkhzUY7Zpsp1Kg985b1A6xGurf9z3hfMGHjvgPnpyBJMH2NWv/jbj5SYT4O4JZS+j L0bvmFUoEC5lOjHDKnjCAh/FFtahbQbmyMoF0ngbQ0jchXkm9oQz45OYXxTa42B0F9KN hUL3BMwKQP/1iuberZQObpbq4Pt3BP1RhMIgl7/htNGBHkEM7IZ0M7yJAyhoL3MUyRbQ BvmcjVKwOaIW6SLvgNgocH92StrLiHKaiuou1mmtlmtxH7mUa+sy3ZeDabPtNLqwaP5e qT8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from; bh=KfgLc+3R4sRuCXLbgA5ATcmW6mxvPd7H/UP3Xm8vv5k=; b=by8DQVqv7cqfk5DeEzPX/deYCe/h1V127sJWYQ4eAjJNFaAt5L12Cz4tLXyDPX1DAr CIrgfKQmZZK5MXTsvqJd8mMgZTnHA7sGosZx+ED2XftikQ8X4OFz5iIqKf+ZIlK0itUj 5u3Slw4AGr3OHpYGZdtufMt9JEINNU9p2r9w1ALC28Ikbd4gskWoq/QF7M2zV7oOFPhz pXBwnPXH9lhdU3bO1H0UX+A9Q9csTguyby4B1KLVkrEONxqXYEV3ZhHPbhDGXBig8ihT fGbDc1tngcCwNm29k+zggJq5S6ILKUzJDCe7gYaWxTB3PUol/OKLYnaX0oVPeU2Aoe2g yY0w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b13-20020a6567cd000000b0045957e1dc05si10629369pgs.876.2022.10.09.11.42.59; Sun, 09 Oct 2022 11:43:13 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230208AbiJISaN (ORCPT + 99 others); Sun, 9 Oct 2022 14:30:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229716AbiJISaK (ORCPT ); Sun, 9 Oct 2022 14:30:10 -0400 Received: from 1wt.eu (wtarreau.pck.nerim.net [62.212.114.60]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9B3E9167DB; Sun, 9 Oct 2022 11:30:08 -0700 (PDT) Received: (from willy@localhost) by pcw.home.local (8.15.2/8.15.2/Submit) id 299ITsUH029168; Sun, 9 Oct 2022 20:29:54 +0200 From: Willy Tarreau To: "Paul E. McKenney" Cc: Alexey Dobriyan , kernel test robot , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Willy Tarreau Subject: [PATCH v2] tools/nolibc: fix missing strlen() definition and infinite loop with gcc-12 Date: Sun, 9 Oct 2022 20:29:36 +0200 Message-Id: <20221009182936.29125-1-w@1wt.eu> X-Mailer: git-send-email 2.17.5 In-Reply-To: <20221009151939.28270-1-w@1wt.eu> References: <20221009151939.28270-1-w@1wt.eu> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_PASS, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 Link: https://lore.kernel.org/r/202210081618.754a77db-yujie.liu@intel.com Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Fixes: 96980b833a21 ("tools/nolibc/string: do not use __builtin_strlen() at -O0") Cc: "Paul E. McKenney" Cc: Alexey Dobriyan Signed-off-by: Willy Tarreau --- v2: dropped the attribute(optimize) in favor of an empty asm() statement --- tools/include/nolibc/string.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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)) -- 2.35.3