svn commit: r360233 - in head: contrib/jemalloc . . . : This partially breaks a 2-socket 32-bit powerpc (old PowerMac G4) based on head -r360311

Mark Millard marklmi at yahoo.com
Fri May 8 16:14:34 UTC 2020


[More details for a sshd failure. The other
examples are omitted. The sshd failure also shows
a all-zeros-up-to-a-page-boundary issue, just for
a different address range.]

On 2020-May-7, at 12:06, Mark Millard <marklmi at yahoo.com> wrote:
> 
> [mountd failure example: also at sz_size2index_lookup assert
> for the same zero'd memory problem.]
> 
>> On 2020-May-7, at 00:46, Mark Millard <marklmi at yahoo.com> wrote:
>> 
>> [__je_sz_size2index_tab seems messed up in 2 of the
>> asserting contexts: first 384 are zero in both. More
>> before that is also messed up (all zero). I show the
>> details later below.]
>> 
>> On 2020-May-6, at 16:57, Mark Millard <marklmi at yahoo.com> wrote:
>> 
>>> [This explores process crashes that happen during system
>>> shutdown, in a context not having MALLOC_PRODUCTION= .
>>> So assert failures are reported as the stopping points.]
>>> 
>>> It looks like shutdown -p now, shutdown -r now, and the
>>> like can lead some processes to assert during their exit
>>> attempt, including a sshd failure (that I've not seen
>>> before), rpcbind, and nfsd. I show information about the
>>> observed asserts for those below.
>>> 
>>> 
>>> sshd hit an assert, failing slab == extent_slab_get(extent) :
>>> 
>>> (gdb) bt 
>>> #0  thr_kill () at thr_kill.S:4
>>> #1  0x50927170 in __raise (s=6) at /usr/src/lib/libc/gen/raise.c:52
>>> #2  0x50886cc0 in abort () at /usr/src/lib/libc/stdlib/abort.c:67
>>> #3  0x508834b0 in arena_dalloc (tsdn=<optimized out>, ptr=<optimized out>, tcache=<optimized out>, alloc_ctx=<optimized out>, slow_path=<optimized out>)
>>>  at /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h:315
>>> #4  idalloctm (tsdn=0x500dd040, ptr=0x5008a180, tcache=0x500dd160, alloc_ctx=<optimized out>, is_internal=<optimized out>, slow_path=<optimized out>)
>>>  at /usr/src/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_c.h:118
>>> #5  0x5087b0a4 in ifree (tsd=0x500dd040, ptr=0x5008a180, tcache=0x500dd160, slow_path=<optimized out>) at jemalloc_jemalloc.c:2590
>>> #6  0x5087acac in __je_free_default (ptr=0x5008a180) at jemalloc_jemalloc.c:2784
>>> #7  0x5087b294 in __free (ptr=0x5008a180) at jemalloc_jemalloc.c:2852
>>> #8  0x10029464 in server_accept_loop (config_s=<optimized out>, sock_in=<optimized out>, sock_out=<optimized out>, newsock=<optimized out>) at /usr/src/crypto/openssh/sshd.c:1185
>>> #9  main (ac=<optimized out>, av=0xffffde3c) at /usr/src/crypto/openssh/sshd.c:2009
>>> 
>>> . . .
>>> (gdb) up
>>> #2  0x50886cc0 in abort () at /usr/src/lib/libc/stdlib/abort.c:67
>>> 67		(void)raise(SIGABRT);
>>> (gdb) up
>>> #3  0x508834b0 in arena_dalloc (tsdn=<optimized out>, ptr=<optimized out>, tcache=<optimized out>, alloc_ctx=<optimized out>, slow_path=<optimized out>)
>>>  at /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h:315
>>> 315			assert(slab == extent_slab_get(extent));
>>> 
>>> (gdb) list
>>> 310			rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
>>> 311			extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
>>> 312			    rtree_ctx, (uintptr_t)ptr, true);
>>> 313			assert(szind == extent_szind_get(extent));
>>> 314			assert(szind < SC_NSIZES);
>>> 315			assert(slab == extent_slab_get(extent));
>>> 316		}
>>> 317	
>>> 318		if (likely(slab)) {
>>> 319			/* Small allocation. */
>>> 
>>> More fully:
>>> 
>>> 285	JEMALLOC_ALWAYS_INLINE void
>>> 286	arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
>>> 287	    alloc_ctx_t *alloc_ctx, bool slow_path) {
>>> 288		assert(!tsdn_null(tsdn) || tcache == NULL);
>>> 289		assert(ptr != NULL);
>>> 290	
>>> 291		if (unlikely(tcache == NULL)) {
>>> 292			arena_dalloc_no_tcache(tsdn, ptr);
>>> 293			return;
>>> 294		}
>>> 295	
>>> 296		szind_t szind;
>>> 297		bool slab;
>>> 298		rtree_ctx_t *rtree_ctx;
>>> 299		if (alloc_ctx != NULL) {
>>> 300			szind = alloc_ctx->szind;
>>> 301			slab = alloc_ctx->slab;
>>> 302			assert(szind != SC_NSIZES);
>>> 303		} else {
>>> 304			rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
>>> 305			rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
>>> 306			    (uintptr_t)ptr, true, &szind, &slab);
>>> 307		}
>>> 308	
>>> 309		if (config_debug) {
>>> 310			rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
>>> 311			extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
>>> 312			    rtree_ctx, (uintptr_t)ptr, true);
>>> 313			assert(szind == extent_szind_get(extent));
>>> 314			assert(szind < SC_NSIZES);
>>> 315			assert(slab == extent_slab_get(extent));
>>> 316		}
>>> 317	
>>> 318		if (likely(slab)) {
>>> 319			/* Small allocation. */
>>> 320			tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
>>> 321			    slow_path);
>>> 322		} else {
>>> 323			arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
>>> 324		}
>>> 325	}
>> 
>> . . .

