Linux ACPI
 help / color / mirror / Atom feed
* [PATCH v6 00/19] Add strprefix() and fix a bug with it
@ 2026-11-14 15:21 Alejandro Colomar
  2026-11-14 15:21 ` [PATCH v6 01/19] string: Add streq() Alejandro Colomar
                   ` (18 more replies)
  0 siblings, 19 replies; 29+ messages in thread
From: Alejandro Colomar @ 2026-11-14 15:21 UTC (permalink / raw)
  To: linux-hardening
  Cc: Alejandro Colomar, Krzysztof Kozlowski, Maciej W. Rozycki,
	Geert Uytterhoeven, Andreas Schwab, Andy Shevchenko,
	Bartosz Golaszewski, Daniel Scally, Danilo Krummrich,
	Greg Kroah-Hartman, Hans Verkuil, Heikki Krogerus, Joe Perches,
	Johan Hovold, Kees Cook, Laurent Pinchart, Len Brown,
	Linus Torvalds, Linus Walleij, Namhyung Kim, Rafael J. Wysocki,
	Rob Herring, Sakari Ailus, Saravana Kannan, Steven Rostedt,
	Tom Zanussi, linux-acpi, driver-core, linux-kernel, devicetree,
	linux-gpio

[-- Attachment #1: Type: text/plain, Size: 27469 bytes --]

Hi!

str_has_prefix() is based on sizes and lengths, which means it must
overload the valid length 0 to mean not found.  This is a typical
consequence of choosing to design an API around sizes and lengths, and
vanishes when moving to pointer-based similar APIs.

According to its author (Steven R.), str_has_prefix() was never meant to
accept an empty prefix, but that's not documented, and there's no
obvious reason why that would be acceptable for a generic string
function (as opposed to a function very specific to its original use).
Anyway, as suggested by Steven, I've added a WARN_ON_ONCE() to catch
such uses, and also added documentation stating this limitation.

Users of strings need a function whose behavior extends naturally to the
empty string, and we can do better, by returning a pointer.  And indeed,
users have ended up using str_has_prefix() with empty prefix, expecting
it to work (as is natural of a generic string API).

This patch set adds strprefix(), uses it to replace most uses of
str_has_prefix(), and notably uses strprefix() in one place to fix a bug
reported by Bartosz.

It also adds strsuffix(), for symmetry.  And it also adds streq(3), just
because it simplifies the tests, deduplicates some definitions of it,
and is also a nice interface.

The patch set also removes strstarts() and strends(), since strprefix()
and strsuffix() are drop-in replacements for them (apart from being
useful in more places).

This patch set also adds infrastructure to make string functions return
a pointer that is as qualified as the input pointer.

Changes in v6
~~~~~~~~~~~~~

-  [1/19]  ++ new patch ++
   -  Add streq(3), since it helps simplify some code in the rest of the
      patch set.
-  [2/19]
   -  Update Subject.
   -  Use Closes tag, and remove Andy from Cc.  [Andy]
   -  Add __attribute__((nonnull(1, 2))), for consistency with the
      existing strends().
-  [3/19]
   -  Don't add WARN_ON_ONCE() to str_has_prefix().  It's too
      problematic.  Just document the issue.  [Andy]
   -  Use Closes tag, and remove Andy from Cc.  [Andy]
-  [4/19]
   -  Use Closes tag, and remove Andy from Cc.  [Andy]
-  [5/19]  == no changes ==
-  [6/19]  == no changes ==
-  [7/19]  == no changes ==
-  [8/19]  ++ new patch ++
   -  Prepare for replacing strstarts() with strprefix().  [Andy]
-  [9/19]
   -  Make strstarts() an alias for strprefix(), in preparation for its
      removal.  [Andy]
-  [10/19]  ++ new patch ++
   -  Prepare for replacing strstarts() with strprefix().  [Andy]
-  [11/19]  ++ new patch ++
   -  Tree-wide replacement of strstarts() with strprefix().  [Andy]
-  [12/19]  ++ new patch ++
   -  Remove strstarts().  [Andy]
-  [13/19]  ++ new patch ++
   -  Prepare for replacing str_has_prefix() with strprefix().
-  [14/19]  ++ new patch ++
   -  Replace the trivial uses of str_has_prefix() with strprefix().
-  [15/19]  ++ new patch ++
   -  Replace some simple uses of str_has_prefic() with strprefix().
-  [16/19]  ++ new patch ++
   -  Add strsuffix() for symmetry.  [Andy]
-  [17/19]  ++ new patch ++
   -  Make strends() an alias for strsuffix(), in preparation for its
      removal.  [Andy]
-  [18/19]  ++ new patch ++
   -  Tree-wide replacement of strends() with strsuffix().  [Andy]
-  [19/19]  ++ new patch ++
   -  Remove strends().  [Andy]

See range-diff below.

v1: <https://lore.kernel.org/linux-hardening/cover.1793876837.git.alx@kernel.org/>
v2: <https://lore.kernel.org/linux-hardening/cover.1793882260.git.alx@kernel.org/>
v3: <https://lore.kernel.org/linux-hardening/cover.1794323750.git.alx@kernel.org/>
v4: <https://lore.kernel.org/linux-hardening/cover.1794425425.git.alx@kernel.org/>
v5: <https://lore.kernel.org/linux-hardening/cover.1794574496.git.alx@kernel.org/>

Testing
~~~~~~~

(I've indented the output, to better see the commands.)

$ git log --oneline --graph v7.4-rc1^..strprefix6
	* 8d5cac1ac296 (HEAD -> strprefix, tag: strprefix6) string: Remove strends()
	* 3cad861d3090 treewide: s/\<strends\>/strsuffix/g
	* 8aa3d317d63c string: Make strends() a legacy alias for strsuffix()
	* 636fe759a4eb string: Add strsuffix()
	* 95bfed420dd9 treewide: Replace some uses of str_has_prefix() by strprefix()
	* 0c0070455de0 treewide: Replace boolean uses of str_has_prefix() by strprefix()
	* 024364c695d5 s390/test_unwind: Use bool for booleans
	* cabc673b9ac7 string: Remove strstarts()
	* 782e2941d0f1 treewide: s/strstarts/strprefix/g
	* ec94f69d2925 platform/x86: hp-bioscfg: Rename local variable
	* 212e7fc2cb99 string: Make strstarts() a legacy alias for strprefix()
	* 8a3c50cfe298 perf map: Use bool for return type instead of int
	* 9def9160f777 string: Make strprefix() const-qualifier-generic
	* d9680e101472 string: Add [C]QChar_of() and QVoid_of()
	* 2a26768609bd stddef: Add const_cast()
	* 7fc1321995f1 device property: Fix fwnode_name_eq() for empty node names
	* 5648bb17b88a string: Document corner-case misbehavior in str_has_prefix() for empty prefix
	* 0eaa4ce73a2b string: Add strprefix()
	* cff11fd710fd string: Add streq()
	* 6628e7d4c6b2 (tag: v7.4-rc1, master) Linux 7.4-rc1
$ cp ../kunitconfig .kunitconfig
$ cat .kunitconfig
	CONFIG_KUNIT=y
	CONFIG_STRING_KUNIT_TEST=y
$ mkdir -p ~/tmp/strprefix6
$ export TMPDIR=$HOME/tmp/strprefix6/
$ ./tools/testing/kunit/kunit.py run "string*"
	[15:41:05] Configuring KUnit Kernel ...
	Generating .config ...
	Populating config with:
	$ make ARCH=um O=.kunit olddefconfig
	[15:41:08] Building KUnit Kernel ...
	Populating config with:
	$ make ARCH=um O=.kunit olddefconfig
	Building with:
	$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=24
	[15:41:23] Starting KUnit Kernel (1/1)...
	[15:41:23] ============================================================
	Running tests with:
	$ .kunit/linux 'kunit.filter_glob=string*' kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
	[15:41:24] ============= string-stream-test (12 subtests) =============
	[15:41:24] [PASSED] string_stream_managed_init_test
	[15:41:24] [PASSED] string_stream_unmanaged_init_test
	[15:41:24] [PASSED] string_stream_managed_free_test
	[15:41:24] [PASSED] string_stream_resource_free_test
	[15:41:24] [PASSED] string_stream_line_add_test
	[15:41:24] [PASSED] string_stream_variable_length_line_test
	[15:41:24] [PASSED] string_stream_append_test
	[15:41:24] [PASSED] string_stream_append_auto_newline_test
	[15:41:24] [PASSED] string_stream_append_empty_string_test
	[15:41:24] [PASSED] string_stream_no_auto_newline_test
	[15:41:24] [PASSED] string_stream_auto_newline_test
	[15:41:24] [PASSED] string_stream_performance_test
	[15:41:24] =============== [PASSED] string-stream-test ================
	[15:41:24] =================== string (29 subtests) ===================
	[15:41:24] [PASSED] string_test_memset16
	[15:41:24] [PASSED] string_test_memset32
	[15:41:24] [PASSED] string_test_memset64
	[15:41:24] [PASSED] string_test_strlen
	[15:41:24] [PASSED] string_test_strnlen
	[15:41:24] [PASSED] string_test_strchr
	[15:41:24] [PASSED] string_test_strnchr
	[15:41:24] [PASSED] string_test_strrchr
	[15:41:24] [PASSED] string_test_strspn
	[15:41:24] [PASSED] string_test_strprefix
	[15:41:24] [PASSED] string_test_strcmp
	[15:41:24] [PASSED] string_test_strcmp_long_strings
	[15:41:24] [PASSED] string_test_strncmp
	[15:41:24] [PASSED] string_test_strncmp_long_strings
	[15:41:24] [PASSED] string_test_strcasecmp
	[15:41:24] [PASSED] string_test_strcasecmp_long_strings
	[15:41:24] [PASSED] string_test_strncasecmp
	[15:41:24] [PASSED] string_test_strncasecmp_long_strings
	[15:41:24] [PASSED] string_test_strscpy
	[15:41:24] [PASSED] string_test_strcat
	[15:41:24] [PASSED] string_test_strncat
	[15:41:24] [PASSED] string_test_strlcat
	[15:41:24] [PASSED] string_test_strtomem
	[15:41:24] [PASSED] string_test_memtostr
	[15:41:24] [PASSED] string_test_strsuffix
	[15:41:24] [SKIPPED] string_bench_strlen (not enabled)
	[15:41:24] [SKIPPED] string_bench_strnlen (not enabled)
	[15:41:24] [SKIPPED] string_bench_strchr (not enabled)
	[15:41:24] [SKIPPED] string_bench_strrchr (not enabled)
	[15:41:24] ===================== [PASSED] string ======================
	[15:41:24] =============== string_helpers (4 subtests) ================
	[15:41:24] [PASSED] test_get_size
	[15:41:24] [PASSED] test_upper_lower
	[15:41:24] [PASSED] test_unescape
	[15:41:24] [PASSED] test_escape
	[15:41:24] ================= [PASSED] string_helpers ==================
	[15:41:24] ============================================================
	[15:41:24] Testing complete. Ran 45 tests: passed: 41, skipped: 4
	[15:41:24] Elapsed time: 18.895s total, 2.787s configuring, 15.842s building, 0.251s running

$ make allmodconfig
	  HOSTCC  scripts/basic/fixdep
	  HOSTCC  scripts/kconfig/conf.o
	  HOSTCC  scripts/kconfig/confdata.o
	  HOSTCC  scripts/kconfig/expr.o
	  LEX     scripts/kconfig/lexer.lex.c
	  YACC    scripts/kconfig/parser.tab.[ch]
	  HOSTCC  scripts/kconfig/lexer.lex.o
	  HOSTCC  scripts/kconfig/menu.o
	  HOSTCC  scripts/kconfig/parser.tab.o
	  HOSTCC  scripts/kconfig/preprocess.o
	  HOSTCC  scripts/kconfig/symbol.o
	  HOSTCC  scripts/kconfig/util.o
	  HOSTLD  scripts/kconfig/conf
	#
	# configuration written to .config
	#
$ time make -j24 | ts -s
	00:00:00   GEN     arch/x86/include/generated/asm/orc_hash.h
	00:00:00   UPD     arch/x86/include/generated/uapi/asm/bpf_perf_event.h
	00:00:00   UPD     arch/x86/include/generated/uapi/asm/errno.h
...
	00:20:14   LD [M]  net/qrtr/qrtr-tun.ko
	00:20:14   LD [M]  net/qrtr/qrtr-mhi.ko
	00:20:14   LD [M]  virt/lib/irqbypass.ko

	real	20m14.429s
	user	430m41.022s
	sys	24m28.452s


Have a lovely day!
Alex


Alejandro Colomar (19):
  string: Add streq()
  string: Add strprefix()
  string: Document corner-case misbehavior in str_has_prefix() for empty
    prefix
  device property: Fix fwnode_name_eq() for empty node names
  stddef: Add const_cast()
  string: Add [C]QChar_of() and QVoid_of()
  string: Make strprefix() const-qualifier-generic
  perf map: Use bool for return type instead of int
  string: Make strstarts() a legacy alias for strprefix()
  platform/x86: hp-bioscfg: Rename local variable
  treewide: s/strstarts/strprefix/g
  string: Remove strstarts()
  s390/test_unwind: Use bool for booleans
  treewide: Replace boolean uses of str_has_prefix() by strprefix()
  treewide: Replace some uses of str_has_prefix() by strprefix()
  string: Add strsuffix()
  string: Make strends() a legacy alias for strsuffix()
  treewide: s/\<strends\>/strsuffix/g
  string: Remove strends()

 arch/alpha/kernel/setup.c                     |   2 +-
 arch/arm/kernel/module.c                      |  12 +-
 arch/mips/bcm47xx/board.c                     |   4 +-
 arch/mips/bcm63xx/boards/board_bcm963xx.c     |   2 +-
 arch/parisc/kernel/setup.c                    |   2 +-
 arch/powerpc/perf/imc-pmu.c                   |   2 +-
 arch/powerpc/platforms/powernv/pci-ioda.c     |   2 +-
 arch/s390/kernel/early_printk.c               |   2 +-
 arch/s390/kernel/module.c                     |   6 +-
 arch/s390/kernel/setup.c                      |   4 +-
 arch/s390/lib/test_unwind.c                   |  19 +--
 crypto/essiv.c                                |   2 +-
 drivers/base/property.c                       |   5 +-
 drivers/clk/socfpga/clk-gate-a10.c            |   2 -
 drivers/clk/socfpga/clk.h                     |   1 -
 .../firmware/efi/libstub/efi-stub-helper.c    |   2 +-
 drivers/firmware/efi/libstub/gop.c            |  10 +-
 drivers/gpio/gpio-aggregator.c                |   2 +-
 drivers/gpio/gpiolib-shared.c                 |   8 +-
 drivers/gpu/drm/omapdrm/dss/base.c            |   2 +-
 .../gpu/drm/renesas/rcar-du/rcar_du_crtc.c    |   2 +-
 drivers/gpu/drm/xe/xe_configfs.c              |   6 +-
 drivers/hid/hid-uclogic-params.c              |   2 +-
 drivers/iio/pressure/hsc030pa.c               |   2 +-
 drivers/input/mouse/psmouse-base.c            |   2 +-
 drivers/input/mouse/trackpoint.c              |   2 +-
 drivers/md/dm-crypt.c                         |   4 +-
 drivers/md/dm-inlinecrypt.c                   |   2 +-
 drivers/media/i2c/ds90ub960.c                 |   2 +-
 drivers/memory/tegra/tegra20.c                |   4 +-
 drivers/mtd/spi-nor/issi.c                    |   2 +-
 drivers/net/ethernet/amd/pds_core/fw.c        |   5 +-
 drivers/net/ethernet/intel/ice/ice_parser.c   |  10 +-
 drivers/of/property.c                         |   6 +-
 drivers/pci/pwrctrl/core.c                    |   2 +-
 drivers/platform/x86/acerhdf.c                |   6 +-
 drivers/platform/x86/dell/dell-lis3lv02d.c    |   2 +-
 .../x86/hp/hp-bioscfg/spmobj-attributes.c     |  14 +-
 drivers/platform/x86/lenovo/thinkpad_acpi.c   |  54 ++++----
 drivers/platform/x86/touchscreen_dmi.c        |   2 +-
 drivers/remoteproc/imx_dsp_rproc.c            |   2 +-
 drivers/remoteproc/imx_rproc.c                |   8 +-
 drivers/remoteproc/mtk_scp.c                  |   2 +-
 drivers/remoteproc/st_remoteproc.c            |   2 +-
 drivers/remoteproc/stm32_rproc.c              |   2 +-
 drivers/remoteproc/xlnx_r5_remoteproc.c       |   2 +-
 .../media/atomisp/pci/atomisp_csi2_bridge.c   |   2 +-
 drivers/tty/serial/serial_base_bus.c          |   4 +-
 drivers/usb/dwc3/dwc3-pci.c                   |   2 +-
 drivers/usb/musb/musb_cppi41.c                |   4 +-
 drivers/usb/musb/musb_debugfs.c               |  20 +--
 fs/smb/client/reparse.c                       |  14 +-
 include/linux/stddef.h                        |  11 ++
 include/linux/string.h                        | 130 +++++++++++++-----
 init/main.c                                   |   2 +-
 kernel/debug/kdb/kdb_main.c                   |   2 +-
 kernel/kcsan/debugfs.c                        |   2 +-
 kernel/kcsan/report.c                         |   2 +-
 kernel/kprobes.c                              |   4 +-
 kernel/locking/locktorture.c                  |   8 +-
 kernel/module/kallsyms.c                      |   2 +-
 kernel/module/main.c                          |   8 +-
 kernel/power/main.c                           |   2 +-
 kernel/printk/braille.c                       |  14 +-
 kernel/trace/trace.c                          |   9 +-
 kernel/trace/trace_events.c                   |   5 +-
 kernel/trace/trace_events_hist.c              |  58 ++++----
 kernel/trace/trace_events_synth.c             |  10 +-
 kernel/trace/trace_events_user.c              |  22 +--
 kernel/trace/trace_probe.c                    |  22 +--
 kernel/trace/trace_stack.c                    |   6 +-
 lib/tests/string_kunit.c                      |  29 ++--
 mm/arch_numa.c                                |   2 +-
 mm/kfence/report.c                            |  14 +-
 .../hda/codecs/side-codecs/tas2781_hda_i2c.c  |   6 +-
 sound/soc/sdw_utils/soc_sdw_senary_sdca.c     |   2 +-
 tools/perf/util/map.c                         |   2 +-
 77 files changed, 364 insertions(+), 296 deletions(-)

Range-diff against v5:
 -:  ------------ >  1:  cff11fd710fd string: Add streq()
 1:  f25bf43d7f18 !  2:  0eaa4ce73a2b string: Add strprefix(), and deprecate str_has_prefix()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    string: Add strprefix(), and deprecate str_has_prefix()
    +    string: Add strprefix()
     
         As Bartosz reported, str_has_prefix() has a bug: it can't differentiate
         between an empty prefix matching an empty string from a non-matching
    @@ Commit message
         Move the description from str_has_prefix(), and describe
         str_has_prefix() by comparing it to strprefix().
     
    +    Closes: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
         Reported-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
    -    Link: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
    -    Cc: Andy Shevchenko <andy@kernel.org>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## include/linux/string.h ##
    @@ include/linux/string.h: void memcpy_and_pad(void *dest, size_t dest_len, const v
     + * *  @s + strlen(@prefix) if @s starts with @prefix
     + * *  NULL if @s does not start with @prefix
     + */
    ++__attribute__((nonnull(1, 2)))
     +static inline char *strprefix(const char *s, const char *prefix)
     +{
     +  size_t len = strlen(prefix);
    @@ lib/tests/string_kunit.c: static void string_test_strspn(struct kunit *test)
      
     +static void string_test_strprefix(struct kunit *test)
     +{
    -+  KUNIT_ASSERT_EQ(test, 0, strcmp(strprefix("foobar", "foo"), "bar"));
    -+  KUNIT_ASSERT_EQ(test, 0, strcmp(strprefix("foobar", ""), "foobar"));
    -+  KUNIT_ASSERT_EQ(test, 0, strcmp(strprefix("foobar", "foobar"), ""));
    ++  KUNIT_ASSERT_TRUE(test, streq(strprefix("foobar", "foo"), "bar"));
    ++  KUNIT_ASSERT_TRUE(test, streq(strprefix("foobar", ""), "foobar"));
    ++  KUNIT_ASSERT_TRUE(test, streq(strprefix("foobar", "foobar"), ""));
     +  KUNIT_ASSERT_NULL(test, strprefix("foobar", "bar"));
     +}
     +
 2:  df3a35c469c6 !  3:  5648bb17b88a string: Warn if the prefix is the empty string
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    string: Warn if the prefix is the empty string
    +    string: Document corner-case misbehavior in str_has_prefix() for empty prefix
     
    -    This corner case is mishandled by this function.
    -    Warn if it happens.  Also, document that if such corner case
    -    is needed, strprefix() is preferable.
    -
    -    We need to move str_has_prefix() to "lib/string.h" to be able to use
    -    WARN_ON_ONCE().
    +    For an empty prefix, this function returns a value that can't be
    +    distinguished from a non-matching prefix.  This is wrong, since an empty
    +    prefix is present in every string, and has resulted in bugs in code that
    +    called this function without knowing this issue.  Let's document it.
     
    +    Closes: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
         Reported-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
    -    Link: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
         Suggested-by: Steven Rostedt <rostedt@goodmis.org>
    -    Cc: Andy Shevchenko <andriy.shevchenko@intel.com>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## include/linux/string.h ##
    -@@ include/linux/string.h: extern char * strstr(const char *, const char *);
    - #ifndef __HAVE_ARCH_STRNSTR
    - extern char * strnstr(const char *, const char *, size_t);
    - #endif
    -+extern size_t str_has_prefix(const char *str, const char *prefix);
    - #ifndef __HAVE_ARCH_STRLEN
    - extern __kernel_size_t strlen(const char *);
    - #endif
     @@ include/linux/string.h: static inline char *strprefix(const char *s, const char *prefix)
    -   return strncmp(s, prefix, len) == 0 ? (char *) s + len : NULL;
    - }
    - 
    --/**
    -- * str_has_prefix - Test if a string has a given prefix
    -- * @str: The string to test
    -- * @prefix: The string to see if @str starts with
    -- *
    -- * This is similar to strprefix(), but returns an offset instead of
    -- * a pointer.
    -- *
    -- * Returns:
    -- * * strlen(@prefix) if @str starts with @prefix
    -- * * 0 if @str does not start with @prefix
    -- */
    --static __always_inline size_t str_has_prefix(const char *str, const char *prefix)
    --{
    --  size_t len = strlen(prefix);
    --  return strncmp(str, prefix, len) == 0 ? len : 0;
    --}
    --
    - /**
    -  * strstarts - does @str start with @prefix?
    -  * @str: string to examine
    -
    - ## lib/string.c ##
    -@@ lib/string.c: char *strnstr(const char *s1, const char *s2, size_t len)
    - EXPORT_SYMBOL(strnstr);
    - #endif
    - 
    -+/**
    -+ * str_has_prefix - Test if a string has a given prefix
    -+ * @str: The string to test
    -+ * @prefix: The string to see if @str starts with
    -+ *
    -+ * This is similar to strprefix(), but returns an offset instead of
    -+ * a pointer.
    -+ *
    +  * This is similar to strprefix(), but returns an offset instead of
    +  * a pointer.
    +  *
     + * Unlike for strprefix(), if the prefix is an empty string, the
     + * behavior is undefined.  If you need to support arbitrary prefixes,
     + * use strprefix().
     + *
    -+ * Returns:
    -+ * * strlen(@prefix) if @str starts with @prefix
    -+ * * 0 if @str does not start with @prefix
    -+ */
    -+size_t str_has_prefix(const char *str, const char *prefix)
    -+{
    -+  size_t len = strlen(prefix);
    -+  WARN_ON_ONCE(len == 0);
    -+  return strncmp(str, prefix, len) == 0 ? len : 0;
    -+}
    -+EXPORT_SYMBOL(str_has_prefix);
    -+
    - #ifndef __HAVE_ARCH_MEMCHR
    - /**
    -  * memchr - Find a character in an area of memory.
    +  * Returns:
    +  * * strlen(@prefix) if @str starts with @prefix
    +  * * 0 if @str does not start with @prefix
 3:  49252e78c9b6 !  4:  7fc1321995f1 device property: Fix fwnode_name_eq() for empty node names
    @@ Commit message
         Let's use strprefix() instead, which also makes this function simpler.
     
         Fixes: a9c8c738066b7 ("device property: Add fwnode_name_eq()")
    +    Closes: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
         Reported-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
    -    Link: https://lore.kernel.org/linux-hardening/20261104-fwnode-for-each-prop-v1-1-6e28fe1c72c4@oss.qualcomm.com/
    -    Cc: Andy Shevchenko <andy@kernel.org>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## drivers/base/property.c ##
 4:  b615b5afb05e =  5:  2a26768609bd stddef: Add const_cast()
 5:  1294b3d64440 !  6:  d9680e101472 string: Add [C]QChar_of() and QVoid_of()
    @@ include/linux/string.h
     +// CQChar_of - const qualified char of
     +#define CQChar_of(p)  QChar_of(const, p)
     +
    - extern char *strndup_user(const char __user *, long);
    - extern void *memdup_user(const void __user *, size_t) __realloc_size(2);
    - extern void *vmemdup_user(const void __user *, size_t) __realloc_size(2);
    + /**
    +  * streq - strings equal
    +  *
 6:  0ca0b7aabcfc !  7:  9def9160f777 string: Make strprefix() const-qualifier-generic
    @@ Commit message
     
      ## include/linux/string.h ##
     @@ include/linux/string.h: void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
    -  * *  @s + strlen(@prefix) if @s starts with @prefix
       * *  NULL if @s does not start with @prefix
       */
    + __attribute__((nonnull(1, 2)))
     -static inline char *strprefix(const char *s, const char *prefix)
     +static inline const char *strprefix(const char *s, const char *prefix)
      {
    @@ include/linux/string.h: void memcpy_and_pad(void *dest, size_t dest_len, const v
     +#define strprefix(s, pfx)  const_cast(CQChar_of(s) *, strprefix(s, pfx))
      
      /**
    -  * strstarts - does @str start with @prefix?
    +  * str_has_prefix - Test if a string has a given prefix
 -:  ------------ >  8:  8a3c50cfe298 perf map: Use bool for return type instead of int
 7:  382a44f7c686 !  9:  212e7fc2cb99 string: Implement strstarts() with strprefix()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    string: Implement strstarts() with strprefix()
    +    string: Make strstarts() a legacy alias for strprefix()
     
    -    The compiler should be able to optimize out the unused pointer
    -    arithmetic done at the end, so performance-wise this shouldn't change
    -    anything.
    +    strprefix() is drop-in compatible with strstarts() --but see caveats
    +    below--, and provides more functionality for cases where we're
    +    interested in the position where the prefix ends in the string.
     
    -    This change de-duplicates the almost-identical implementations,
    -    and better shows the relationship between the two functions.
    +    strprefix() returns a pointer that can be converted to bool.  This is
    +    converted implicitly in most places, but if the target type is not bool,
    +    then it might be problematic and require an explicit conversion with !!.
    +
    +    I checked that we don't need this anywhere, and also, I expect the
    +    compiler would likely diagnose in such a case, so this should be safe.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## include/linux/string.h ##
     @@ include/linux/string.h: static inline const char *strprefix(const char *s, const char *prefix)
    -  */
    - static inline bool strstarts(const char *str, const char *prefix)
    - {
    --  return strncmp(str, prefix, strlen(prefix)) == 0;
    -+  return strprefix(str, prefix);
    +   return strncmp(s, prefix, len) == 0 ? s + len : NULL;
      }
    + #define strprefix(s, pfx)  const_cast(CQChar_of(s) *, strprefix(s, pfx))
    ++#define strstarts(s, pfx)  strprefix(s, pfx)  // legacy alias
      
      /**
    +  * str_has_prefix - Test if a string has a given prefix
    +@@ include/linux/string.h: static __always_inline size_t str_has_prefix(const char *str, const char *prefix
    +   return strncmp(str, prefix, len) == 0 ? len : 0;
    + }
    + 
    +-/**
    +- * strstarts - does @str start with @prefix?
    +- * @str: string to examine
    +- * @prefix: prefix to look for.
    +- *
    +- * Returns:
    +- * True if @str begins with @prefix. False in all other cases.
    +- */
    +-static inline bool strstarts(const char *str, const char *prefix)
    +-{
    +-  return strncmp(str, prefix, strlen(prefix)) == 0;
    +-}
    +-
    + /**
    +  * strends - Check if a string ends with another string.
    +  * @str: NULL-terminated string to check against @suffix
 -:  ------------ > 10:  ec94f69d2925 platform/x86: hp-bioscfg: Rename local variable
 -:  ------------ > 11:  782e2941d0f1 treewide: s/strstarts/strprefix/g
 -:  ------------ > 12:  cabc673b9ac7 string: Remove strstarts()
 -:  ------------ > 13:  024364c695d5 s390/test_unwind: Use bool for booleans
 -:  ------------ > 14:  0c0070455de0 treewide: Replace boolean uses of str_has_prefix() by strprefix()
 -:  ------------ > 15:  95bfed420dd9 treewide: Replace some uses of str_has_prefix() by strprefix()
 -:  ------------ > 16:  636fe759a4eb string: Add strsuffix()
 -:  ------------ > 17:  8aa3d317d63c string: Make strends() a legacy alias for strsuffix()
 -:  ------------ > 18:  3cad861d3090 treewide: s/\<strends\>/strsuffix/g
 -:  ------------ > 19:  8d5cac1ac296 string: Remove strends()



-- 
2.55.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2026-11-14 19:00 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-14 15:21 [PATCH v6 00/19] Add strprefix() and fix a bug with it Alejandro Colomar
2026-11-14 15:21 ` [PATCH v6 01/19] string: Add streq() Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 02/19] string: Add strprefix() Alejandro Colomar
2026-11-14 15:28   ` Joe Perches
2026-11-14 17:03     ` Alejandro Colomar
2026-11-14 18:35       ` Alejandro Colomar
2026-11-14 15:53   ` Joe Perches
2026-11-14 16:59     ` Alejandro Colomar
2026-11-14 18:24       ` Joe Perches
2026-11-14 19:00         ` Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 03/19] string: Document corner-case misbehavior in str_has_prefix() for empty prefix Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 04/19] device property: Fix fwnode_name_eq() for empty node names Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 05/19] stddef: Add const_cast() Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 06/19] string: Add [C]QChar_of() and QVoid_of() Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 07/19] string: Make strprefix() const-qualifier-generic Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 08/19] perf map: Use bool for return type instead of int Alejandro Colomar
2026-11-14 15:22 ` [PATCH v6 09/19] string: Make strstarts() a legacy alias for strprefix() Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 10/19] platform/x86: hp-bioscfg: Rename local variable Alejandro Colomar
2026-11-14 16:04   ` Joe Perches
2026-11-14 17:08     ` Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 11/19] treewide: s/strstarts/strprefix/g Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 12/19] string: Remove strstarts() Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 13/19] s390/test_unwind: Use bool for booleans Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 14/19] treewide: Replace boolean uses of str_has_prefix() by strprefix() Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 15/19] treewide: Replace some " Alejandro Colomar
2026-11-14 15:23 ` [PATCH v6 16/19] string: Add strsuffix() Alejandro Colomar
2026-11-14 15:24 ` [PATCH v6 17/19] string: Make strends() a legacy alias for strsuffix() Alejandro Colomar
2026-11-14 15:24 ` [PATCH v6 18/19] treewide: s/\<strends\>/strsuffix/g Alejandro Colomar
2026-11-14 15:24 ` [PATCH v6 19/19] string: Remove strends() Alejandro Colomar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox