Browse code

glibc: fixes tunables, malloc arena and makecheck

Change-Id: I8e05bec192cddbc1214a4c610d06457ed40aaacf
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/3680
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>

Alexey Makhalov authored on 2017/08/31 06:25:19
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,124 @@
0
+From b075241890641122df79c130149601c942a310a5 Mon Sep 17 00:00:00 2001
1
+From: Alexey Makhalov <amakhalov@vmware.com>
2
+Date: Wed, 19 Jul 2017 19:53:14 +0000
3
+Subject: [PATCH 1/2] Fix range check in do_tunable_update_val
4
+
5
+Current implementation of tunables does not set arena_max and arena_test
6
+values. Any value provided by glibc.malloc.arena_max and
7
+glibc.malloc.arena_test parameters is ignored.
8
+
9
+These tunables have minval value set to 1 (see elf/dl-tunables.list file)
10
+and undefined maxval value. In that case default value (which is 0. see
11
+scripts/gen-tunables.awk) is being used to set maxval.
12
+
13
+For instance, generated tunable_list[] entry for arena_max is:
14
+(gdb) p *cur
15
+$1 = {name = 0x7ffff7df6217 "glibc.malloc.arena_max",
16
+ type = {type_code = TUNABLE_TYPE_SIZE_T, min = 1, max = 0},
17
+  val = {numval = 0, strval = 0x0}, initialized = false,
18
+   security_level = TUNABLE_SECLEVEL_SXID_IGNORE,
19
+    env_alias = 0x7ffff7df622e "MALLOC_ARENA_MAX"}
20
+
21
+As a result, any value of glibc.malloc.arena_max is ignored by
22
+TUNABLE_SET_VAL_IF_VALID_RANGE macro
23
+  __type min = (__cur)->type.min;                        <- initialized to 1
24
+  __type max = (__cur)->type.max;                        <- initialized to 0!
25
+  if (min == max)                                        <- false
26
+    {
27
+      min = __default_min;
28
+      max = __default_max;
29
+    }
30
+  if ((__type) (__val) >= min && (__type) (val) <= max)  <- false
31
+    {
32
+      (__cur)->val.numval = val;
33
+      (__cur)->initialized = true;
34
+    }
35
+
36
+Assigning correct min/max values at a build time fixes a problem.
37
+Plus, a bit of optimization: Setting of default min/max values for the given
38
+type at a run time might be eliminated.
39
+---
40
+ elf/dl-tunables.c        | 15 ++++-----------
41
+ scripts/gen-tunables.awk | 12 ++++++++++--
42
+ 2 files changed, 14 insertions(+), 13 deletions(-)
43
+
44
+diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
45
+index 44c160c..8e02a95 100644
46
+--- a/elf/dl-tunables.c
47
+@@ -86,18 +86,11 @@ get_next_env (char **envp, char **name, size_t *namelen, char **val,
48
+   return NULL;
49
+ }
50
+ 
51
+-#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
52
+-				       __default_max)			      \
53
++#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type)		      \
54
+ ({									      \
55
+   __type min = (__cur)->type.min;					      \
56
+   __type max = (__cur)->type.max;					      \
57
+ 									      \
58
+-  if (min == max)							      \
59
+-    {									      \
60
+-      min = __default_min;						      \
61
+-      max = __default_max;						      \
62
+-    }									      \
63
+-									      \
64
+   if ((__type) (__val) >= min && (__type) (val) <= max)			      \
65
+     {									      \
66
+       (__cur)->val.numval = val;					      \
67
+@@ -117,17 +110,17 @@ do_tunable_update_val (tunable_t *cur, const void *valp)
68
+     {
69
+     case TUNABLE_TYPE_INT_32:
70
+ 	{
71
+-	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t, INT32_MIN, INT32_MAX);
72
++	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t);
73
+ 	  break;
74
+ 	}
75
+     case TUNABLE_TYPE_UINT_64:
76
+ 	{
77
+-	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, UINT64_MAX);
78
++	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
79
+ 	  break;
80
+ 	}
81
+     case TUNABLE_TYPE_SIZE_T:
82
+ 	{
83
+-	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, SIZE_MAX);
84
++	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
85
+ 	  break;
86
+ 	}
87
+     case TUNABLE_TYPE_STRING:
88
+diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
89
+index ccdd0c6..6221990 100644
90
+--- a/scripts/gen-tunables.awk
91
+@@ -1,6 +1,14 @@
92
+ # Generate dl-tunable-list.h from dl-tunables.list
93
+ 
94
+ BEGIN {
95
++  min_of["STRING"]="0"
96
++  max_of["STRING"]="0"
97
++  min_of["INT_32"]="INT32_MIN"
98
++  max_of["INT_32"]="INT32_MAX"
99
++  min_of["UINT_64"]="0"
100
++  max_of["UINT_64"]="UINT64_MAX"
101
++  min_of["SIZE_T"]="0"
102
++  max_of["SIZE_T"]="SIZE_MAX"
103
+   tunable=""
104
+   ns=""
105
+   top_ns=""
106
+@@ -43,10 +51,10 @@ $1 == "}" {
107
+       types[top_ns,ns,tunable] = "STRING"
108
+     }
109
+     if (!minvals[top_ns,ns,tunable]) {
110
+-      minvals[top_ns,ns,tunable] = "0"
111
++      minvals[top_ns,ns,tunable] = min_of[types[top_ns,ns,tunable]]
112
+     }
113
+     if (!maxvals[top_ns,ns,tunable]) {
114
+-      maxvals[top_ns,ns,tunable] = "0"
115
++      maxvals[top_ns,ns,tunable] = max_of[types[top_ns,ns,tunable]]
116
+     }
117
+     if (!env_alias[top_ns,ns,tunable]) {
118
+       env_alias[top_ns,ns,tunable] = "NULL"
119
+-- 
120
+2.9.3
121
+
0 122
new file mode 100644
... ...
@@ -0,0 +1,251 @@
0
+From e72b84cec44852dd76365cb7e1bf691b56a8adfc Mon Sep 17 00:00:00 2001
1
+From: Alexey Makhalov <amakhalov@vmware.com>
2
+Date: Tue, 29 Aug 2017 21:10:08 +0000
3
+Subject: [PATCH 2/2] malloc arena fix
4
+
5
+---
6
+ elf/dl-tunables.list |  5 ++++
7
+ malloc/arena.c       | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
8
+ malloc/malloc.c      | 31 +++++++++++++++++++++++++
9
+ malloc/malloc.h      |  1 +
10
+ 4 files changed, 101 insertions(+)
11
+
12
+diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
13
+index c188c6a..15a1a14 100644
14
+--- a/elf/dl-tunables.list
15
+@@ -76,6 +76,11 @@ glibc {
16
+       minval: 1
17
+       security_level: SXID_IGNORE
18
+     }
19
++    arena_stickiness {
20
++      type: SIZE_T
21
++      env_alias: MALLOC_ARENA_STICKINESS
22
++      security_level: SXID_IGNORE
23
++    }
24
+     tcache_max {
25
+       type: SIZE_T
26
+       security_level: SXID_ERASE
27
+diff --git a/malloc/arena.c b/malloc/arena.c
28
+index dc14fae..f0edf2b 100644
29
+--- a/malloc/arena.c
30
+@@ -63,6 +63,12 @@ typedef struct _heap_info
31
+   char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
32
+ } heap_info;
33
+ 
34
++typedef struct _arena_tracker
35
++{
36
++  mstate arena; /* Arena most recently tracked for growth. */
37
++  size_t growth; /* Current size in bytes. */
38
++} arena_tracker;
39
++
40
+ /* Get a compile-time error if the heap_info padding is not correct
41
+    to make alignment work as expected in sYSMALLOc.  */
42
+ extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
43
+@@ -73,6 +79,8 @@ extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
44
+ 
45
+ static __thread mstate thread_arena attribute_tls_model_ie;
46
+ 
47
++static __thread arena_tracker thread_arena_tracker attribute_tls_model_ie;
48
++
49
+ /* Arena free list.  free_list_lock synchronizes access to the
50
+    free_list variable below, and the next_free and attached_threads
51
+    members of struct malloc_state objects.  No other locks must be
52
+@@ -236,6 +244,7 @@ TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t)
53
+ TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t)
54
+ TUNABLE_CALLBACK_FNDECL (set_arena_max, size_t)
55
+ TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t)
56
++TUNABLE_CALLBACK_FNDECL (set_arena_stickiness, size_t)
57
+ #if USE_TCACHE
58
+ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
59
+ TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
60
+@@ -327,6 +336,7 @@ ptmalloc_init (void)
61
+   TUNABLE_GET (mmap_max, int32_t, TUNABLE_CALLBACK (set_mmaps_max));
62
+   TUNABLE_GET (arena_max, size_t, TUNABLE_CALLBACK (set_arena_max));
63
+   TUNABLE_GET (arena_test, size_t, TUNABLE_CALLBACK (set_arena_test));
64
++  TUNABLE_GET (arena_stickiness, size_t, TUNABLE_CALLBACK (set_arena_stickiness));
65
+ #if USE_TCACHE
66
+   TUNABLE_GET (tcache_max, size_t, TUNABLE_CALLBACK (set_tcache_max));
67
+   TUNABLE_GET (tcache_count, size_t, TUNABLE_CALLBACK (set_tcache_count));
68
+@@ -392,6 +402,13 @@ ptmalloc_init (void)
69
+                     __libc_mallopt (M_MMAP_THRESHOLD, atoi (&envline[16]));
70
+                 }
71
+               break;
72
++            case 16:
73
++              if (!__builtin_expect (__libc_enable_secure, 0))
74
++                {
75
++                  if (memcmp (envline, "ARENA_STICKINESS", 16) == 0)
76
++                    __libc_mallopt (M_ARENA_STICKINESS, atoi (&envline[17]));
77
++                }
78
++              break;
79
+             default:
80
+               break;
81
+             }
82
+@@ -974,6 +991,53 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
83
+   return ar_ptr;
84
+ }
85
+ 
86
++static void
87
++internal_function
88
++arena_stickiness_track_alloc (void *victim)
89
++{
90
++  if (!victim || chunk_is_mmapped (mem2chunk (victim)))
91
++    return;
92
++
93
++  if (thread_arena_tracker.arena != arena_for_chunk (mem2chunk (victim))) {
94
++    thread_arena_tracker.growth = 0;
95
++    thread_arena_tracker.arena = arena_for_chunk (mem2chunk (victim));
96
++  } else {
97
++    thread_arena_tracker.growth += chunksize (mem2chunk (victim));
98
++    if (thread_arena_tracker.growth >= mp_.arena_stickiness) {
99
++      /* Swtich thread to the next arena */
100
++      mstate replaced_arena = thread_arena;
101
++      mstate next_to_use = replaced_arena->next;
102
++
103
++      __libc_lock_lock (free_list_lock);
104
++      detach_arena (replaced_arena);
105
++#if 0
106
++      /* If this was the last attached thread for this arena, put the
107
++	 arena on the free list.  */
108
++      if (replaced_arena->attached_threads == 0)
109
++	{
110
++	  replaced_arena->next_free = free_list;
111
++	  free_list = replaced_arena;
112
++	}
113
++#endif
114
++      if (next_to_use->attached_threads == 0)
115
++        remove_from_free_list (next_to_use);
116
++      ++next_to_use->attached_threads;
117
++
118
++      __libc_lock_unlock (free_list_lock);
119
++      thread_arena = next_to_use;
120
++    }
121
++  }
122
++}
123
++
124
++/* chunk must be valid and not mmaped.  */
125
++static void
126
++internal_function
127
++arena_stickiness_track_free (mchunkptr chunk)
128
++{
129
++  if (thread_arena_tracker.arena == arena_for_chunk (chunk))
130
++    thread_arena_tracker.growth -= chunksize (chunk);
131
++}
132
++
133
+ static void __attribute__ ((section ("__libc_thread_freeres_fn")))
134
+ arena_thread_freeres (void)
135
+ {
136
+diff --git a/malloc/malloc.c b/malloc/malloc.c
137
+index 54e406b..29787a5 100644
138
+--- a/malloc/malloc.c
139
+@@ -1723,6 +1723,7 @@ struct malloc_par
140
+   INTERNAL_SIZE_T mmap_threshold;
141
+   INTERNAL_SIZE_T arena_test;
142
+   INTERNAL_SIZE_T arena_max;
143
++  INTERNAL_SIZE_T arena_stickiness;
144
+ 
145
+   /* Memory map support */
146
+   int n_mmaps;
147
+@@ -1787,6 +1788,7 @@ static struct malloc_par mp_ =
148
+   .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
149
+   .trim_threshold = DEFAULT_TRIM_THRESHOLD,
150
+ #define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
151
++  .arena_stickiness = 0,
152
+   .arena_test = NARENAS_FROM_NCORES (1)
153
+ #if USE_TCACHE
154
+   ,
155
+@@ -3083,6 +3085,10 @@ __libc_malloc (size_t bytes)
156
+ 
157
+   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
158
+           ar_ptr == arena_for_chunk (mem2chunk (victim)));
159
++
160
++  if (mp_.arena_stickiness > 0)
161
++    arena_stickiness_track_alloc (victim);
162
++
163
+   return victim;
164
+ }
165
+ libc_hidden_def (__libc_malloc)
166
+@@ -3126,6 +3132,9 @@ __libc_free (void *mem)
167
+ 
168
+   MAYBE_INIT_TCACHE ();
169
+ 
170
++  if (mp_.arena_stickiness > 0)
171
++    arena_stickiness_track_free (p);
172
++
173
+   ar_ptr = arena_for_chunk (p);
174
+   _int_free (ar_ptr, p, 0);
175
+ }
176
+@@ -3226,6 +3235,8 @@ __libc_realloc (void *oldmem, size_t bytes)
177
+       return newmem;
178
+     }
179
+ 
180
++  if (mp_.arena_stickiness > 0)
181
++    arena_stickiness_track_free (oldp);
182
+   __libc_lock_lock (ar_ptr->mutex);
183
+ 
184
+   newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
185
+@@ -3234,6 +3245,9 @@ __libc_realloc (void *oldmem, size_t bytes)
186
+   assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
187
+           ar_ptr == arena_for_chunk (mem2chunk (newp)));
188
+ 
189
++  if (mp_.arena_stickiness > 0)
190
++    arena_stickiness_track_alloc (newp);
191
++
192
+   if (newp == NULL)
193
+     {
194
+       /* Try harder to allocate memory in other arenas.  */
195
+@@ -3452,6 +3466,9 @@ __libc_calloc (size_t n, size_t elem_size)
196
+       return mem;
197
+     }
198
+ 
199
++  if (mp_.arena_stickiness > 0)
200
++    arena_stickiness_track_alloc (mem);
201
++
202
+   csz = chunksize (p);
203
+ 
204
+ #if MORECORE_CLEARS
205
+@@ -5145,6 +5162,15 @@ do_set_arena_max (size_t value)
206
+   return 1;
207
+ }
208
+ 
209
++static inline int
210
++__always_inline
211
++do_set_arena_stickiness (size_t value)
212
++{
213
++  LIBC_PROBE (memory_mallopt_arena_stickiness, 2, value, mp_.arena_stickiness);
214
++  mp_.arena_stickiness = value;
215
++  return 1;
216
++}
217
++
218
+ #if USE_TCACHE
219
+ static inline int
220
+ __always_inline
221
+@@ -5237,6 +5263,11 @@ __libc_mallopt (int param_number, int value)
222
+       if (value > 0)
223
+ 	do_set_arena_max (value);
224
+       break;
225
++
226
++    case M_ARENA_STICKINESS:
227
++      if (value > 0)
228
++	do_set_arena_stickiness (value);
229
++      break;
230
+     }
231
+   __libc_lock_unlock (av->mutex);
232
+   return res;
233
+diff --git a/malloc/malloc.h b/malloc/malloc.h
234
+index 339ab64..31bdb44 100644
235
+--- a/malloc/malloc.h
236
+@@ -121,6 +121,7 @@ extern struct mallinfo mallinfo (void) __THROW;
237
+ #define M_PERTURB           -6
238
+ #define M_ARENA_TEST        -7
239
+ #define M_ARENA_MAX         -8
240
++#define M_ARENA_STICKINESS  -9
241
+ 
242
+ /* General SVID/XPG interface to tunable parameters. */
243
+ extern int mallopt (int __param, int __val) __THROW;
244
+-- 
245
+2.9.3
246
+
... ...
@@ -4,7 +4,7 @@
4 4
 Summary:	Main C library
