1  /* { dg-do compile } */
       2  /* { dg-options "-O2 -std=gnu11 -fgnu89-inline" } */
       3  /* { dg-final { scan-assembler-not ".quad\[\\t \]+tunable_list" { target lp64 } } } */
       4  /* { dg-final { scan-assembler-not ".long\[\\t \]+tunable_list" { target { ! lp64 } } } } */
       5  
       6  typedef unsigned long int size_t;
       7  typedef long long int intmax_t;
       8  typedef unsigned long long int uintmax_t;
       9  typedef unsigned long long int uint64_t;
      10  typedef intmax_t tunable_num_t;
      11  typedef union
      12  {
      13    tunable_num_t numval;
      14    const char *strval;
      15  } tunable_val_t;
      16  enum
      17  {
      18    HWCAP_X86_SSE2 = 1 << 0,
      19    HWCAP_X86_64 = 1 << 1,
      20    HWCAP_X86_AVX512_1 = 1 << 2
      21  };
      22  typedef void (*tunable_callback_t) (tunable_val_t *);
      23  extern void *__minimal_malloc (size_t n)
      24      __attribute__ ((visibility ("hidden")));
      25  extern int __libc_enable_secure __attribute__ ((section (".data.rel.ro")));
      26  extern uint64_t _dl_strtoul (const char *, char **)
      27      __attribute__ ((visibility ("hidden")));
      28  extern void _dl_fatal_printf (const char *fmt, ...)
      29      __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__));
      30  typedef enum
      31  {
      32    glibc_rtld_nns,
      33    glibc_elision_skip_lock_after_retries,
      34    glibc_malloc_trim_threshold,
      35    glibc_malloc_perturb,
      36    glibc_cpu_x86_shared_cache_size,
      37    glibc_pthread_rseq,
      38    glibc_mem_tagging,
      39    glibc_elision_tries,
      40    glibc_elision_enable,
      41    glibc_malloc_hugetlb,
      42    glibc_cpu_x86_rep_movsb_threshold,
      43    glibc_malloc_mxfast,
      44    glibc_rtld_dynamic_sort,
      45    glibc_elision_skip_lock_busy,
      46    glibc_malloc_top_pad,
      47    glibc_cpu_x86_rep_stosb_threshold,
      48    glibc_cpu_x86_non_temporal_threshold,
      49    glibc_cpu_x86_shstk,
      50    glibc_pthread_stack_cache_size,
      51    glibc_cpu_hwcap_mask,
      52    glibc_malloc_mmap_max,
      53    glibc_elision_skip_trylock_internal_abort,
      54    glibc_malloc_tcache_unsorted_limit,
      55    glibc_cpu_x86_ibt,
      56    glibc_cpu_hwcaps,
      57    glibc_elision_skip_lock_internal_abort,
      58    glibc_malloc_arena_max,
      59    glibc_malloc_mmap_threshold,
      60    glibc_cpu_x86_data_cache_size,
      61    glibc_malloc_tcache_count,
      62    glibc_malloc_arena_test,
      63    glibc_pthread_mutex_spin_count,
      64    glibc_rtld_optional_static_tls,
      65    glibc_malloc_tcache_max,
      66    glibc_malloc_check,
      67  } tunable_id_t;
      68  typedef enum
      69  {
      70    TUNABLE_TYPE_INT_32,
      71    TUNABLE_TYPE_UINT_64,
      72    TUNABLE_TYPE_SIZE_T,
      73    TUNABLE_TYPE_STRING
      74  } tunable_type_code_t;
      75  typedef struct
      76  {
      77    tunable_type_code_t type_code;
      78    tunable_num_t min;
      79    tunable_num_t max;
      80  } tunable_type_t;
      81  typedef enum
      82  {
      83    TUNABLE_SECLEVEL_SXID_ERASE = 0,
      84    TUNABLE_SECLEVEL_SXID_IGNORE = 1,
      85    TUNABLE_SECLEVEL_NONE = 2,
      86  } tunable_seclevel_t;
      87  struct _tunable
      88  {
      89    const char name[42];
      90    tunable_type_t type;
      91    tunable_val_t val;
      92    _Bool initialized;
      93    tunable_seclevel_t security_level;
      94    const char env_alias[23];
      95  };
      96  typedef struct _tunable tunable_t;
      97  extern _Bool unsigned_tunable_type (tunable_type_code_t t);
      98  
      99  static tunable_t tunable_list[] __attribute__ ((section (".data.rel.ro"))) = {
     100    { "glibc"
     101      "."
     102      "rtld"
     103      "."
     104      "nns",
     105      { TUNABLE_TYPE_SIZE_T, 1, 16 },
     106      { .numval = 4 },
     107      ((void *)0),
     108      TUNABLE_SECLEVEL_SXID_ERASE,
     109      { 0 } },
     110    { "glibc"
     111      "."
     112      "elision"
     113      "."
     114      "skip_lock_after_retries",
     115      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     116      { .numval = 3 },
     117      ((void *)0),
     118      TUNABLE_SECLEVEL_SXID_ERASE,
     119      { 0 } },
     120    { "glibc"
     121      "."
     122      "malloc"
     123      "."
     124      "trim_threshold",
     125      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     126      {},
     127      ((void *)0),
     128      TUNABLE_SECLEVEL_SXID_IGNORE,
     129      "MALLOC_TRIM_THRESHOLD_" },
     130    { "glibc"
     131      "."
     132      "malloc"
     133      "."
     134      "perturb",
     135      { TUNABLE_TYPE_INT_32, 0, 0xff },
     136      {},
     137      ((void *)0),
     138      TUNABLE_SECLEVEL_SXID_IGNORE,
     139      "MALLOC_PERTURB_" },
     140    { "glibc"
     141      "."
     142      "cpu"
     143      "."
     144      "x86_shared_cache_size",
     145      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     146      {},
     147      ((void *)0),
     148      TUNABLE_SECLEVEL_SXID_ERASE,
     149      { 0 } },
     150    { "glibc"
     151      "."
     152      "pthread"
     153      "."
     154      "rseq",
     155      { TUNABLE_TYPE_INT_32, 0, 1 },
     156      { .numval = 1 },
     157      ((void *)0),
     158      TUNABLE_SECLEVEL_SXID_ERASE,
     159      { 0 } },
     160    { "glibc"
     161      "."
     162      "mem"
     163      "."
     164      "tagging",
     165      { TUNABLE_TYPE_INT_32, 0, 255 },
     166      {},
     167      ((void *)0),
     168      TUNABLE_SECLEVEL_SXID_IGNORE,
     169      { 0 } },
     170    { "glibc"
     171      "."
     172      "elision"
     173      "."
     174      "tries",
     175      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     176      { .numval = 3 },
     177      ((void *)0),
     178      TUNABLE_SECLEVEL_SXID_ERASE,
     179      { 0 } },
     180    { "glibc"
     181      "."
     182      "elision"
     183      "."
     184      "enable",
     185      { TUNABLE_TYPE_INT_32, 0, 1 },
     186      {},
     187      ((void *)0),
     188      TUNABLE_SECLEVEL_SXID_ERASE,
     189      { 0 } },
     190    { "glibc"
     191      "."
     192      "malloc"
     193      "."
     194      "hugetlb",
     195      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     196      {},
     197      ((void *)0),
     198      TUNABLE_SECLEVEL_SXID_ERASE,
     199      { 0 } },
     200    { "glibc"
     201      "."
     202      "cpu"
     203      "."
     204      "x86_rep_movsb_threshold",
     205      { TUNABLE_TYPE_SIZE_T, 1, (18446744073709551615UL) },
     206      {},
     207      ((void *)0),
     208      TUNABLE_SECLEVEL_SXID_ERASE,
     209      { 0 } },
     210    { "glibc"
     211      "."
     212      "malloc"
     213      "."
     214      "mxfast",
     215      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     216      {},
     217      ((void *)0),
     218      TUNABLE_SECLEVEL_SXID_IGNORE,
     219      { 0 } },
     220    { "glibc"
     221      "."
     222      "rtld"
     223      "."
     224      "dynamic_sort",
     225      { TUNABLE_TYPE_INT_32, 1, 2 },
     226      { .numval = 2 },
     227      ((void *)0),
     228      TUNABLE_SECLEVEL_SXID_ERASE,
     229      { 0 } },
     230    { "glibc"
     231      "."
     232      "elision"
     233      "."
     234      "skip_lock_busy",
     235      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     236      { .numval = 3 },
     237      ((void *)0),
     238      TUNABLE_SECLEVEL_SXID_ERASE,
     239      { 0 } },
     240    { "glibc"
     241      "."
     242      "malloc"
     243      "."
     244      "top_pad",
     245      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     246      {},
     247      ((void *)0),
     248      TUNABLE_SECLEVEL_SXID_IGNORE,
     249      "MALLOC_TOP_PAD_" },
     250    { "glibc"
     251      "."
     252      "cpu"
     253      "."
     254      "x86_rep_stosb_threshold",
     255      { TUNABLE_TYPE_SIZE_T, 1, (18446744073709551615UL) },
     256      { .numval = 2048 },
     257      ((void *)0),
     258      TUNABLE_SECLEVEL_SXID_ERASE,
     259      { 0 } },
     260    { "glibc"
     261      "."
     262      "cpu"
     263      "."
     264      "x86_non_temporal_threshold",
     265      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     266      {},
     267      ((void *)0),
     268      TUNABLE_SECLEVEL_SXID_ERASE,
     269      { 0 } },
     270    { "glibc"
     271      "."
     272      "cpu"
     273      "."
     274      "x86_shstk",
     275      { TUNABLE_TYPE_STRING, 0, 0 },
     276      {},
     277      ((void *)0),
     278      TUNABLE_SECLEVEL_SXID_ERASE,
     279      { 0 } },
     280    { "glibc"
     281      "."
     282      "pthread"
     283      "."
     284      "stack_cache_size",
     285      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     286      { .numval = 41943040 },
     287      ((void *)0),
     288      TUNABLE_SECLEVEL_SXID_ERASE,
     289      { 0 } },
     290    { "glibc"
     291      "."
     292      "cpu"
     293      "."
     294      "hwcap_mask",
     295      { TUNABLE_TYPE_UINT_64, 0, (18446744073709551615UL) },
     296      { .numval = (HWCAP_X86_64 | HWCAP_X86_AVX512_1) },
     297      ((void *)0),
     298      TUNABLE_SECLEVEL_SXID_ERASE,
     299      "LD_HWCAP_MASK" },
     300    { "glibc"
     301      "."
     302      "malloc"
     303      "."
     304      "mmap_max",
     305      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     306      {},
     307      ((void *)0),
     308      TUNABLE_SECLEVEL_SXID_IGNORE,
     309      "MALLOC_MMAP_MAX_" },
     310    { "glibc"
     311      "."
     312      "elision"
     313      "."
     314      "skip_trylock_internal_abort",
     315      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     316      { .numval = 3 },
     317      ((void *)0),
     318      TUNABLE_SECLEVEL_SXID_ERASE,
     319      { 0 } },
     320    { "glibc"
     321      "."
     322      "malloc"
     323      "."
     324      "tcache_unsorted_limit",
     325      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     326      {},
     327      ((void *)0),
     328      TUNABLE_SECLEVEL_SXID_ERASE,
     329      { 0 } },
     330    { "glibc"
     331      "."
     332      "cpu"
     333      "."
     334      "x86_ibt",
     335      { TUNABLE_TYPE_STRING, 0, 0 },
     336      {},
     337      ((void *)0),
     338      TUNABLE_SECLEVEL_SXID_ERASE,
     339      { 0 } },
     340    { "glibc"
     341      "."
     342      "cpu"
     343      "."
     344      "hwcaps",
     345      { TUNABLE_TYPE_STRING, 0, 0 },
     346      {},
     347      ((void *)0),
     348      TUNABLE_SECLEVEL_SXID_ERASE,
     349      { 0 } },
     350    { "glibc"
     351      "."
     352      "elision"
     353      "."
     354      "skip_lock_internal_abort",
     355      { TUNABLE_TYPE_INT_32, 0, (2147483647) },
     356      { .numval = 3 },
     357      ((void *)0),
     358      TUNABLE_SECLEVEL_SXID_ERASE,
     359      { 0 } },
     360    { "glibc"
     361      "."
     362      "malloc"
     363      "."
     364      "arena_max",
     365      { TUNABLE_TYPE_SIZE_T, 1, (18446744073709551615UL) },
     366      {},
     367      ((void *)0),
     368      TUNABLE_SECLEVEL_SXID_IGNORE,
     369      "MALLOC_ARENA_MAX" },
     370    { "glibc"
     371      "."
     372      "malloc"
     373      "."
     374      "mmap_threshold",
     375      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     376      {},
     377      ((void *)0),
     378      TUNABLE_SECLEVEL_SXID_IGNORE,
     379      "MALLOC_MMAP_THRESHOLD_" },
     380    { "glibc"
     381      "."
     382      "cpu"
     383      "."
     384      "x86_data_cache_size",
     385      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     386      {},
     387      ((void *)0),
     388      TUNABLE_SECLEVEL_SXID_ERASE,
     389      { 0 } },
     390    { "glibc"
     391      "."
     392      "malloc"
     393      "."
     394      "tcache_count",
     395      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     396      {},
     397      ((void *)0),
     398      TUNABLE_SECLEVEL_SXID_ERASE,
     399      { 0 } },
     400    { "glibc"
     401      "."
     402      "malloc"
     403      "."
     404      "arena_test",
     405      { TUNABLE_TYPE_SIZE_T, 1, (18446744073709551615UL) },
     406      {},
     407      ((void *)0),
     408      TUNABLE_SECLEVEL_SXID_IGNORE,
     409      "MALLOC_ARENA_TEST" },
     410    { "glibc"
     411      "."
     412      "pthread"
     413      "."
     414      "mutex_spin_count",
     415      { TUNABLE_TYPE_INT_32, 0, 32767 },
     416      { .numval = 100 },
     417      ((void *)0),
     418      TUNABLE_SECLEVEL_SXID_ERASE,
     419      { 0 } },
     420    { "glibc"
     421      "."
     422      "rtld"
     423      "."
     424      "optional_static_tls",
     425      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     426      { .numval = 512 },
     427      ((void *)0),
     428      TUNABLE_SECLEVEL_SXID_ERASE,
     429      { 0 } },
     430    { "glibc"
     431      "."
     432      "malloc"
     433      "."
     434      "tcache_max",
     435      { TUNABLE_TYPE_SIZE_T, 0, (18446744073709551615UL) },
     436      {},
     437      ((void *)0),
     438      TUNABLE_SECLEVEL_SXID_ERASE,
     439      { 0 } },
     440    { "glibc"
     441      "."
     442      "malloc"
     443      "."
     444      "check",
     445      { TUNABLE_TYPE_INT_32, 0, 3 },
     446      {},
     447      ((void *)0),
     448      TUNABLE_SECLEVEL_SXID_ERASE,
     449      "MALLOC_CHECK_" },
     450  };
     451  extern void __tunables_init (char **);
     452  extern void __tunables_print (void);
     453  extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
     454  extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
     455                                 tunable_num_t *);
     456  static __inline __attribute__ ((__always_inline__)) _Bool
     457  tunable_val_lt (tunable_num_t lhs, tunable_num_t rhs, _Bool unsigned_cmp)
     458  {
     459    if (unsigned_cmp)
     460      return (uintmax_t)lhs < (uintmax_t)rhs;
     461    else
     462      return lhs < rhs;
     463  }
     464  static __inline __attribute__ ((__always_inline__)) _Bool
     465  tunable_val_gt (tunable_num_t lhs, tunable_num_t rhs, _Bool unsigned_cmp)
     466  {
     467    if (unsigned_cmp)
     468      return (uintmax_t)lhs > (uintmax_t)rhs;
     469    else
     470      return lhs > rhs;
     471  }
     472  static __inline __attribute__ ((__always_inline__)) _Bool
     473  tunable_is_name (const char *orig, const char *envname)
     474  {
     475    for (; *orig != '\0' && *envname != '\0'; envname++, orig++)
     476      if (*orig != *envname)
     477        break;
     478    if (*orig == '\0' && *envname == '=')
     479      return 1;
     480    else
     481      return 0;
     482  }
     483  static char *
     484  tunables_strdup (const char *in)
     485  {
     486    size_t i = 0;
     487    while (in[i++] != '\0')
     488      ;
     489    char *out = __minimal_malloc (i + 1);
     490    if (out == ((void *)0))
     491      _dl_fatal_printf ("failed to allocate memory to process tunables\n");
     492    while (i-- > 0)
     493      out[i] = in[i];
     494    return out;
     495  }
     496  static char **
     497  get_next_env (char **envp, char **name, size_t *namelen, char **val,
     498                char ***prev_envp)
     499  {
     500    while (envp != ((void *)0) && *envp != ((void *)0))
     501      {
     502        char **prev = envp;
     503        char *envline = *envp++;
     504        int len = 0;
     505        while (envline[len] != '\0' && envline[len] != '=')
     506          len++;
     507        if (envline[len] == '\0')
     508          continue;
     509        *name = envline;
     510        *namelen = len;
     511        *val = &envline[len + 1];
     512        *prev_envp = prev;
     513        return envp;
     514      }
     515    return ((void *)0);
     516  }
     517  static void
     518  do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
     519                         const tunable_num_t *minp, const tunable_num_t *maxp)
     520  {
     521    tunable_num_t val, min, max;
     522    if (cur->type.type_code == TUNABLE_TYPE_STRING)
     523      {
     524        cur->val.strval = valp->strval;
     525        cur->initialized = 1;
     526        return;
     527      }
     528    _Bool unsigned_cmp = unsigned_tunable_type (cur->type.type_code);
     529    val = valp->numval;
     530    min = minp != ((void *)0) ? *minp : cur->type.min;
     531    max = maxp != ((void *)0) ? *maxp : cur->type.max;
     532    if (tunable_val_lt (min, cur->type.min, unsigned_cmp))
     533      min = cur->type.min;
     534    if (tunable_val_gt (max, cur->type.max, unsigned_cmp))
     535      max = cur->type.max;
     536    if (tunable_val_gt (min, max, unsigned_cmp))
     537      {
     538        min = cur->type.min;
     539        max = cur->type.max;
     540      }
     541    if (tunable_val_lt (val, min, unsigned_cmp)
     542        || tunable_val_lt (max, val, unsigned_cmp))
     543      return;
     544    cur->val.numval = val;
     545    cur->type.min = min;
     546    cur->type.max = max;
     547    cur->initialized = 1;
     548  }
     549  static void
     550  tunable_initialize (tunable_t *cur, const char *strval)
     551  {
     552    tunable_val_t val;
     553    if (cur->type.type_code != TUNABLE_TYPE_STRING)
     554      val.numval = (tunable_num_t)_dl_strtoul (strval, ((void *)0));
     555    else
     556      val.strval = strval;
     557    do_tunable_update_val (cur, &val, ((void *)0), ((void *)0));
     558  }
     559  static void
     560  parse_tunables (char *tunestr, char *valstring)
     561  {
     562    if (tunestr == ((void *)0) || *tunestr == '\0')
     563      return;
     564    char *p = tunestr;
     565    size_t off = 0;
     566    while (1)
     567      {
     568        char *name = p;
     569        size_t len = 0;
     570        while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
     571          len++;
     572        if (p[len] == '\0')
     573          {
     574            if (__libc_enable_secure)
     575              tunestr[off] = '\0';
     576            return;
     577          }
     578        if (p[len] == ':')
     579          {
     580            p += len + 1;
     581            continue;
     582          }
     583        p += len + 1;
     584        char *value = &valstring[p - tunestr];
     585        len = 0;
     586        while (p[len] != ':' && p[len] != '\0')
     587          len++;
     588        for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
     589          {
     590            tunable_t *cur = &tunable_list[i];
     591            if (tunable_is_name (cur->name, name))
     592              {
     593                if (__libc_enable_secure)
     594                  {
     595                    if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
     596                      {
     597                        if (off > 0)
     598                          tunestr[off++] = ':';
     599                        const char *n = cur->name;
     600                        while (*n != '\0')
     601                          tunestr[off++] = *n++;
     602                        tunestr[off++] = '=';
     603                        for (size_t j = 0; j < len; j++)
     604                          tunestr[off++] = value[j];
     605                      }
     606                    if (cur->security_level != TUNABLE_SECLEVEL_NONE)
     607                      break;
     608                  }
     609                value[len] = '\0';
     610                tunable_initialize (cur, value);
     611                break;
     612              }
     613          }
     614        if (p[len] != '\0')
     615          p += len + 1;
     616      }
     617  }
     618  void
     619  __tunables_init (char **envp)
     620  {
     621    char *envname = ((void *)0);
     622    char *envval = ((void *)0);
     623    size_t len = 0;
     624    char **prev_envp = envp;
     625    while ((envp = get_next_env (envp, &envname, &len, &envval, &prev_envp))
     626           != ((void *)0))
     627      {
     628        if (tunable_is_name ("GLIBC_TUNABLES", envname))
     629          {
     630            char *new_env = tunables_strdup (envname);
     631            if (new_env != ((void *)0))
     632              parse_tunables (new_env + len + 1, envval);
     633            *prev_envp = new_env;
     634            continue;
     635          }
     636        for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
     637          {
     638            tunable_t *cur = &tunable_list[i];
     639            const char *name = cur->env_alias;
     640            if (tunable_is_name (name, envname))
     641              {
     642                tunable_initialize (cur, envval);
     643                break;
     644              }
     645          }
     646      }
     647  }