The machine code for:

309		if (config_debug) {
310			rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
311			extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
312			    rtree_ctx, (uintptr_t)ptr, true);
313			assert(szind == extent_szind_get(extent));
314			assert(szind < SC_NSIZES);
315			assert(slab == extent_slab_get(extent));
316		}

was dropping the address in "extent" the next instruction
after finding it: replacing with with a field's value.
So by the time the status of the assert could be known,
examining extent was a difficulty.

So I touched the source code to force the address to be
kept and to give a place to breakpoint on failure before
calling another routine:

# svnlite diff /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h
Index: /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h
===================================================================
--- /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h	(revision 360322)
+++ /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h	(working copy)
@@ -308,11 +308,11 @@
 
 	if (config_debug) {
 		rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
-		extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
+		extent_t * volatile extent = rtree_extent_read(tsdn, &extents_rtree,
 		    rtree_ctx, (uintptr_t)ptr, true);
 		assert(szind == extent_szind_get(extent));
 		assert(szind < SC_NSIZES);
-		assert(slab == extent_slab_get(extent));
+		assert((slab == extent_slab_get(extent)) ?true :extent==NULL);
 	}
 
 	if (likely(slab)) {


The ":extent==NULL" should be guaranteed to produce :false as a result
but with more code involved to get there. It gave me a place to breakpoint
on failure.

(gdb) bt -full
#0  0x50883258 in arena_dalloc (tsdn=<optimized out>, ptr=<optimized out>, tcache=<optimized out>, alloc_ctx=<optimized out>, slow_path=<optimized out>)
    at /usr/src/contrib/jemalloc/include/jemalloc/internal/arena_inlines_b.h:315
        extent = 0x51007fc0
        slab = <optimized out>
        szind = <optimized out>
        rtree_ctx = 0x500dd06c
        extent = <optimized out>
#1  idalloctm (tsdn=0x500dd040, ptr=0x5008a180, tcache=0x500dd160, alloc_ctx=<optimized out>, is_internal=<optimized out>, slow_path=<optimized out>)
    at /usr/src/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_c.h:118
No locals.
#2  0x5087b0e4 in ifree (tsd=0x500dd040, ptr=0x5008a180, tcache=0x500dd160, slow_path=<optimized out>) at jemalloc_jemalloc.c:2590
        alloc_ctx = {szind = 0, slab = true}
        rtree_ctx = <optimized out>
        usize = <optimized out>
#3  0x5087acec in __je_free_default (ptr=0x5008a180) at jemalloc_jemalloc.c:2784
        tcache = 0x500dd160
        tsd = <optimized out>
#4  0x5087b2d4 in __free (ptr=0x5008a180) at jemalloc_jemalloc.c:2852
        log_var = <optimized out>
        log_var = <optimized out>
#5  0x10029464 in server_accept_loop (config_s=<optimized out>, sock_in=<optimized out>, sock_out=<optimized out>, newsock=<optimized out>) at /usr/src/crypto/openssh/sshd.c:1185
        from = {ss_len = 16 '\020', ss_family = 2 '\002', __ss_pad1 = "\317\200\300\250\001\031", __ss_align = 0, 
          __ss_pad2 = "\000\000\000\000\000\000\000\002Am", '\000' <repeats 19 times>, "\065\341I\000\000\000\000^\264\234\331", '\000' <repeats 12 times>, "^\262\027\034-a\241H\000\000\000\000\000\000\000\000^\264\235Y,\024\247\030\000\000\000\000\000\000\000\000V\312\331f6-N\370\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\b"}
        rnd = '\000' <repeats 255 times>
        startup_p = {6, 7}
        startups = 1
        i = <optimized out>
        maxfd = 6
        fdset = <optimized out>
        fromlen = <optimized out>
        ret = <optimized out>
        j = <optimized out>
        pid = <optimized out>
        laddr = <optimized out>
        raddr = <optimized out>
#6  main (ac=<optimized out>, av=0xffffde3c) at /usr/src/crypto/openssh/sshd.c:2009
        config_s = {8, 9}
        on = 1
        ssh = 0x0
        logfile = <optimized out>
        newsock = -1
        sock_out = -1
        sock_in = -1
        connection_info = <optimized out>
        i = <optimized out>
        opt = <optimized out>
        line = <optimized out>
        r = <optimized out>
        key = <optimized out>
        pubkey = <optimized out>
        keytype = <optimized out>
        fp = <optimized out>
        j = <optimized out>
        new_umask = <optimized out>
        already_daemon = <optimized out>
        remote_port = <optimized out>
        remote_ip = <optimized out>
        rdomain = <optimized out>
--Type <RET> for more, q to quit, c to continue without paging--
        laddr = <optimized out>
        authctxt = <optimized out>
        obytes = <optimized out>
        ibytes = <optimized out>

(gdb) list
310			rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
311			extent_t * volatile extent = rtree_extent_read(tsdn, &extents_rtree,
312			    rtree_ctx, (uintptr_t)ptr, true);
313			assert(szind == extent_szind_get(extent));
314			assert(szind < SC_NSIZES);
315			assert((slab == extent_slab_get(extent)) ?true :extent==NULL);
316		}
317	
318		if (likely(slab)) {
319			/* Small allocation. */

(gdb) print/x extent
$6 = 0x51007fc0

(gdb) print/x *extent
$2 = {e_bits = 0x0, e_addr = 0x0, {e_size_esn = 0x0, e_bsize = 0x0}, ql_link = {qre_next = 0x0, qre_prev = 0x0}, ph_link = {phn_prev = 0x0, phn_next = 0x0, phn_lchild = 0x0}, {e_slab_data = {
      bitmap = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfff8}}, {e_alloc_time = {
        ns = 0x0}, e_prof_tctx = {repr = 0x0}}}}