5 5
 Name:		glibc
6 6
 Version:	2.26
7
-Release:	1%{?dist}
7
+Release:	2%{?dist}
8 8
 License:	LGPLv2+
9 9
 URL:		http://www.gnu.org/software/libc
10 10
 Group:		Applications/System
... ...
@@ -16,6 +16,8 @@ Source1:	locale-gen.sh
16 16
 Source2:	locale-gen.conf
17 17
 Patch0:   	http://www.linuxfromscratch.org/patches/downloads/glibc/glibc-2.25-fhs-1.patch
18 18
 Patch1:		glibc-2.24-bindrsvport-blacklist.patch
19
+Patch2:		0001-Fix-range-check-in-do_tunable_update_val.patch
20
+Patch3:		0002-malloc-arena-fix.patch
19 21
 Provides:	rtld(GNU_HASH)
20 22
 Requires:       filesystem
21 23
 %description
... ...
@@ -71,6 +73,8 @@ Name Service Cache Daemon
71 71
 sed -i 's/\\$$(pwd)/`pwd`/' timezone/Makefile
72 72
 %patch0 -p1
73 73
 %patch1 -p1
74
+%patch2 -p1
75
+%patch3 -p1
74 76
 install -vdm 755 %{_builddir}/%{name}-build
75 77
 # do not try to explicitly provide GLIBC_PRIVATE versioned libraries
