[{"id":3680614,"web_url":"http://patchwork.ozlabs.org/comment/3680614/","msgid":"<46833eeb-72b9-4756-b750-6ab54355fe7f@linaro.org>","list_archive_url":null,"date":"2026-04-22T13:04:34","subject":"Re: [PATCH] misc: Optimize getusershell.c","submitter":{"id":66065,"url":"http://patchwork.ozlabs.org/api/people/66065/","name":"Adhemerval Zanella","email":"adhemerval.zanella@linaro.org"},"content":"On 20/04/26 10:05, Rocket Ma wrote:\n> * misc/getusershell.c: Completely rewrite the unit. Only allocate one\n> big buffer to store shell names. Add a missing unit test.\n> \n> The new implementation read the whole file into one buffer, and wipe out\n> every byte but shell names. Later when addressing shell names from first\n> shell, jump to next '\\0' and then jump to next '/'. This could reduce\n> memory footprint and shall improve some performance.\n> \n> Signed-off-by: Rocket Ma <marocketbd@gmail.com>\n\nThis has cause CI regressions [1]:\n\n  elf-check-localplt.out\n  \n  Extra PLT reference: libc.so: endusershell\n  Extra PLT reference: libc.so: fread\n  Extra PLT reference: libc.so: setbuf\n\nThis is due the use of the non-internal function names that generated extra\nPLT calls.\n\n[1] https://www.delorie.com/trybots/32bit/59989/\n\n> ---\n>  misc/Makefile                |   1 +\n>  misc/getusershell.c          | 272 +++++++++++++++++++----------------\n>  misc/tst-getusershell.c      |  75 ++++++++++\n>  misc/tst-getusershell.shells |   7 +\n>  4 files changed, 230 insertions(+), 125 deletions(-)\n>  create mode 100644 misc/tst-getusershell.c\n>  create mode 100644 misc/tst-getusershell.shells\n> \n> diff --git a/misc/Makefile b/misc/Makefile\n> index 4395366d74..31c930ef64 100644\n> --- a/misc/Makefile\n> +++ b/misc/Makefile\n> @@ -245,6 +245,7 @@ tests := \\\n>    tst-empty \\\n>    tst-error1 \\\n>    tst-fdset \\\n> +  tst-getusershell \\\n>    tst-hsearch \\\n>    tst-insremque \\\n>    tst-ioctl \\\n> diff --git a/misc/getusershell.c b/misc/getusershell.c\n> index 4221095dca..19394852a4 100644\n> --- a/misc/getusershell.c\n> +++ b/misc/getusershell.c\n> @@ -1,143 +1,165 @@\n> -/*\n> - * Copyright (c) 1985, 1993\n> - *\tThe Regents of the University of California.  All rights reserved.\n> - *\n> - * Redistribution and use in source and binary forms, with or without\n> - * modification, are permitted provided that the following conditions\n> - * are met:\n> - * 1. Redistributions of source code must retain the above copyright\n> - *    notice, this list of conditions and the following disclaimer.\n> - * 2. Redistributions in binary form must reproduce the above copyright\n> - *    notice, this list of conditions and the following disclaimer in the\n> - *    documentation and/or other materials provided with the distribution.\n> - * 4. Neither the name of the University nor the names of its contributors\n> - *    may be used to endorse or promote products derived from this software\n> - *    without specific prior written permission.\n> - *\n> - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n> - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n> - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n> - * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n> - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n> - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n> - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n> - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n> - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n> - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n> - * SUCH DAMAGE.\n> - */\n> -\n> -#if defined(LIBC_SCCS) && !defined(lint)\n> -static char sccsid[] = \"@(#)getusershell.c\t8.1 (Berkeley) 6/4/93\";\n> -#endif /* LIBC_SCCS and not lint */\n> -\n> -#include <sys/param.h>\n> -#include <sys/file.h>\n> -#include <sys/stat.h>\n> -#include <stdio.h>\n> -#include <stdio_ext.h>\n> +/* Copyright (C) 2026 The GNU Toolchain Authors.\n> +   This file is part of the GNU C Library.\n> +\n> +   The GNU C Library is free software; you can redistribute it and/or\n> +   modify it under the terms of the GNU Lesser General Public\n> +   License as published by the Free Software Foundation; either\n> +   version 2.1 of the License, or (at your option) any later version.\n> +\n> +   The GNU C Library is distributed in the hope that it will be useful,\n> +   but WITHOUT ANY WARRANTY; without even the implied warranty of\n> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> +   Lesser General Public License for more details.\n> +\n> +   You should have received a copy of the GNU Lesser General Public\n> +   License along with the GNU C Library; if not, see\n> +   <https://www.gnu.org/licenses/>.  */\n> +\n>  #include <ctype.h>\n> -#include <stdlib.h>\n> +#include <fcntl.h>\n> +#include <stddef.h>\n> +#include <stdio.h>\n> +#include <stdint.h>\n> +#include <sys/stat.h>\n>  #include <unistd.h>\n>  #include <paths.h>\n> +#include <stdlib.h>\n> +#include <string.h>\n>  \n> -/*\n> - * Local shells should NOT be added here.  They should be added in\n> - * /etc/shells.\n> - */\n> -\n> -/* NB: we do not initialize okshells here.  The initialization needs\n> -   relocations.  These interfaces are used so rarely that this is not\n> -   justified.  Instead explicitly initialize the array when it is\n> -   used.  */\n> -#if 0\n> -static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };\n> -#else\n> -static const char *okshells[3];\n> -#endif\n> -static char **curshell, **shells, *strings;\n> -static char **initshells (void) __THROW;\n> -\n> -/*\n> - * Get a list of shells from _PATH_SHELLS, if it exists.\n> - */\n> -char *\n> -getusershell (void)\n> +#define DEFAULT_SHELLS _PATH_BSHELL \"\\0\" _PATH_CSHELL\n> +\n> +static char *shellbuf;\n> +static char *shellend;\n> +static char *nextshell;\n> +\n> +static char *\n> +address_next_shell (void)\n>  {\n> -\tchar *ret;\n> -\n> -\tif (curshell == NULL)\n> -\t\tcurshell = initshells();\n> -\tret = *curshell;\n> -\tif (ret != NULL)\n> -\t\tcurshell++;\n> -\treturn (ret);\n> +  char *curshell;\n> +  char *next0;\n> +\n> +  curshell = nextshell;\n> +  if (nextshell == NULL)\n> +    return curshell;\n> +\n> +  /* init_shells guarantees we have a \\0 at the end */\n> +  next0 = memchr (nextshell, '\\0', shellend - nextshell);\n> +  if (next0 == NULL)\n> +    /* Unexpected, perhaps user modified our buffer? */\n> +    nextshell = NULL;\n> +  else\n> +    nextshell = memchr (next0, '/', shellend - next0);\n> +  return curshell;\n>  }\n>  \n> -void\n> -endusershell (void)\n> +/* Read /etc/shells, strip unnecessary bytes, and setup nextshell */\n> +static void\n> +init_shells (void)\n>  {\n> +  FILE *fp;\n> +  struct __stat64_t64 fstat;\n> +  size_t buflen;\n> +  char *top;\n> +  char *line_start, *line_end;\n> +  char *slash, *discard;\n> +\n> +  endusershell ();\n> +\n> +  if ((fp = fopen (_PATH_SHELLS, \"rce\")) == NULL)\n> +    goto default_out;\n> +  if ((__fstat64_time64 (fileno (fp), &fstat)) == -1)\n> +    goto close_out;\n> +  /* Consider if buflen will overflow. */\n> +  if (fstat.st_size < 2 || fstat.st_size > PTRDIFF_MAX - 1)\n> +    goto close_out;\n> +  /* 1 byte for \\n (will be overwritten as \\0). */\n> +  buflen = fstat.st_size + 1;\n> +  if ((shellbuf = malloc (buflen)) == NULL)\n> +    goto close_out;\n> +  shellbuf[buflen - 1] = '\\n';\n> +  setbuf (fp, NULL);\n> +  if ((fread (shellbuf, 1, fstat.st_size, fp)) != fstat.st_size)\n> +    goto free_out;\n> +\n> +  top = shellbuf + buflen;\n> +  line_start = shellbuf;\n> +  while ((line_end = memchr (line_start, '\\n', top - line_start)) != NULL)\n> +    {\n> +      line_end++; /* include \\n */\n> +      discard = line_start;\n> +\n> +      slash = memchr (line_start, '/', line_end - line_start);\n> +      if (slash == NULL)\n> +\tgoto wipe_line;\n> +\n> +      discard = memchr (line_start, '#', line_end - line_start);\n> +      if (discard != NULL && discard < slash)\n> +\tgoto wipe_line;\n> +\n> +      (void) memset (line_start, '\\0', slash - line_start);\n> +      discard = slash;\n> +      while (discard < line_end && *discard != '#'\n> +\t     && !isspace ((unsigned char) *discard))\n> +\tdiscard++;\n> +\n> +    wipe_line:\n> +      (void) memset (discard, '\\0', line_end - discard);\n> +      line_start = line_end;\n> +    }\n> +\n> +  if ((nextshell = memchr (shellbuf, '/', top - shellbuf)) == NULL)\n> +    goto free_out;\n> +  shellend = top;\n> +  (void) fclose (fp);\n> +  return;\n>  \n> -\tfree(shells);\n> -\tshells = NULL;\n> -\tfree(strings);\n> -\tstrings = NULL;\n> -\tcurshell = NULL;\n> +free_out:\n> +  free (shellbuf);\n> +  shellbuf = NULL;\n> +close_out:\n> +  (void) fclose (fp);\n> +default_out:\n> +  shellbuf = malloc (sizeof (DEFAULT_SHELLS));\n> +  if (shellbuf == NULL)\n> +    {\n> +      /* Can't allocate a buffer to store default shells,\n> +\t use read-only string to avoid unexpected user write.\n> +\t Leave shellbuf as NULL so that it can be freed. */\n> +      nextshell = (char *) DEFAULT_SHELLS;\n> +      shellend = (char *) DEFAULT_SHELLS + sizeof (DEFAULT_SHELLS);\n> +    }\n> +  else\n> +    {\n> +      memcpy (shellbuf, DEFAULT_SHELLS, sizeof (DEFAULT_SHELLS));\n> +      nextshell = shellbuf;\n> +      shellend = shellbuf + sizeof (DEFAULT_SHELLS);\n> +    }\n> +}\n> +\n> +char *\n> +getusershell (void)\n> +{\n> +  if (shellend == NULL)\n> +    init_shells ();\n> +  return address_next_shell ();\n>  }\n>  \n>  void\n>  setusershell (void)\n>  {\n> -\n> -\tcurshell = initshells();\n> +  if (shellend == NULL)\n> +    init_shells ();\n> +  else if (shellbuf != NULL)\n> +    nextshell = memchr (shellbuf, '/', shellend - shellbuf);\n> +  else /* shellend != NULL && shellbuf == NULL */\n> +    nextshell = (char *) DEFAULT_SHELLS;\n>  }\n>  \n> -static char **\n> -initshells (void)\n> +void\n> +endusershell (void)\n>  {\n> -\tchar **sp, *cp;\n> -\tFILE *fp;\n> -\tstruct __stat64_t64 statb;\n> -\tsize_t flen;\n> -\n> -\tfree(shells);\n> -\tshells = NULL;\n> -\tfree(strings);\n> -\tstrings = NULL;\n> -\tif ((fp = fopen(_PATH_SHELLS, \"rce\")) == NULL)\n> -\t\tgoto init_okshells_noclose;\n> -\tif (__fstat64_time64(fileno(fp), &statb) == -1) {\n> -\tinit_okshells:\n> -\t\t(void)fclose(fp);\n> -\tinit_okshells_noclose:\n> -\t\tokshells[0] = _PATH_BSHELL;\n> -\t\tokshells[1] = _PATH_CSHELL;\n> -\t\treturn (char **) okshells;\n> -\t}\n> -\tif (statb.st_size > ~(size_t)0 / sizeof (char *) * 3)\n> -\t\tgoto init_okshells;\n> -\tflen = statb.st_size + 3;\n> -\tif ((strings = malloc(flen)) == NULL)\n> -\t\tgoto init_okshells;\n> -\tshells = malloc(statb.st_size / 3 * sizeof (char *));\n> -\tif (shells == NULL) {\n> -\t\tfree(strings);\n> -\t\tstrings = NULL;\n> -\t\tgoto init_okshells;\n> -\t}\n> -\tsp = shells;\n> -\tcp = strings;\n> -\twhile (fgets_unlocked(cp, flen - (cp - strings), fp) != NULL) {\n> -\t\twhile (*cp != '#' && *cp != '/' && *cp != '\\0')\n> -\t\t\tcp++;\n> -\t\tif (*cp == '#' || *cp == '\\0' || cp[1] == '\\0')\n> -\t\t\tcontinue;\n> -\t\t*sp++ = cp;\n> -\t\twhile (!isspace(*cp) && *cp != '#' && *cp != '\\0')\n> -\t\t\tcp++;\n> -\t\t*cp++ = '\\0';\n> -\t}\n> -\t*sp = NULL;\n> -\t(void)fclose(fp);\n> -\treturn (shells);\n> +  free (shellbuf);\n> +  shellbuf = NULL;\n> +  shellend = NULL;\n> +  nextshell = NULL;\n>  }\n> diff --git a/misc/tst-getusershell.c b/misc/tst-getusershell.c\n> new file mode 100644\n> index 0000000000..b2f71804d8\n> --- /dev/null\n> +++ b/misc/tst-getusershell.c\n> @@ -0,0 +1,75 @@\n> +/* Test the getusershell series functions.\n> +   Copyright (C) 2026 The GNU Toolchain Authors.\n> +   This file is part of the GNU C Library.\n> +\n> +   The GNU C Library is free software; you can redistribute it and/or\n> +   modify it under the terms of the GNU Lesser General Public\n> +   License as published by the Free Software Foundation; either\n> +   version 2.1 of the License, or (at your option) any later version.\n> +\n> +   The GNU C Library is distributed in the hope that it will be useful,\n> +   but WITHOUT ANY WARRANTY; without even the implied warranty of\n> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> +   Lesser General Public License for more details.\n> +\n> +   You should have received a copy of the GNU Lesser General Public\n> +   License along with the GNU C Library; if not, see\n> +   <https://www.gnu.org/licenses/>.  */\n> +\n> +#include \"support/temp_file.h\"\n> +#include <stdlib.h>\n> +#include <unistd.h>\n> +#include <paths.h>\n> +#include <support/check.h>\n> +#include <support/xunistd.h>\n> +#include <support/support.h>\n> +#include <support/namespace.h>\n> +#include <support/test-driver.h>\n> +\n> +static void\n> +test_in_chroot (void *chroot_path)\n> +{\n> +  xchroot (chroot_path);\n> +\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/bash\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/usr/bin/zsh\");\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +\n> +  setusershell ();\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  endusershell ();\n> +\n> +  xunlink (\"/etc/shells\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/csh\");\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +  endusershell ();\n> +}\n> +\n> +static int\n> +do_test (void)\n> +{\n> +  support_become_root ();\n> +  if (!support_can_chroot ())\n> +    return EXIT_UNSUPPORTED;\n> +\n> +  char *chroot_dir = support_create_temp_directory(\"tst-getusershell-\");\n> +  char *etc = xasprintf(\"%s/etc\", chroot_dir);\n> +  add_temp_file(etc);\n> +  xmkdir(etc, 0777);\n> +  /* Don't add shells to file list as it will be deleted in test. */\n> +  char *shells = xasprintf(\"%s/shells\", etc);\n> +  support_copy_file(\"tst-getusershell.shells\", shells);\n> +\n> +  support_isolate_in_subprocess(test_in_chroot, chroot_dir);\n> +\n> +  free(etc);\n> +  free(shells);\n> +  free(chroot_dir);\n> +\n> +  return 0;\n> +}\n> +\n> +#include <support/test-driver.c>\n> diff --git a/misc/tst-getusershell.shells b/misc/tst-getusershell.shells\n> new file mode 100644\n> index 0000000000..fcc7675398\n> --- /dev/null\n> +++ b/misc/tst-getusershell.shells\n> @@ -0,0 +1,7 @@\n> +# test hash\n> +  # indentation\n> +\n> +/bin/sh\n> +\t/bin/bash # ...\n> +\n> +xx /usr/bin/zsh#...\n> \\ No newline at end of file","headers":{"Return-Path":"<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>","X-Original-To":["incoming@patchwork.ozlabs.org","libc-alpha@sourceware.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","libc-alpha@sourceware.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=Rnm5p9MD;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=Rnm5p9MD","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=linaro.org","sourceware.org; spf=pass smtp.mailfrom=linaro.org","server2.sourceware.org;\n arc=none smtp.remote-ip=2607:f8b0:4864:20::1232"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g0zwT47BHz1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 23:05:13 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8E9D34BBCD8F\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 13:05:11 +0000 (GMT)","from mail-dl1-x1232.google.com (mail-dl1-x1232.google.com\n [IPv6:2607:f8b0:4864:20::1232])\n by sourceware.org (Postfix) with ESMTPS id A95964BBCDC9\n for <libc-alpha@sourceware.org>; Wed, 22 Apr 2026 13:04:38 +0000 (GMT)","by mail-dl1-x1232.google.com with SMTP id\n a92af1059eb24-12c8cc7a77eso2158087c88.1\n for <libc-alpha@sourceware.org>; Wed, 22 Apr 2026 06:04:38 -0700 (PDT)","from ?IPV6:2804:1b3:a7c3:d5d0:bddf:fa51:e156:c28b?\n ([2804:1b3:a7c3:d5d0:bddf:fa51:e156:c28b])\n by smtp.gmail.com with ESMTPSA id\n a92af1059eb24-12c831d5b29sm23362050c88.8.2026.04.22.06.04.35\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 22 Apr 2026 06:04:36 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 8E9D34BBCD8F","OpenDKIM Filter v2.11.0 sourceware.org A95964BBCDC9"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org A95964BBCDC9","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org A95964BBCDC9","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776863078; cv=none;\n b=M+zjCXEDvqM3yv3G7ANYOgVBQu3GhZvDme/0reGxQkzAchZHPLgJJxBhHpOWQv0OE/rv9tRQGLdFHicu/Qw14VO/w0vegOUrZcuHDbBsA1dWP8f34wCIAuoyK0/kUQWH1sUO8Wcv2SVhwzY+XBMWttiGS5oCc3tCMSzT/+aeS80=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776863078; c=relaxed/simple;\n bh=KfZh64JWL+1FeCBW2HoeJ9VaBxWX2BO2o0nGW4U0nDE=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From;\n b=eoj/L0ul4MtkbyLOscxJVMyhlQhlcoCG46wjBwsHoblJmpXmxLG8/a5J3YcXZnx/3sW1MQV+az5blpt6ZECJmVsCKVPvGqgvg1qAxqAqYrRXaIj68EZByUGfJG44RNkKWHcZrzJsHXIPNN9s0Qk9U0LQ8KfCua9BNkPRjwtPF4E=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1776863078; x=1777467878; darn=sourceware.org;\n h=content-transfer-encoding:in-reply-to:organization:from\n :content-language:references:to:subject:user-agent:mime-version:date\n :message-id:from:to:cc:subject:date:message-id:reply-to;\n bh=9v48JZzPxifoPebYDg/2z7Z0wwOJqGfPpfFQsaYp/7k=;\n b=Rnm5p9MDz8olBQqQFEPVlaqSygl3dwnYG+E8F/nhnhSo1IsuIO+x3hEkC5WqLWXFHJ\n Xn1tbQvsNQp4kUKUc6i3ohRcv3yWrOO29Ozk1R1OqEkId6kmbDWgSHN6NzVoO8I7I2Jm\n bU7FgCHh94UEsHQU+Nb1cKahEFtlYJJvoN/KCRmwoK98Dg+OCs1cSDWnphXnS/UqGl68\n nOQquurco24La898pdxmBFj1cOoRvJoHSCpg92Bu0C4xFfzTjsdPaOW7Vu5MUDgIPYXZ\n BTM+zYSHcmM8GNQtntrwmobvT1LORyEKVYAmxEFVX5A1dXqk25jx+w20bM4ARJtydVtV\n bJgA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776863078; x=1777467878;\n h=content-transfer-encoding:in-reply-to:organization:from\n :content-language:references:to:subject:user-agent:mime-version:date\n :message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=9v48JZzPxifoPebYDg/2z7Z0wwOJqGfPpfFQsaYp/7k=;\n b=Ku1RzW/QLgyTQEWOxHDkHZt9ug/P/CB9xk63U87U7dg6S+hsTLTUb3Ctpsl9u6qVmd\n 6NvVRXZg860nRTWVx640wEOQKUmiDxvmWoyILyXJkLKnfEiBvrzjkTb5kjpchS7q4wbF\n R4tMxmNT59+DUL//Zkxkx4fBvyLTdx9OCzq4M6qbiBmxMQNzhs9rkpeIJ7kXDHGEqvkJ\n vtbpdKs3jMyNJALcBR2lsruIp1ggRtYmDLn9UCEunmmemE95GJKwyR3uxRY/YceKY7JI\n R7a0/oFow5n1Cj0dQLYJYE/jD+pZlnU0SHibpD+00wXzPRKaPFGWitd4SgRUXH/M3SSe\n +IxQ==","X-Forwarded-Encrypted":"i=1;\n AFNElJ+PNR5oq01/G8eBeUJV9mmPmrsMfQH947yZvyb8K8gl2oLA10v08+L2FDj4pgZN7FUO9S+ZnspdnZJW@sourceware.org","X-Gm-Message-State":"AOJu0YyDA9pVJ15CT50iHHA9/hyZw9V978ubyy+liEwqaJRoo0P/96hB\n v6d8Gwk9Eelt2P8F3SD+b1lxHRTWw/MrFsdFWF7QuXEUI3n+Si8Yl3fCpZ07y/IEW1y4HqOhDES\n OsNgh","X-Gm-Gg":"AeBDiesv1ukraB9hrmLExAxvAeQrxQrjZmPpVkQdVOg2Fxs4PBkUdbYRZ3YjRlO/igb\n VwXiVPjHGVHadS3R/NPOAcMgOU9xYq8Hh7rbPBKCgM/fALBUO9O0iPqsq2Gvf27cGCbSfXcfhlA\n +HhjNtJ83ufw+7GEitOmqGcATZno1bMvMMlz/kFsMXWdQNO51PNCDLRi7U1Jx3gLDAGsMEEbph2\n ZrBnxwP9Y4rqC+oifmxcDXiBdTtxZqDfuX1sw3Jkl+FeUy8nvoW0qE/bM4u0l/0VjYKxEIK0gt+\n ME4vvfvY93ZwJogzKHqAXUBIQmOa5j6X7KnjyluF98y+Qws1pX7tFj7UFzwmL+Blby5uRDyYHrj\n LuNFAIL5RcbC/JLidrwzKNTaNX8B+juTGUtzRQQvVo3MTZAxZSTI5P7kZB8DfyCe2qZMZj8GZ/1\n Ak9GpTZNBnQc4m1gw3oeJAKUKLnCnRQtO8TjNxP1ttJqTep67hLIQHB+0+2xp7THN7a/tbZnnPB\n aYn6SLhmz1dtagVG6DcJld3q8T7e0QaTK6sYnoGEhTg","X-Received":"by 2002:a05:7022:b88:b0:123:3c24:b15 with SMTP id\n a92af1059eb24-12c73b43fadmr8624342c88.19.1776863076966;\n Wed, 22 Apr 2026 06:04:36 -0700 (PDT)","Message-ID":"<46833eeb-72b9-4756-b750-6ab54355fe7f@linaro.org>","Date":"Wed, 22 Apr 2026 10:04:34 -0300","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] misc: Optimize getusershell.c","To":"Rocket Ma <marocketbd@gmail.com>, libc-alpha@sourceware.org","References":"<20260420130550.3404747-1-marocketbd@gmail.com>","Content-Language":"en-US","From":"Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>","Organization":"Linaro","In-Reply-To":"<20260420130550.3404747-1-marocketbd@gmail.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"7bit","X-BeenThere":"libc-alpha@sourceware.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Libc-alpha mailing list <libc-alpha.sourceware.org>","List-Unsubscribe":"<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>","List-Archive":"<https://sourceware.org/pipermail/libc-alpha/>","List-Post":"<mailto:libc-alpha@sourceware.org>","List-Help":"<mailto:libc-alpha-request@sourceware.org?subject=help>","List-Subscribe":"<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>","Errors-To":"libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org"}},{"id":3682013,"web_url":"http://patchwork.ozlabs.org/comment/3682013/","msgid":"<70a7356a-43a5-41d2-af1b-c03a822b7b90@linaro.org>","list_archive_url":null,"date":"2026-04-24T12:39:31","subject":"Re: [PATCH] misc: Optimize getusershell.c","submitter":{"id":66065,"url":"http://patchwork.ozlabs.org/api/people/66065/","name":"Adhemerval Zanella","email":"adhemerval.zanella@linaro.org"},"content":"On 20/04/26 10:05, Rocket Ma wrote:\n> * misc/getusershell.c: Completely rewrite the unit. Only allocate one\n> big buffer to store shell names. Add a missing unit test.\n> \n> The new implementation read the whole file into one buffer, and wipe out\n> every byte but shell names. Later when addressing shell names from first\n> shell, jump to next '\\0' and then jump to next '/'. This could reduce\n> memory footprint and shall improve some performance.\n> \n> Signed-off-by: Rocket Ma <marocketbd@gmail.com>\n\nThe patch seems ok, some minor comments (mostly style issues).\n\n> ---\n>  misc/Makefile                |   1 +\n>  misc/getusershell.c          | 272 +++++++++++++++++++----------------\n>  misc/tst-getusershell.c      |  75 ++++++++++\n>  misc/tst-getusershell.shells |   7 +\n>  4 files changed, 230 insertions(+), 125 deletions(-)\n>  create mode 100644 misc/tst-getusershell.c\n>  create mode 100644 misc/tst-getusershell.shells\n> \n> diff --git a/misc/Makefile b/misc/Makefile\n> index 4395366d74..31c930ef64 100644\n> --- a/misc/Makefile\n> +++ b/misc/Makefile\n> @@ -245,6 +245,7 @@ tests := \\\n>    tst-empty \\\n>    tst-error1 \\\n>    tst-fdset \\\n> +  tst-getusershell \\\n>    tst-hsearch \\\n>    tst-insremque \\\n>    tst-ioctl \\\n> diff --git a/misc/getusershell.c b/misc/getusershell.c\n> index 4221095dca..19394852a4 100644\n> --- a/misc/getusershell.c\n> +++ b/misc/getusershell.c\n> @@ -1,143 +1,165 @@\n> -/*\n> - * Copyright (c) 1985, 1993\n> - *\tThe Regents of the University of California.  All rights reserved.\n> - *\n> - * Redistribution and use in source and binary forms, with or without\n> - * modification, are permitted provided that the following conditions\n> - * are met:\n> - * 1. Redistributions of source code must retain the above copyright\n> - *    notice, this list of conditions and the following disclaimer.\n> - * 2. Redistributions in binary form must reproduce the above copyright\n> - *    notice, this list of conditions and the following disclaimer in the\n> - *    documentation and/or other materials provided with the distribution.\n> - * 4. Neither the name of the University nor the names of its contributors\n> - *    may be used to endorse or promote products derived from this software\n> - *    without specific prior written permission.\n> - *\n> - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n> - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n> - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n> - * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n> - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n> - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n> - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n> - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n> - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n> - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n> - * SUCH DAMAGE.\n> - */\n> -\n> -#if defined(LIBC_SCCS) && !defined(lint)\n> -static char sccsid[] = \"@(#)getusershell.c\t8.1 (Berkeley) 6/4/93\";\n> -#endif /* LIBC_SCCS and not lint */\n> -\n> -#include <sys/param.h>\n> -#include <sys/file.h>\n> -#include <sys/stat.h>\n> -#include <stdio.h>\n> -#include <stdio_ext.h>\n> +/* Copyright (C) 2026 The GNU Toolchain Authors.\n> +   This file is part of the GNU C Library.\n> +\n> +   The GNU C Library is free software; you can redistribute it and/or\n> +   modify it under the terms of the GNU Lesser General Public\n> +   License as published by the Free Software Foundation; either\n> +   version 2.1 of the License, or (at your option) any later version.\n> +\n> +   The GNU C Library is distributed in the hope that it will be useful,\n> +   but WITHOUT ANY WARRANTY; without even the implied warranty of\n> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> +   Lesser General Public License for more details.\n> +\n> +   You should have received a copy of the GNU Lesser General Public\n> +   License along with the GNU C Library; if not, see\n> +   <https://www.gnu.org/licenses/>.  */\n> +\n>  #include <ctype.h>\n> -#include <stdlib.h>\n> +#include <fcntl.h>\n> +#include <stddef.h>\n> +#include <stdio.h>\n> +#include <stdint.h>\n> +#include <sys/stat.h>\n>  #include <unistd.h>\n>  #include <paths.h>\n> +#include <stdlib.h>\n> +#include <string.h>\n>  \n> -/*\n> - * Local shells should NOT be added here.  They should be added in\n> - * /etc/shells.\n> - */\n> -\n> -/* NB: we do not initialize okshells here.  The initialization needs\n> -   relocations.  These interfaces are used so rarely that this is not\n> -   justified.  Instead explicitly initialize the array when it is\n> -   used.  */\n> -#if 0\n> -static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };\n> -#else\n> -static const char *okshells[3];\n> -#endif\n> -static char **curshell, **shells, *strings;\n> -static char **initshells (void) __THROW;\n> -\n> -/*\n> - * Get a list of shells from _PATH_SHELLS, if it exists.\n> - */\n> -char *\n> -getusershell (void)\n> +#define DEFAULT_SHELLS _PATH_BSHELL \"\\0\" _PATH_CSHELL\n> +\n> +static char *shellbuf;\n> +static char *shellend;\n> +static char *nextshell;\n> +\n> +static char *\n> +address_next_shell (void)\n>  {\n> -\tchar *ret;\n> -\n> -\tif (curshell == NULL)\n> -\t\tcurshell = initshells();\n> -\tret = *curshell;\n> -\tif (ret != NULL)\n> -\t\tcurshell++;\n> -\treturn (ret);\n> +  char *curshell;\n> +  char *next0;\n> +\n> +  curshell = nextshell;\n> +  if (nextshell == NULL)\n> +    return curshell;\n> +\n> +  /* init_shells guarantees we have a \\0 at the end */\n> +  next0 = memchr (nextshell, '\\0', shellend - nextshell);\n> +  if (next0 == NULL)\n> +    /* Unexpected, perhaps user modified our buffer? */\n> +    nextshell = NULL;\n\nI don't think should allow users changing the return value, nor we have this\nset in function contract.  Maybe an assert would be better here.\n\n> +  else\n> +    nextshell = memchr (next0, '/', shellend - next0);\n> +  return curshell;\n>  }\n>  \n> -void\n> -endusershell (void)\n> +/* Read /etc/shells, strip unnecessary bytes, and setup nextshell */\n> +static void\n> +init_shells (void)\n>  {\n> +  FILE *fp;\n> +  struct __stat64_t64 fstat;\n> +  size_t buflen;\n> +  char *top;\n> +  char *line_start, *line_end;\n> +  char *slash, *discard;\n> +\n> +  endusershell ();\n> +\n> +  if ((fp = fopen (_PATH_SHELLS, \"rce\")) == NULL)\n> +    goto default_out;\n\nWe try to avoid assignment and comparison in the same expression, we\nprefer to:\n\n  fp = fopen (_PATH_SHELLS, \"rce\");\n  if (fp == NULL)\n     ...\n\n> +  if ((__fstat64_time64 (fileno (fp), &fstat)) == -1)\n> +    goto close_out;\n> +  /* Consider if buflen will overflow. */\n> +  if (fstat.st_size < 2 || fstat.st_size > PTRDIFF_MAX - 1)\n> +    goto close_out;\n> +  /* 1 byte for \\n (will be overwritten as \\0). */\n> +  buflen = fstat.st_size + 1;\n> +  if ((shellbuf = malloc (buflen)) == NULL)\n> +    goto close_out;\n> +  shellbuf[buflen - 1] = '\\n';\n> +  setbuf (fp, NULL);\n> +  if ((fread (shellbuf, 1, fstat.st_size, fp)) != fstat.st_size)\n> +    goto free_out;\n> +\n> +  top = shellbuf + buflen;\n> +  line_start = shellbuf;\n> +  while ((line_end = memchr (line_start, '\\n', top - line_start)) != NULL)\n> +    {\n> +      line_end++; /* include \\n */\n> +      discard = line_start;\n> +\n> +      slash = memchr (line_start, '/', line_end - line_start);\n> +      if (slash == NULL)\n> +\tgoto wipe_line;\n> +\n> +      discard = memchr (line_start, '#', line_end - line_start);\n> +      if (discard != NULL && discard < slash)\n> +\tgoto wipe_line;\n> +\n> +      (void) memset (line_start, '\\0', slash - line_start);\n> +      discard = slash;\n> +      while (discard < line_end && *discard != '#'\n> +\t     && !isspace ((unsigned char) *discard))\n> +\tdiscard++;\n> +\n> +    wipe_line:\n> +      (void) memset (discard, '\\0', line_end - discard);\n> +      line_start = line_end;\n> +    }\n> +\n> +  if ((nextshell = memchr (shellbuf, '/', top - shellbuf)) == NULL)\n> +    goto free_out;\n> +  shellend = top;\n> +  (void) fclose (fp);\n> +  return;\n>  \n> -\tfree(shells);\n> -\tshells = NULL;\n> -\tfree(strings);\n> -\tstrings = NULL;\n> -\tcurshell = NULL;\n> +free_out:\n> +  free (shellbuf);\n> +  shellbuf = NULL;\n> +close_out:\n> +  (void) fclose (fp);\n> +default_out:\n> +  shellbuf = malloc (sizeof (DEFAULT_SHELLS));\n\nThe current implementation already sets and returns read-only strings,\nso the implicit function contract is user are not supposed to write on\nthe getusershell returned values.  So I think there is no much gain in\nreturning allocated strings here.\n\n> +  if (shellbuf == NULL)\n> +    {\n> +      /* Can't allocate a buffer to store default shells,\n> +\t use read-only string to avoid unexpected user write.\n> +\t Leave shellbuf as NULL so that it can be freed. */\n> +      nextshell = (char *) DEFAULT_SHELLS;\n> +      shellend = (char *) DEFAULT_SHELLS + sizeof (DEFAULT_SHELLS);\n> +    }\n> +  else\n> +    {\n> +      memcpy (shellbuf, DEFAULT_SHELLS, sizeof (DEFAULT_SHELLS));\n> +      nextshell = shellbuf;\n> +      shellend = shellbuf + sizeof (DEFAULT_SHELLS);\n> +    }\n> +}\n> +\n> +char *\n> +getusershell (void)\n> +{\n> +  if (shellend == NULL)\n> +    init_shells ();\n> +  return address_next_shell ();\n>  }\n>  \n>  void\n>  setusershell (void)\n>  {\n> -\n> -\tcurshell = initshells();\n> +  if (shellend == NULL)\n> +    init_shells ();\n> +  else if (shellbuf != NULL)\n> +    nextshell = memchr (shellbuf, '/', shellend - shellbuf);\n> +  else /* shellend != NULL && shellbuf == NULL */\n> +    nextshell = (char *) DEFAULT_SHELLS;\n>  }\n>  \n> -static char **\n> -initshells (void)\n> +void\n> +endusershell (void)\n>  {\n> -\tchar **sp, *cp;\n> -\tFILE *fp;\n> -\tstruct __stat64_t64 statb;\n> -\tsize_t flen;\n> -\n> -\tfree(shells);\n> -\tshells = NULL;\n> -\tfree(strings);\n> -\tstrings = NULL;\n> -\tif ((fp = fopen(_PATH_SHELLS, \"rce\")) == NULL)\n> -\t\tgoto init_okshells_noclose;\n> -\tif (__fstat64_time64(fileno(fp), &statb) == -1) {\n> -\tinit_okshells:\n> -\t\t(void)fclose(fp);\n> -\tinit_okshells_noclose:\n> -\t\tokshells[0] = _PATH_BSHELL;\n> -\t\tokshells[1] = _PATH_CSHELL;\n> -\t\treturn (char **) okshells;\n> -\t}\n> -\tif (statb.st_size > ~(size_t)0 / sizeof (char *) * 3)\n> -\t\tgoto init_okshells;\n> -\tflen = statb.st_size + 3;\n> -\tif ((strings = malloc(flen)) == NULL)\n> -\t\tgoto init_okshells;\n> -\tshells = malloc(statb.st_size / 3 * sizeof (char *));\n> -\tif (shells == NULL) {\n> -\t\tfree(strings);\n> -\t\tstrings = NULL;\n> -\t\tgoto init_okshells;\n> -\t}\n> -\tsp = shells;\n> -\tcp = strings;\n> -\twhile (fgets_unlocked(cp, flen - (cp - strings), fp) != NULL) {\n> -\t\twhile (*cp != '#' && *cp != '/' && *cp != '\\0')\n> -\t\t\tcp++;\n> -\t\tif (*cp == '#' || *cp == '\\0' || cp[1] == '\\0')\n> -\t\t\tcontinue;\n> -\t\t*sp++ = cp;\n> -\t\twhile (!isspace(*cp) && *cp != '#' && *cp != '\\0')\n> -\t\t\tcp++;\n> -\t\t*cp++ = '\\0';\n> -\t}\n> -\t*sp = NULL;\n> -\t(void)fclose(fp);\n> -\treturn (shells);\n> +  free (shellbuf);\n> +  shellbuf = NULL;\n> +  shellend = NULL;\n> +  nextshell = NULL;\n>  }\n> diff --git a/misc/tst-getusershell.c b/misc/tst-getusershell.c\n> new file mode 100644\n> index 0000000000..b2f71804d8\n> --- /dev/null\n> +++ b/misc/tst-getusershell.c\n> @@ -0,0 +1,75 @@\n> +/* Test the getusershell series functions.\n> +   Copyright (C) 2026 The GNU Toolchain Authors.\n> +   This file is part of the GNU C Library.\n> +\n> +   The GNU C Library is free software; you can redistribute it and/or\n> +   modify it under the terms of the GNU Lesser General Public\n> +   License as published by the Free Software Foundation; either\n> +   version 2.1 of the License, or (at your option) any later version.\n> +\n> +   The GNU C Library is distributed in the hope that it will be useful,\n> +   but WITHOUT ANY WARRANTY; without even the implied warranty of\n> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n> +   Lesser General Public License for more details.\n> +\n> +   You should have received a copy of the GNU Lesser General Public\n> +   License along with the GNU C Library; if not, see\n> +   <https://www.gnu.org/licenses/>.  */\n> +\n> +#include \"support/temp_file.h\"\n> +#include <stdlib.h>\n> +#include <unistd.h>\n> +#include <paths.h>\n> +#include <support/check.h>\n> +#include <support/xunistd.h>\n> +#include <support/support.h>\n> +#include <support/namespace.h>\n> +#include <support/test-driver.h>\n> +\n> +static void\n> +test_in_chroot (void *chroot_path)\n> +{\n> +  xchroot (chroot_path);\n> +\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/bash\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/usr/bin/zsh\");\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +\n> +  setusershell ();\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  endusershell ();\n> +\n> +  xunlink (\"/etc/shells\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/sh\");\n> +  TEST_COMPARE_STRING (getusershell (), \"/bin/csh\");\n> +  TEST_COMPARE_STRING (getusershell (), NULL);\n> +  endusershell ();\n> +}\n> +\n> +static int\n> +do_test (void)\n> +{\n> +  support_become_root ();\n> +  if (!support_can_chroot ())\n> +    return EXIT_UNSUPPORTED;\n> +\n> +  char *chroot_dir = support_create_temp_directory(\"tst-getusershell-\");\n\nMissing space before '(' here and below.\n\n> +  char *etc = xasprintf(\"%s/etc\", chroot_dir);\n> +  add_temp_file(etc);\n> +  xmkdir(etc, 0777);\n> +  /* Don't add shells to file list as it will be deleted in test. */\n> +  char *shells = xasprintf(\"%s/shells\", etc);\n> +  support_copy_file(\"tst-getusershell.shells\", shells);\n> +\n> +  support_isolate_in_subprocess(test_in_chroot, chroot_dir);\n> +\n> +  free(etc);\n> +  free(shells);\n> +  free(chroot_dir);\n> +\n> +  return 0;\n> +}\n> +\n> +#include <support/test-driver.c>\n> diff --git a/misc/tst-getusershell.shells b/misc/tst-getusershell.shells\n> new file mode 100644\n> index 0000000000..fcc7675398\n> --- /dev/null\n> +++ b/misc/tst-getusershell.shells\n> @@ -0,0 +1,7 @@\n> +# test hash\n> +  # indentation\n> +\n> +/bin/sh\n> +\t/bin/bash # ...\n> +\n> +xx /usr/bin/zsh#...\n> \\ No newline at end of file","headers":{"Return-Path":"<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>","X-Original-To":["incoming@patchwork.ozlabs.org","libc-alpha@sourceware.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","libc-alpha@sourceware.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=CJ011V+7;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=CJ011V+7","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=linaro.org","sourceware.org; spf=pass smtp.mailfrom=linaro.org","server2.sourceware.org;\n arc=none smtp.remote-ip=2607:f8b0:4864:20::1332"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g2CGf2w5Bz1xvV\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 22:40:04 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8F3DA4BB589F\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 12:40:00 +0000 (GMT)","from mail-dy1-x1332.google.com (mail-dy1-x1332.google.com\n [IPv6:2607:f8b0:4864:20::1332])\n by sourceware.org (Postfix) with ESMTPS id 194A24BB3B9E\n for <libc-alpha@sourceware.org>; Fri, 24 Apr 2026 12:39:37 +0000 (GMT)","by mail-dy1-x1332.google.com with SMTP id\n 5a478bee46e88-2b6b0500e06so12353567eec.1\n for <libc-alpha@sourceware.org>; Fri, 24 Apr 2026 05:39:37 -0700 (PDT)","from ?IPV6:2804:1b3:a7c0:44cb:6d39:8695:6380:f6f4?\n ([2804:1b3:a7c0:44cb:6d39:8695:6380:f6f4])\n by smtp.gmail.com with ESMTPSA id\n 5a478bee46e88-2e53d4bdaf7sm30675597eec.25.2026.04.24.05.39.33\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Fri, 24 Apr 2026 05:39:34 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 8F3DA4BB589F","OpenDKIM Filter v2.11.0 sourceware.org 194A24BB3B9E"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 194A24BB3B9E","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 194A24BB3B9E","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777034377; cv=none;\n b=rK3jUMpiutF/Z1Ujk37BOTOfuOch0xxCqdXw26I+T0ntl4N9PD9YRHryaxf1tEJZ4UFgH7DTBSYpwOg4lFfnNwlyrW1G3UetwGuHnhVrEtEaBRHn8IGryCIEceIIpyeIYB6mnBhY/gE+c1Cv+g9H7/LdYieP/1f0YLQByma+phY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777034377; c=relaxed/simple;\n bh=W7AbtbQ9NiLyCObSKsq39L3hBWgtc63awL0Wqh7rKs8=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From;\n b=rI+WyEMmADWCDYfsy/Skssg7T5WyMIPeX01que6IioPbXNQrmozMyf9Qp/7euL3kM/NB0x02TKNIhIc3/PvIBH7YZe0wXF90t19MI9Lh8dU+L0YnUx0QQVKRDar5ZzDquGfgt5bQ4uqspwrJUKER4h+LgwX9JMOiTAUYvV1hl8k=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1777034376; x=1777639176; darn=sourceware.org;\n h=content-transfer-encoding:in-reply-to:organization:from\n :content-language:references:to:subject:user-agent:mime-version:date\n :message-id:from:to:cc:subject:date:message-id:reply-to;\n bh=MonJtmCjus1e2I+PkiOhcVompvf+T909yLFbultl0RI=;\n b=CJ011V+7ABfjTv5NWixCEqpKN7hRqIa2FLjIx99zIL3s+411oAeNyFiNG1SkbRNd4U\n 0/VZZk6BaQ0j9OrboUst/+oj8M6hQ1NaHPADqiVrgXmQPlcVfugDrdxlbYgpWVSboKY7\n wY39IUA4Ible5rZLMBSMbWaASJpUqlD1+d5mM6jHT3GlgnVnVocX/EtILQrhCC7fDbZd\n q0uItNL75hcA+V+MC8d/0YOPNXGa2NHHOmYmsi3BIKb2N5q6H8dvMdL3uv06qPvxt3Sv\n 2Q9GnJn3Ztbz+qsr/ep5wardTvfTFNCd3WDLP/xmvwpED6h9MQk0HEi39+plGUlnWw5V\n p4Hw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777034376; x=1777639176;\n h=content-transfer-encoding:in-reply-to:organization:from\n :content-language:references:to:subject:user-agent:mime-version:date\n :message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=MonJtmCjus1e2I+PkiOhcVompvf+T909yLFbultl0RI=;\n b=re/DSq6mcGPyhJSvA30uDHyOITa7gO3Ui8aAISlvCXu8y+nxkWz3WSYslZgvLR5ZQH\n Yzkv73F0eJ5PTeJEYv5XW/jQtxA0zJXD7MaZsfinpbqUlIIPDM3DGaucP/A6lIyScfwm\n FExNx7BYoSHCgpLKk42rLkAnNLXrmvWScDP0JTpgHA4ms9thopGwmueXW85uy7El7cVI\n G86s6hT4PRZI1Im2QVqpINgMqoppV7q4Vm0sBOOuH0V2dffA7uNmKPrAe0tMZ261a1oc\n 6NHILbwnGVciMQo6km/9HaC2AdWzu/Kb0AX533owJ63jRmIkWBX8qgh7Bx94Woa2DtQ9\n R1uw==","X-Gm-Message-State":"AOJu0YxfG5wLMYsPdzOraun9bz7zeMIcok87qisr71ySIwKuuaQyO8Y4\n p55U/Er0LhWPKiMktAAIRGkDGP/7PJJD24qJZdg6+M66dgskk9CCv+IAoI3qWrA0TuS1wi+nOLq\n 8JLN5","X-Gm-Gg":"AeBDievK9GqBdeNahfyCTviTHiQhy3IbCxjBQ0Z+eWAEEh7wY+aJ1V/PNSNTgTL4nbd\n MAafRY7M50sxPF6qJFkS1xVG9dznJZkNjbeCPBsWEFmhBX/VFH/cyasw8DTdEvfPuL4TqB67iG0\n UjUyAHBJ1w1B6oGkwt5ePLmaFY+Hx/6lN5/B93BH7t0BPx3TL646BYhz9iqLtB0tiUoLMTJMmxj\n H1l6ACWQyWgLgjhH0kPhWZ+1X7NDIlpnhHRcn+WARrsCZkoeVidRIa6Zi/Lhd00ZK3D+K8cV8ca\n rJPcy82MvzX9zoyEH4FD7MBBaMHgG3vEGrz5q/r/NTDoJNxS0liNYAPfMRdXSxTnkeCqB6qsX6G\n /NMIkP2XTp8WwLrrn/3/d3y35mcqHBWfzBr5wdVIIuCfYl02UEUjOtxiXePLMM4DJ3Wr6YYE+6U\n utzIZJJZlUVuaWq7JLkWQlrZ5f9UoN9xezT8/U7rb6qN3fu/YcqpKA9js6Py5cneH3hdv5HafFE\n xuS+oOn/K+YHQc5kS4SEaTpl7y4qVjTthcF2z/BzHBm","X-Received":"by 2002:a05:7301:1f17:b0:2ea:b975:3db1 with SMTP id\n 5a478bee46e88-2eab9753fd9mr6411959eec.23.1777034375200;\n Fri, 24 Apr 2026 05:39:35 -0700 (PDT)","Message-ID":"<70a7356a-43a5-41d2-af1b-c03a822b7b90@linaro.org>","Date":"Fri, 24 Apr 2026 09:39:31 -0300","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] misc: Optimize getusershell.c","To":"libc-alpha@sourceware.org, Rocket Ma <marocketbd@gmail.com>","References":"<20260420130550.3404747-1-marocketbd@gmail.com>","Content-Language":"en-US","From":"Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>","Organization":"Linaro","In-Reply-To":"<20260420130550.3404747-1-marocketbd@gmail.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"7bit","X-BeenThere":"libc-alpha@sourceware.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Libc-alpha mailing list <libc-alpha.sourceware.org>","List-Unsubscribe":"<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>","List-Archive":"<https://sourceware.org/pipermail/libc-alpha/>","List-Post":"<mailto:libc-alpha@sourceware.org>","List-Help":"<mailto:libc-alpha-request@sourceware.org?subject=help>","List-Subscribe":"<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>","Errors-To":"libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org"}}]