It looks like the prefix of the above has been stomped on
to be zeros. Checking addresses as well:

(gdb) x/64x extent
0x51007fc0:	0x00000000	0x00000000	0x00000000	0x00000000
0x51007fd0:	0x00000000	0x00000000	0x00000000	0x00000000
0x51007fe0:	0x00000000	0x00000000	0x00000000	0x00000000
0x51007ff0:	0x00000000	0x00000000	0x00000000	0x00000000
0x51008000:	0xffffffff	0xffffffff	0xffffffff	0xffffffff
0x51008010:	0xffffffff	0xffffffff	0xffffffff	0xffffffff
0x51008020:	0xffffffff	0xffffffff	0x0000fff8	0x00000000
0x51008030:	0x00000000	0x00000000	0x00000000	0x00000000
0x51008040:	0x00000800	0x0014f000	0x5008b000	0x00005000
0x51008050:	0x51008040	0x51008040	0x00000000	0x00000000
0x51008060:	0x00000000	0x00000000	0x00000000	0x00000000
0x51008070:	0x00000000	0x00000000	0x00000000	0x00000000
0x51008080:	0x00000000	0x00000000	0x00000000	0x00000000
0x51008090:	0x00000000	0x00000000	0x00000000	0x00000000
0x510080a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x510080b0:	0x00000000	0x00000000	0x00000000	0x00000000

