/* * Verify redzones. * This function is called on free() and realloc(). */ void redzone_check(caddr_t naddr) { struct stack ast, fst; caddr_t haddr, faddr; u_int ncorruptions; u_long nsize; int i; haddr = naddr - REDZONE_HSIZE; bcopy(haddr, &ast, sizeof(ast)); haddr += sizeof(ast); bcopy(haddr, &nsize, sizeof(nsize)); haddr += sizeof(nsize); atomic_subtract_long(&redzone_extra_mem, redzone_size_ntor(nsize) - nsize); /* Look for buffer underflow. */ ncorruptions = 0; for (i = 0; i < REDZONE_CHSIZE; i++, haddr++) { if (*(u_char *)haddr != 0x42) ncorruptions++; } if (ncorruptions > 0) { printf("REDZONE: Buffer underflow detected. %u byte%s " "corrupted before %p (%lu bytes allocated).\n", ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize); printf("Allocation backtrace:\n"); stack_print_ddb(&ast); printf("Free backtrace:\n"); stack_save(&fst); stack_print_ddb(&fst); if (redzone_panic) panic("Stopping here."); } faddr = naddr + nsize; /* Look for buffer overflow. */ ncorruptions = 0; for (i = 0; i < REDZONE_CFSIZE; i++, faddr++) { if (*(u_char *)faddr != 0x42) ncorruptions++; } if (ncorruptions > 0) { printf("REDZONE: Buffer overflow detected. %u byte%s corrupted " "after %p (%lu bytes allocated).\n", ncorruptions, ncorruptions == 1 ? "" : "s", naddr + nsize, nsize); printf("Allocation backtrace:\n"); stack_print_ddb(&ast); printf("Free backtrace:\n"); stack_save(&fst); stack_print_ddb(&fst); if (redzone_panic) panic("Stopping here."); } }
/* * Drop data from (the front of) a sockbuf. If the current record is * exhausted this routine will move onto the next one and continue dropping * data. */ void sbdrop(struct sockbuf *sb, int len) { struct mbuf *m; struct mbuf *free_chain = NULL; sbcheck(sb); crit_enter(); m = sb->sb_mb; while (m && len > 0) { if (m->m_len > len) { m->m_len -= len; m->m_data += len; sb->sb_cc -= len; atomic_subtract_long(&sb->sb_cc_prealloc, len); break; } len -= m->m_len; m = sbunlinkmbuf(sb, m, &free_chain); if (m == NULL && len) m = sb->sb_mb; } /* * Remove any trailing 0-length mbufs in the current record. If * the last record for which data was removed is now empty, m will be * NULL. */ while (m && m->m_len == 0) { m = sbunlinkmbuf(sb, m, &free_chain); } crit_exit(); if (free_chain) m_freem(free_chain); sbcheck(sb); }
/* * Compress mbuf chain m into the socket buffer sb following mbuf tailm. * If tailm is null, the buffer is presumed empty. Also, as a side-effect, * increment the sockbuf counts for each mbuf in the chain. */ void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *tailm) { int eor = 0; struct mbuf *free_chain = NULL; mbuftrackid(m, 23); sbcheck(sb); while (m) { struct mbuf *o; eor |= m->m_flags & M_EOR; /* * Disregard empty mbufs as long as we don't encounter * an end-of-record or there is a trailing mbuf of * the same type to propagate the EOR flag to. * * Defer the m_free() call because it can block and break * the atomicy of the sockbuf. */ if (m->m_len == 0 && (eor == 0 || (((o = m->m_next) || (o = tailm)) && o->m_type == m->m_type))) { o = m->m_next; m->m_next = free_chain; free_chain = m; m = o; continue; } /* See if we can coalesce with preceding mbuf. */ if (tailm && !(tailm->m_flags & M_EOR) && M_WRITABLE(tailm) && m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ m->m_len <= M_TRAILINGSPACE(tailm) && tailm->m_type == m->m_type) { u_long mbcnt_sz; bcopy(mtod(m, caddr_t), mtod(tailm, caddr_t) + tailm->m_len, (unsigned)m->m_len); tailm->m_len += m->m_len; sb->sb_cc += m->m_len; /* update sb counter */ /* * Fix the wrongly updated mbcnt_prealloc */ mbcnt_sz = MSIZE; if (m->m_flags & M_EXT) mbcnt_sz += m->m_ext.ext_size; atomic_subtract_long(&sb->sb_mbcnt_prealloc, mbcnt_sz); o = m->m_next; m->m_next = free_chain; free_chain = m; m = o; continue; } /* Insert whole mbuf. */ if (tailm == NULL) { KASSERT(sb->sb_mb == NULL, ("sbcompress: sb_mb not NULL")); sb->sb_mb = m; /* only mbuf in sockbuf */ sb->sb_lastrecord = m; /* new last record */ } else { tailm->m_next = m; /* tack m on following tailm */ } sb->sb_lastmbuf = m; /* update last mbuf hint */ tailm = m; /* just inserted mbuf becomes the new tail */ m = m->m_next; /* advance to next mbuf */ tailm->m_next = NULL; /* split inserted mbuf off from chain */ /* update sb counters for just added mbuf */ sballoc(sb, tailm); /* clear EOR on intermediate mbufs */ tailm->m_flags &= ~M_EOR; } /* * Propogate EOR to the last mbuf */ if (eor) { if (tailm) tailm->m_flags |= eor; else kprintf("semi-panic: sbcompress"); } /* * Clean up any defered frees. */ while (free_chain) free_chain = m_free(free_chain); sbcheck(sb); }