76 78
 %define __find_provides %{_builddir}/%{name}-%{version}/find_provides.sh
... ...
@@ -114,12 +118,6 @@ cd %{_builddir}/%{name}-build
114 114
 # just rerun/continue make to workaroung it.
115 115
 make %{?_smp_mflags} || make %{?_smp_mflags} || make %{?_smp_mflags}
116 116
 
117
-%check
118
-# disable security hardening for tests
119
-rm -f $(dirname $(gcc -print-libgcc-file-name))/../specs
120
-cd %{_builddir}/glibc-build
121
-make %{?_smp_mflags} check
122
-
123 117
 %install
124 118
 #	Do not remove static libs
125 119
 pushd %{_builddir}/glibc-build
... ...
@@ -169,6 +167,19 @@ popd
169 169
 sed -i 's@#! /bin/bash@#! /bin/sh@' %{buildroot}/usr/bin/ldd
170 170
 sed -i 's@#!/bin/bash@#!/bin/sh@' %{buildroot}/usr/bin/tzselect
171 171
 
172
+%check
173
+cd %{_builddir}/glibc-build
174
+make %{?_smp_mflags} check ||:
175
+# 2 intermittent failures and 2 stable false positives are OK
176
+# XPASS for: elf/tst-protected1a and elf/tst-protected1b
177
+[ `grep ^XPASS tests.sum | wc -l` -ne 2 -a `grep "^XPASS: elf/tst-protected1[ab]" tests.sum | wc -l` -ne 2 ] && exit 1 ||:
178
+
179
+# FAIL (intermittent) for posix/tst-spawn3 and stdio-common/test-vfprintf
180
+n=0
181
+grep "^FAIL: posix/tst-spawn3" tests.sum >/dev/null && n=$((n+1)) ||:
182
+grep "^FAIL: stdio-common/test-vfprintf" tests.sum >/dev/null && n=$((n+1)) ||:
183
+# check for exact 'n' failures
184
+[ `grep ^FAIL tests.sum | wc -l` -ne $n ] && exit 1 ||:
172 185
 
173 186
 %post -p /sbin/ldconfig
174 187
 
... ...
@@ -257,6 +268,10 @@ sed -i 's@#!/bin/bash@#!/bin/sh@' %{buildroot}/usr/bin/tzselect
257 257
 
258 258
 
259 259
 %changelog
260
+*   Tue Aug 29 2017 Alexey Makhalov <amakhalov@vmware.com> 2.26-2
261
+-   Fix tunables setter.
262
+-   Add malloc arena fix.
263
+-   Fix makecheck.
260 264
 *   Tue Aug 15 2017 Alexey Makhalov <amakhalov@vmware.com> 2.26-1
261 265
 -   Version update
262 266
 *   Tue Aug 08 2017 Anish Swaminathan <anishs@vmware.com> 2.25-4