Note that the non-zero values start at: 0x51008000, again a page
boundary, like the other examples in prior notes for other cases.
This appears to be another example of memory having been stomped
on/replaced that likely previously had the intended values.

The first prior non-zero values are at:

0x51005a30:	0x00000000	0x51008740	0x0000000f	0x01000000
0x51005a40:	0x51008740	0x0000000f	0x01000000	0x51008740
0x51005a50:	0x0000000f	0x01000000	0x51008740	0x0000000f
0x51005a60:	0x01000000	0x51008740	0x0000000f	0x01000000
0x51005a70:	0x51008740	0x0000000f	0x01000000	0x51008740
0x51005a80:	0x0000000f	0x01000000	0x51008940	0x00000014
0x51005a90:	0x01000000	0x510089c0	0x00000014	0x01000000
0x51005aa0:	0x51008a40	0x00000018	0x01000000	0x51008ac0
0x51005ab0:	0x00000018	0x01000000	0x51008b40	0x00000018
0x51005ac0:	0x01000000	0x51008bc0	0x00000018	0x01000000
0x51005ad0:	0x51008c40	0x00000018	0x01000000	0x51008cc0
0x51005ae0:	0x00000001	0x01000000	0x00000000	0x00000000

So the pages for address ranges 0x51006yyy and 0x51007yyy seem to be
all-zero, along with the tail of the page for the range 0x51005yyy.

#2 (ifree) in the backtrace shows the alloc_ctx content:

         alloc_ctx = {szind = 0, slab = true}

So slab==true but the bit in extent->e_bits==false, leading to
the failed assert.

Before going to sleep for the night, I could ssh into the
old PowerMac without this detection. After getting up, trying
the same got the failure detection. I did not have the machine
doing anything else special between.

The other examples in the other programs are similar: just
waiting long enough with normal background processing going
on eventually leads to the context for the next explicit use
(or exit) to detect the problem.

I'm still no where near identifying when the stomped-on memory
range is trashed with zeros in code terms in any example
program.

But sshd, dhclient, rpcbind, nfsd, and sendmail all seem to
have some common subject area(s) involved in their
implementation. So I suspect something common across those
is essentially involved.


For reference:

In #0:

(gdb) print/x rtree_ctx
$5 = 0x500dd06c

(gdb) print/x *rtree_ctx
$4 = {cache = {{leafkey = 0x50000000, leaf = 0x51004fc0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x50c00000, leaf = 0x51008dc0}, {leafkey = 0x1, 
      leaf = 0x0} <repeats 12 times>}, l2_cache = {{leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {
      leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}, {leafkey = 0x1, leaf = 0x0}}}



===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)



More information about the freebsd-ppc mailing list