Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp2379377imu; Sat, 22 Dec 2018 21:04:10 -0800 (PST) X-Google-Smtp-Source: ALg8bN52Ma+xxRBuyPVr+XMNSI/ShGImEn6mOHhj4pbdbs03yQGfLm35TZey5JZj7qYqHLE6G7w+ X-Received: by 2002:a63:e516:: with SMTP id r22mr8392405pgh.256.1545541450402; Sat, 22 Dec 2018 21:04:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1545541450; cv=none; d=google.com; s=arc-20160816; b=r979wlhKju/S3uvZ57/fSS8jxHb0WGxAy1mEQJVQn8qH60MmVjKW39JESwLNi18iXH u2CSUmq2lasEjvu8VNrfZZ8DCKw9I8cGMLnXaL8goIu5OfbS4WsAGm8LQayhQ5aTNenj we9v8nesw5pE5CGsF6yBLGB2oZzzjgI9cwgStZ5ENbcm0mfBWouMKagMWHW31FomH7f1 fCS+DGwjP2bf/DXML0eLUjUV0GZPSn8Fxz45ZUlVNHWLx1keMZ2ph9jHT3jZkOORIGhK RGIMGuj0Pq/bQeAFQaFZlV8YlGHVmrwdPoPsRslGKS7Qplu+a66MakgBH7pAXWCwtBL1 4Wyw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:subject:cc:to:from:date; bh=+LNQ7WqmUC3i4w9uwnj2wcV9w/JH75/hkvNT9iVuJ+I=; b=XzL49NzKDhRFZC8Vi1pxQ8V/ME41hv1JopyW6JQe2Nqme34rZhU42p+cer6twz3OW7 JbSn2iiE1RqfTSs+GdiJDDOJ0XW4vzd2LsAvmL/oBPUamqN6tP4nIjPibBzZEr1FcC/N hVyJ2ukdqupTTm3mYJyzcU2FUvkOnK20/Pkevf40XiJ4crh/B1AT+yhFvds7bdrb1ChD ZPOrbl9ge/rrtaYb+l6Br144DGI/jWfdqDbNww87Fw7XmNvigfTDahwgUgv9QIXkM7bb 2j1Z5FaD5o4HjCkk8NWwYUCMbGjxysmjEx8Dnnk5PGIF316UKgrN4VVV2O4/fdl2xMuK fnNQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f189si25302367pfg.123.2018.12.22.21.03.54; Sat, 22 Dec 2018 21:04:10 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391720AbeLUTk5 (ORCPT + 99 others); Fri, 21 Dec 2018 14:40:57 -0500 Received: from mail.kernel.org ([198.145.29.99]:33108 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389698AbeLUTk5 (ORCPT ); Fri, 21 Dec 2018 14:40:57 -0500 Received: from gandalf.local.home (cpe-66-24-56-78.stny.res.rr.com [66.24.56.78]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id DD11E21927; Fri, 21 Dec 2018 19:40:55 +0000 (UTC) Date: Fri, 21 Dec 2018 14:40:54 -0500 From: Steven Rostedt To: Linus Torvalds Cc: Linux List Kernel Mailing , Ingo Molnar , Andrew Morton , Namhyung Kim , Masami Hiramatsu , Joe Perches , Tom Zanussi , Greg Kroah-Hartman Subject: Re: [for-next][PATCH 23/24] string.h: Add strncmp_prefix() helper macro Message-ID: <20181221144054.20bdeb33@gandalf.local.home> In-Reply-To: References: <20181221175618.968519903@goodmis.org> <20181221175659.208858193@goodmis.org> X-Mailer: Claws Mail 3.16.0 (GTK+ 2.24.32; x86_64-pc-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, 21 Dec 2018 10:51:29 -0800 Linus Torvalds wrote: > On Fri, Dec 21, 2018 at 9:57 AM Steven Rostedt wrote: > > > > I figured the best thing to do is to create a helper macro and place it > > into include/linux/string.h. And go around and fix all the open coded > > versions of it later. > > > > I plan on only applying this patch and updating the tracing hooks for > > this merge window. And perhaps use it to fix some of the bugs that were > > found. > > I like the helper function concept, but as they say about CS: "There > is only one hard problem in computer science: naming and off-by-one > errors". > > And this one has that problem. The name makes absolutely no sense. Good thing I rebased and put these patches at the end before running my tests :-) (Specifically because I was expecting to have feedback like this). > > Calling it "strncmp_prefix()" when there is no "n" there makes no sense. > > So drop the "n" from the name. I originally did that, but then I thought strcmp() is a full compare, and 'n' denotes it is partial. But thinking about it more, yeah one would think it would need a parameter to represent 'n'. > > And honestly, maybe it would be better to use a different naming > pattern entirely, and avoid the crazy non-boolean "str*cmp()" model. > That thing is useful for search comparisons (where "before/after" > matters), but it's horrible for the actual "is this true or not", > where the code ends up being > > if (!strcmp_prefix(a, "prefix")) { > // This is the "Yes, prefix matched" case, despite the > "if !" syntax > > which is just confusing. > > So I'd really prefer more of a > > #define has_prefix(str, prefix) ... I like changing the name. > > model that actually returns a boolean (true if it has a prefix, false > if it doesn't), rather than use the "str*cmp" naming and return > values. Actually, instead of returning a bool, it can return the length if it matches. Reason being, there's several locations that does something like: while (...) { len = strlen("const"); if (strncmp(str, "const", len) == 0) { str += len; break; } } And I was having trouble thinking about how to deal with these. But if we have a has_prefix() that returns the length on match then we can do: if ((len = has_prefix(str, "const")) { str += len; > > (But I agree that *if* you use the "strcmp" naming, then you do need > to hold to the traditional strcmp return value semantics). > > Hmm? > > Finally, I also suspect that your helper might be slightly fragile. > Doing sizeof() seems broken. I could see somebody using some prefix > define for arrays with constant sizes, and doing > > #define PFX1 "cpp\0" > #define PFX2 "c\0\0\0" > #define PFX3 "h\0\0\0" > > or similar. Also, is there a reason you use "&prefix" for the constant That was left over in my original tests in userspace. When I first tried it with __builtin_constant_p() I got an error, and added the '&', but then fixed something else. The something else was what actually caused the error, but since it didn't complain (and past all my tests), I left in the '&'. > test? I don't see that pattern anywhere else. Plus it looks entirely > wrong without the parenthesis (ie "&(prefix)" to make sure we group > things right). > > So a lot of small problems, but the naming one is big. OK, what about if we just use strlen() and say that this macro is not safe for parameters with side effects. -- Steve diff --git a/include/linux/string.h b/include/linux/string.h index 27d0482e5e05..f9d274a81276 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -14,6 +14,29 @@ extern void *memdup_user(const void __user *, size_t); extern void *vmemdup_user(const void __user *, size_t); extern void *memdup_user_nul(const void __user *, size_t); +/** + * have_prefix - Test if a string has a given prefix + * @str: The string to test + * @prefix: The string to see if @str starts with + * + * IMPORTANT; @prefix must not have side effects (used more than once here) + * + * A common way to test a prefix of a string is to do: + * strncmp(str, prefix, sizeof(prefix) - 1) + * + * But this can lead to bugs due to typos, or if prefix is a pointer + * and not a constant. Instead use has_prefix(). + * + * Returns: 0 if @str does not start with @prefix + strlen(@prefix) if @str does start with @prefix + */ +#define has_prefix(str, prefix) \ + ({ \ + int ____strcmp_prefix_len____ = strlen(prefix); \ + strncmp(str, prefix, ____strcmp_prefix_len____) == 0 ? \ + ____strcmp_prefix_len____ : 0; \ + }) + /* * Include machine specific inline routines */