public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/azanella/tunables] elf: Do not duplicate GLIBC_TUNABLES string
@ 2023-10-06 14:28 Adhemerval Zanella
0 siblings, 0 replies; only message in thread
From: Adhemerval Zanella @ 2023-10-06 14:28 UTC (permalink / raw)
To: glibc-cvs
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=1a73ac45a777578853b219fc5055fde4b9c7ab0a
commit 1a73ac45a777578853b219fc5055fde4b9c7ab0a
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri Oct 6 11:25:54 2023 -0300
elf: Do not duplicate GLIBC_TUNABLES string
TODO: maybe adds extra tests
TODO: add comment why add spans to GLIBC_TUNABLES is safe
Diff:
---
elf/dl-tunables.c | 58 +++++----------
elf/dl-tunables.h | 6 +-
sysdeps/generic/dl-tunables-parse.h | 98 ++++++++++++++++++++++++++
sysdeps/s390/cpu-features.c | 47 +++++-------
sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 38 ++++++----
sysdeps/unix/sysv/linux/powerpc/cpu-features.c | 49 ++++++-------
sysdeps/x86/cpu-tunables.c | 55 +++++++--------
7 files changed, 207 insertions(+), 144 deletions(-)
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 6b5661dce4..ab76d4364a 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -36,28 +36,6 @@
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
-#include <not-errno.h>
-
-static char *
-tunables_strdup (const char *in)
-{
- size_t i = 0;
-
- while (in[i++] != '\0');
- char *out = __minimal_malloc (i + 1);
-
- /* For most of the tunables code, we ignore user errors. However,
- this is a system error - and running out of memory at program
- startup should be reported, so we do. */
- if (out == NULL)
- _dl_fatal_printf ("failed to allocate memory to process tunables\n");
-
- while (i-- > 0)
- out[i] = in[i];
-
- return out;
-}
-
static char **
get_next_env (char **envp, char **name, size_t *namelen, char **val,
char ***prev_envp)
@@ -134,14 +112,14 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
/* Validate range of the input value and initialize the tunable CUR if it looks
good. */
static void
-tunable_initialize (tunable_t *cur, const char *strval)
+tunable_initialize (tunable_t *cur, const char *strval, size_t len)
{
- tunable_val_t val;
+ tunable_val_t val = { 0 };
if (cur->type.type_code != TUNABLE_TYPE_STRING)
val.numval = (tunable_num_t) _dl_strtoul (strval, NULL);
else
- val.strval = strval;
+ val.strval = (struct tunable_str_t) { strval, len };
do_tunable_update_val (cur, &val, NULL, NULL);
}
@@ -158,6 +136,7 @@ struct tunable_toset_t
{
tunable_t *t;
const char *value;
+ size_t len;
};
enum { tunables_list_size = array_length (tunable_list) };
@@ -166,18 +145,18 @@ enum { tunables_list_size = array_length (tunable_list) };
where delimiters ':' are replaced with '\0', so string tunables are null
terminated. */
static int
-parse_tunables_string (char *valstring, struct tunable_toset_t *tunables)
+parse_tunables_string (const char *valstring, struct tunable_toset_t *tunables)
{
if (valstring == NULL || *valstring == '\0')
return 0;
- char *p = valstring;
+ const char *p = valstring;
bool done = false;
int ntunables = 0;
while (!done)
{
- char *name = p;
+ const char *name = p;
/* First, find where the name ends. */
while (*p != '=' && *p != ':' && *p != '\0')
@@ -199,7 +178,7 @@ parse_tunables_string (char *valstring, struct tunable_toset_t *tunables)
/* Skip the ':' or '='. */
p++;
- char *value = p;
+ const char *value = p;
while (*p != '=' && *p != ':' && *p != '\0')
p++;
@@ -208,8 +187,6 @@ parse_tunables_string (char *valstring, struct tunable_toset_t *tunables)
return 0;
else if (*p == '\0')
done = true;
- else
- *p++ = '\0';
/* Add the tunable if it exists. */
for (size_t i = 0; i < tunables_list_size; i++)
@@ -218,7 +195,8 @@ parse_tunables_string (char *valstring, struct tunable_toset_t *tunables)
if (tunable_is_name (cur->name, name))
{
- tunables[ntunables++] = (struct tunable_toset_t) { cur, value };
+ tunables[ntunables++] =
+ (struct tunable_toset_t) { cur, value, p - value };
break;
}
}
@@ -228,12 +206,12 @@ parse_tunables_string (char *valstring, struct tunable_toset_t *tunables)
}
static void
-parse_tunables (char *valstring)
+parse_tunables (const char *valstring)
{
struct tunable_toset_t tunables[tunables_list_size];
int ntunables = parse_tunables_string (valstring, tunables);
for (int i = 0; i < ntunables; i++)
- tunable_initialize (tunables[i].t, tunables[i].value);
+ tunable_initialize (tunables[i].t, tunables[i].value, tunables[i].len);
}
/* Initialize the tunables list from the environment. For now we only use the
@@ -256,7 +234,7 @@ __tunables_init (char **envp)
{
if (tunable_is_name ("GLIBC_TUNABLES", envname))
{
- parse_tunables (tunables_strdup (envval));
+ parse_tunables (envval);
continue;
}
@@ -274,7 +252,7 @@ __tunables_init (char **envp)
/* We have a match. Initialize and move on to the next line. */
if (tunable_is_name (name, envname))
{
- tunable_initialize (cur, envval);
+ tunable_initialize (cur, envval, 0);
break;
}
}
@@ -288,7 +266,7 @@ __tunables_print (void)
{
const tunable_t *cur = &tunable_list[i];
if (cur->type.type_code == TUNABLE_TYPE_STRING
- && cur->val.strval == NULL)
+ && cur->val.strval.str == NULL)
_dl_printf ("%s:\n", cur->name);
else
{
@@ -314,7 +292,9 @@ __tunables_print (void)
(size_t) cur->type.max);
break;
case TUNABLE_TYPE_STRING:
- _dl_printf ("%s\n", cur->val.strval);
+ _dl_printf ("%.*s\n",
+ (int) cur->val.strval.len,
+ cur->val.strval.str);
break;
default:
__builtin_unreachable ();
@@ -349,7 +329,7 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
}
case TUNABLE_TYPE_STRING:
{
- *((const char **)valp) = cur->val.strval;
+ *((struct tunable_str_t **) valp) = &cur->val.strval;
break;
}
default:
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
index 45c191e021..0e777d7d37 100644
--- a/elf/dl-tunables.h
+++ b/elf/dl-tunables.h
@@ -30,7 +30,11 @@ typedef intmax_t tunable_num_t;
typedef union
{
tunable_num_t numval;
- const char *strval;
+ struct tunable_str_t
+ {
+ const char *str;
+ size_t len;
+ } strval;
} tunable_val_t;
typedef void (*tunable_callback_t) (tunable_val_t *);
diff --git a/sysdeps/generic/dl-tunables-parse.h b/sysdeps/generic/dl-tunables-parse.h
new file mode 100644
index 0000000000..83cecaf416
--- /dev/null
+++ b/sysdeps/generic/dl-tunables-parse.h
@@ -0,0 +1,98 @@
+/* Helper functions to handle tunable strings.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_TUNABLES_PARSE_H
+#define _DL_TUNABLES_PARSE_H 1
+
+#ifndef DEFAULT_MEMCMP
+# define DEFAULT_MEMCMP memcmp
+#endif
+
+/* Compare the contents of STRVAL with STR of size LEN. The STR might not
+ be null-terminated. */
+static inline bool
+tunable_strcmp (const struct tunable_str_t *strval, const char *str,
+ size_t len)
+{
+ return strval->len == len && DEFAULT_MEMCMP (strval->str, str, len) == 0;
+}
+#define tunable_strcmp_cte(__tunable, __str) \
+ ({ \
+ __builtin_constant_p (__str) \
+ ? tunable_strcmp (&__tunable->strval, __str, sizeof (__str) - 1) \
+ : tunable_strcmp (&__tunable->strval, __str, strlen (__str)); \
+ })
+
+/* Helper function to iterate over string tunable composed by multiple
+ suboptions separated by comma. The tunable is represented as span (address
+ and size) from GLIBC_TUNABLES, so it might not be null terminated.
+
+ For instance, to print all the items:
+
+ struct tunable_str_comma_t st;
+ tunable_str_comma_init (&st, valp);
+
+ struct tunable_str_t tstr;
+ while (tunable_str_comma_next (&st, &tstr))
+ {
+ if (tstr.len == 0)
+ continue;
+
+ _dl_printf ("[%s] %.*s (%d)\n", __func__,
+ (int) tstr.len,
+ tstr.str,
+ (int) tstr.len);
+ } */
+
+struct tunable_str_comma_t
+{
+ const char *p;
+ size_t plen;
+ size_t maxplen;
+};
+
+static inline void
+tunable_str_comma_init (struct tunable_str_comma_t *state, tunable_val_t *valp)
+{
+ state->p = valp->strval.str;
+ state->plen = 0;
+ state->maxplen = valp->strval.len;
+}
+
+static inline bool
+tunable_str_comma_next (struct tunable_str_comma_t *state,
+ struct tunable_str_t *str)
+{
+ if (*state->p == '\0' || state->plen >= state->maxplen)
+ return false;
+
+ const char *c;
+ for (c = state->p; *c != ','; c++, state->plen++)
+ if (*c == '\0' || state->plen == state->maxplen)
+ break;
+
+ str->str = state->p;
+ str->len = c - state->p;
+
+ state->p = c + 1;
+ state->plen++;
+
+ return true;
+}
+
+#endif
diff --git a/sysdeps/s390/cpu-features.c b/sysdeps/s390/cpu-features.c
index 39f8c23a60..c1898d8e1e 100644
--- a/sysdeps/s390/cpu-features.c
+++ b/sysdeps/s390/cpu-features.c
@@ -22,6 +22,7 @@
#include <ifunc-memcmp.h>
#include <string.h>
extern __typeof (memcmp) MEMCMP_DEFAULT;
+#include <dl-tunables-parse.h>
#define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR) \
(DEST_PTR)->hwcap = (SRC_PTR)->hwcap; \
@@ -51,32 +52,23 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
struct cpu_features cpu_features_curr;
S390_COPY_CPU_FEATURES (cpu_features, &cpu_features_curr);
- const char *token = valp->strval;
- do
+ struct tunable_str_comma_t st;
+ tunable_str_comma_init (&st, valp);
+
+ struct tunable_str_t tstr;
+ while (tunable_str_comma_next (&st, &tstr))
{
- const char *token_end, *feature;
- bool disable;
- size_t token_len;
- size_t feature_len;
-
- /* Find token separator or end of string. */
- for (token_end = token; *token_end != ','; token_end++)
- if (*token_end == '\0')
- break;
-
- /* Determine feature. */
- token_len = token_end - token;
- if (*token == '-')
- {
- disable = true;
- feature = token + 1;
- feature_len = token_len - 1;
- }
- else
+ if (tstr.len == 0)
+ continue;
+
+ const char *feature = tstr.str;
+ size_t feature_len = tstr.len;
+
+ bool disable = *feature == '-';
+ if (disable)
{
- disable = false;
- feature = token;
- feature_len = token_len;
+ feature = feature + 1;
+ feature_len = feature_len - 1;
}
/* Handle only the features here which are really used in the
@@ -187,14 +179,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
else
cpu_features_curr.stfle_bits[0] |= stfle_bits0_mask;
}
-
- /* Jump over current token ... */
- token += token_len;
-
- /* ... and skip token separator for next round. */
- if (*token == ',') token++;
}
- while (*token != '\0');
/* Copy back the features after checking that no unsupported features were
enabled by user. */
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index dc09c1c827..3f1a6bcd62 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -16,10 +16,12 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <array_length.h>
#include <cpu-features.h>
#include <sys/auxv.h>
#include <elf/dl-hwcaps.h>
#include <sys/prctl.h>
+#include <dl-tunables-parse.h>
#define DCZID_DZP_MASK (1 << 4)
#define DCZID_BS_MASK (0xf)
@@ -33,28 +35,32 @@
struct cpu_list
{
const char *name;
+ size_t len;
uint64_t midr;
};
-static struct cpu_list cpu_list[] = {
- {"falkor", 0x510FC000},
- {"thunderxt88", 0x430F0A10},
- {"thunderx2t99", 0x431F0AF0},
- {"thunderx2t99p1", 0x420F5160},
- {"phecda", 0x680F0000},
- {"ares", 0x411FD0C0},
- {"emag", 0x503F0001},
- {"kunpeng920", 0x481FD010},
- {"a64fx", 0x460F0010},
- {"generic", 0x0}
+static const struct cpu_list cpu_list[] =
+{
+#define CPU_LIST_ENTRY(__str, __num) { __str, sizeof (__str) - 1, __num }
+ CPU_LIST_ENTRY ("falkor", 0x510FC000),
+ CPU_LIST_ENTRY ("thunderxt88", 0x430F0A10),
+ CPU_LIST_ENTRY ("thunderx2t99", 0x431F0AF0),
+ CPU_LIST_ENTRY ("thunderx2t99p1", 0x420F5160),
+ CPU_LIST_ENTRY ("phecda", 0x680F0000),
+ CPU_LIST_ENTRY ("ares", 0x411FD0C0),
+ CPU_LIST_ENTRY ("emag", 0x503F0001),
+ CPU_LIST_ENTRY ("kunpeng920", 0x481FD010),
+ CPU_LIST_ENTRY ("a64fx", 0x460F0010),
+ CPU_LIST_ENTRY ("generic", 0x0),
};
static uint64_t
-get_midr_from_mcpu (const char *mcpu)
+get_midr_from_mcpu (const struct tunable_str_t *mcpu)
{
- for (int i = 0; i < sizeof (cpu_list) / sizeof (struct cpu_list); i++)
- if (strcmp (mcpu, cpu_list[i].name) == 0)
+ for (int i = 0; i < array_length (cpu_list); i++) {
+ if (tunable_strcmp (mcpu, cpu_list[i].name, cpu_list[i].len))
return cpu_list[i].midr;
+ }
return UINT64_MAX;
}
@@ -65,7 +71,9 @@ init_cpu_features (struct cpu_features *cpu_features)
register uint64_t midr = UINT64_MAX;
/* Get the tunable override. */
- const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL);
+ const struct tunable_str_t *mcpu = TUNABLE_GET (glibc, cpu, name,
+ struct tunable_str_t *,
+ NULL);
if (mcpu != NULL)
midr = get_midr_from_mcpu (mcpu);
diff --git a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
index 7c6e20e702..6709213576 100644
--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <cpu-features.h>
#include <elf/dl-tunables.h>
+#include <dl-tunables-parse.h>
#include <unistd.h>
#include <string.h>
@@ -43,38 +44,33 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features);
unsigned long int tcbv_hwcap = cpu_features->hwcap;
unsigned long int tcbv_hwcap2 = cpu_features->hwcap2;
- const char *token = valp->strval;
- do
+
+ struct tunable_str_comma_t st;
+ tunable_str_comma_init (&st, valp);
+
+ struct tunable_str_t tstr;
+ while (tunable_str_comma_next (&st, &tstr))
{
- const char *token_end, *feature;
- bool disable;
- size_t token_len, i, feature_len, offset = 0;
- /* Find token separator or end of string. */
- for (token_end = token; *token_end != ','; token_end++)
- if (*token_end == '\0')
- break;
+ if (tstr.len == 0)
+ continue;
- /* Determine feature. */
- token_len = token_end - token;
- if (*token == '-')
- {
- disable = true;
- feature = token + 1;
- feature_len = token_len - 1;
- }
- else
+ const char *feature = tstr.str;
+ size_t feature_len = tstr.len;
+
+ bool disable = *feature == '-';
+ if (disable)
{
- disable = false;
- feature = token;
- feature_len = token_len;
+ feature = feature + 1;
+ feature_len = feature_len - 1;
}
- for (i = 0; i < array_length (hwcap_tunables); ++i)
+
+ size_t offset = 0;
+ for (int i = 0; i < array_length (hwcap_tunables); ++i)
{
const char *hwcap_name = hwcap_names + offset;
size_t hwcap_name_len = strlen (hwcap_name);
/* Check the tunable name on the supported list. */
- if (hwcap_name_len == feature_len
- && memcmp (feature, hwcap_name, feature_len) == 0)
+ if (tunable_strcmp (&tstr, hwcap_name, hwcap_name_len))
{
/* Update the hwcap and hwcap2 bits. */
if (disable)
@@ -98,12 +94,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
}
offset += hwcap_name_len + 1;
}
- token += token_len;
- /* ... and skip token separator for next round. */
- if (*token == ',')
- token++;
}
- while (*token != '\0');
}
static inline void
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index 0d4f328585..48e6a865a1 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -38,6 +38,7 @@ extern __typeof (memcmp) DEFAULT_MEMCMP;
#else
# define DEFAULT_MEMCMP memcmp
#endif
+#include <dl-tunables-parse.h>
#define CHECK_GLIBC_IFUNC_CPU_OFF(f, cpu_features, name, len) \
_Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \
@@ -106,33 +107,33 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
NOTE: the IFUNC selection may change over time. Please check all
multiarch implementations when experimenting. */
- const char *p = valp->strval, *c;
struct cpu_features *cpu_features = &GLRO(dl_x86_cpu_features);
- size_t len;
- do
+ struct tunable_str_comma_t st;
+ tunable_str_comma_init (&st, valp);
+
+ struct tunable_str_t tstr;
+ while (tunable_str_comma_next (&st, &tstr))
{
- const char *n;
- bool disable;
- size_t nl;
+ if (tstr.len == 0)
+ continue;
- for (c = p; *c != ','; c++)
- if (*c == '\0')
- break;
+ const char *n = tstr.str;
+ size_t len = tstr.len;
- len = c - p;
- disable = *p == '-';
+ bool disable = *n == '-';
if (disable)
{
- n = p + 1;
- nl = len - 1;
- }
- else
- {
- n = p;
- nl = len;
+ n = n + 1;
+ len = len - 1;
}
- switch (nl)
+
+ _dl_printf ("[%s] %.*s (%d)\n", __func__,
+ (int) tstr.len,
+ tstr.str,
+ (int) tstr.len);
+
+ switch (len)
{
default:
break;
@@ -280,9 +281,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
}
break;
}
- p += len + 1;
}
- while (*c != '\0');
}
#if CET_ENABLED
@@ -290,12 +289,11 @@ attribute_hidden
void
TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *valp)
{
- if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+ if (tunable_strcmp_cte (valp, "on"))
GL(dl_x86_feature_control).ibt = cet_always_on;
- else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+ else if (tunable_strcmp_cte (valp, "off"))
GL(dl_x86_feature_control).ibt = cet_always_off;
- else if (DEFAULT_MEMCMP (valp->strval, "permissive",
- sizeof ("permissive")) == 0)
+ else if (tunable_strcmp_cte (valp, "permissive"))
GL(dl_x86_feature_control).ibt = cet_permissive;
}
@@ -303,12 +301,11 @@ attribute_hidden
void
TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *valp)
{
- if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+ if (tunable_strcmp_cte (valp, "on"))
GL(dl_x86_feature_control).shstk = cet_always_on;
- else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+ else if (tunable_strcmp_cte (valp, "off"))
GL(dl_x86_feature_control).shstk = cet_always_off;
- else if (DEFAULT_MEMCMP (valp->strval, "permissive",
- sizeof ("permissive")) == 0)
+ else if (tunable_strcmp_cte (valp, "permissive"))
GL(dl_x86_feature_control).shstk = cet_permissive;
}
#endif
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-10-06 14:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-06 14:28 [glibc/azanella/tunables] elf: Do not duplicate GLIBC_TUNABLES string Adhemerval Zanella
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).