data-stack.c (dovecot-2.3.16) | : | data-stack.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 115 | skipping to change at line 115 | |||
{ | { | |||
return STACK_BLOCK_DATA(block) + (block->size - block->left); | return STACK_BLOCK_DATA(block) + (block->size - block->left); | |||
} | } | |||
static void data_stack_last_buffer_reset(bool preserve_data ATTR_UNUSED) | static void data_stack_last_buffer_reset(bool preserve_data ATTR_UNUSED) | |||
{ | { | |||
if (last_buffer_block != NULL) { | if (last_buffer_block != NULL) { | |||
#ifdef DEBUG | #ifdef DEBUG | |||
unsigned char *last_alloc_end, *p, *pend; | unsigned char *last_alloc_end, *p, *pend; | |||
/* We assume that this function gets called before | ||||
current_block changes. */ | ||||
i_assert(last_buffer_block == current_block); | ||||
last_alloc_end = data_stack_after_last_alloc(current_block); | last_alloc_end = data_stack_after_last_alloc(current_block); | |||
p = last_alloc_end + MEM_ALIGN(sizeof(size_t)) + last_buffer_size ; | p = last_alloc_end + MEM_ALIGN(sizeof(size_t)) + last_buffer_size ; | |||
pend = last_alloc_end + ALLOC_SIZE(last_buffer_size); | pend = last_alloc_end + ALLOC_SIZE(last_buffer_size); | |||
#endif | #endif | |||
/* reset t_buffer_get() mark - not really needed but makes it | /* reset t_buffer_get() mark - not really needed but makes it | |||
easier to notice if t_malloc()/t_push()/t_pop() is called | easier to notice if t_malloc()/t_push()/t_pop() is called | |||
between t_buffer_get() and t_buffer_alloc(). | between t_buffer_get() and t_buffer_alloc(). | |||
do this before we get to i_panic() to avoid recursive | do this before we get to i_panic() to avoid recursive | |||
panics. */ | panics. */ | |||
last_buffer_block = NULL; | last_buffer_block = NULL; | |||
#ifdef DEBUG | #ifdef DEBUG | |||
/* NOTE: If the below panic triggers, it may also be due to an | ||||
internal bug in data-stack (since this is rather complex). Whi | ||||
le | ||||
debugging whether that is the case, it's a good idea to change | ||||
the | ||||
i_panic() to abort(). Otherwise the i_panic() changes the | ||||
data-stack's internal state and complicates debugging. */ | ||||
while (p < pend) | while (p < pend) | |||
if (*p++ != CLEAR_CHR) | if (*p++ != CLEAR_CHR) | |||
i_panic("t_buffer_get(): buffer overflow"); | i_panic("t_buffer_get(): buffer overflow"); | |||
if (!preserve_data) { | if (!preserve_data) { | |||
p = last_alloc_end; | p = last_alloc_end; | |||
memset(p, CLEAR_CHR, SENTRY_COUNT); | memset(p, CLEAR_CHR, SENTRY_COUNT); | |||
} | } | |||
#endif | #endif | |||
} | } | |||
skipping to change at line 161 | skipping to change at line 170 | |||
/* allocate new block */ | /* allocate new block */ | |||
frame = t_buffer_get(sizeof(*frame)); | frame = t_buffer_get(sizeof(*frame)); | |||
frame->prev = current_frame; | frame->prev = current_frame; | |||
current_frame = frame; | current_frame = frame; | |||
/* mark our current position */ | /* mark our current position */ | |||
current_frame->block = current_block; | current_frame->block = current_block; | |||
current_frame->block_space_left = current_block->left; | current_frame->block_space_left = current_block->left; | |||
current_frame->last_alloc_size = 0; | current_frame->last_alloc_size = 0; | |||
current_frame->marker = marker; | current_frame->marker = marker; | |||
#ifdef DEBUG | ||||
current_frame->alloc_bytes = 0; | ||||
current_frame->alloc_count = 0; | ||||
#endif | ||||
t_buffer_alloc(sizeof(*frame)); | t_buffer_alloc(sizeof(*frame)); | |||
#ifndef STATIC_CHECKER | #ifndef STATIC_CHECKER | |||
return data_stack_frame_id++; | return data_stack_frame_id++; | |||
#else | #else | |||
struct data_stack_frame *ds_frame = i_new(struct data_stack_frame, 1); | struct data_stack_frame *ds_frame = i_new(struct data_stack_frame, 1); | |||
ds_frame->id = data_stack_frame_id++; | ds_frame->id = data_stack_frame_id++; | |||
return ds_frame; | return ds_frame; | |||
#endif | #endif | |||
skipping to change at line 394 | skipping to change at line 407 | |||
static void data_stack_send_grow_event(size_t last_alloc_size) | static void data_stack_send_grow_event(size_t last_alloc_size) | |||
{ | { | |||
if (event_datastack_deinitialized) { | if (event_datastack_deinitialized) { | |||
/* already in the deinitialization code - | /* already in the deinitialization code - | |||
don't send more events */ | don't send more events */ | |||
return; | return; | |||
} | } | |||
if (event_datastack == NULL) | if (event_datastack == NULL) | |||
event_datastack = event_create(NULL); | event_datastack = event_create(NULL); | |||
event_set_name(event_datastack, "data_stack_grow"); | event_set_name(event_datastack, "data_stack_grow"); | |||
if (!event_want_debug(event_datastack)) | ||||
return; | ||||
const char *backtrace; | ||||
if (backtrace_get(&backtrace) == 0) | ||||
event_add_str(event_datastack, "backtrace", backtrace); | ||||
event_add_int(event_datastack, "alloc_size", data_stack_get_alloc_size()) ; | event_add_int(event_datastack, "alloc_size", data_stack_get_alloc_size()) ; | |||
event_add_int(event_datastack, "used_size", data_stack_get_used_size()); | event_add_int(event_datastack, "used_size", data_stack_get_used_size()); | |||
event_add_int(event_datastack, "last_alloc_size", last_alloc_size); | event_add_int(event_datastack, "last_alloc_size", last_alloc_size); | |||
event_add_int(event_datastack, "last_block_size", current_block->size); | event_add_int(event_datastack, "last_block_size", current_block->size); | |||
#ifdef DEBUG | #ifdef DEBUG | |||
event_add_int(event_datastack, "frame_alloc_bytes", | event_add_int(event_datastack, "frame_alloc_bytes", | |||
current_frame->alloc_bytes); | current_frame->alloc_bytes); | |||
event_add_int(event_datastack, "frame_alloc_count", | event_add_int(event_datastack, "frame_alloc_count", | |||
current_frame->alloc_count); | current_frame->alloc_count); | |||
#endif | #endif | |||
event_add_str(event_datastack, "frame_marker", current_frame->marker); | event_add_str(event_datastack, "frame_marker", current_frame->marker); | |||
/* It's possible that the data stack gets grown and shrunk rapidly. | ||||
Try to avoid doing expensive work if the event isn't even used for | ||||
anything. Note that at this point all the event fields must be | ||||
set already that might potentially be used by the filters. */ | ||||
if (!event_want_debug(event_datastack)) | ||||
return; | ||||
/* Getting backtrace is potentially inefficient, so do it after | ||||
checking if the event is wanted. Note that this prevents using the | ||||
backtrace field in event field comparisons. */ | ||||
const char *backtrace; | ||||
if (backtrace_get(&backtrace) == 0) | ||||
event_add_str(event_datastack, "backtrace", backtrace); | ||||
string_t *str = t_str_new(128); | string_t *str = t_str_new(128); | |||
str_printfa(str, "total_used=%zu, total_alloc=%zu, last_alloc_size=%zu", | str_printfa(str, "total_used=%zu, total_alloc=%zu, last_alloc_size=%zu", | |||
data_stack_get_used_size(), | data_stack_get_used_size(), | |||
data_stack_get_alloc_size(), | data_stack_get_alloc_size(), | |||
last_alloc_size); | last_alloc_size); | |||
#ifdef DEBUG | #ifdef DEBUG | |||
str_printfa(str, ", frame_bytes=%llu, frame_alloc_count=%u", | str_printfa(str, ", frame_bytes=%llu, frame_alloc_count=%u", | |||
current_frame->alloc_bytes, current_frame->alloc_count); | current_frame->alloc_bytes, current_frame->alloc_count); | |||
#endif | #endif | |||
e_debug(event_datastack, "Growing data stack by %zu for '%s' (%s)", | e_debug(event_datastack, "Growing data stack by %zu for '%s' (%s)", | |||
skipping to change at line 493 | skipping to change at line 514 | |||
ret = data_stack_after_last_alloc(current_block); | ret = data_stack_after_last_alloc(current_block); | |||
#ifdef DEBUG | #ifdef DEBUG | |||
if (current_block->left - alloc_size < current_block->left_lowwater) | if (current_block->left - alloc_size < current_block->left_lowwater) | |||
current_block->left_lowwater = current_block->left - alloc_size; | current_block->left_lowwater = current_block->left - alloc_size; | |||
#endif | #endif | |||
if (permanent) | if (permanent) | |||
current_block->left -= alloc_size; | current_block->left -= alloc_size; | |||
if (warn) T_BEGIN { | if (warn) T_BEGIN { | |||
/* sending event can cause errno changes. */ | ||||
#ifdef DEBUG | ||||
i_assert(errno == old_errno); | ||||
#else | ||||
int old_errno = errno; | ||||
#endif | ||||
/* warn after allocation, so if e_debug() wants to | /* warn after allocation, so if e_debug() wants to | |||
allocate more memory we don't go to infinite loop */ | allocate more memory we don't go to infinite loop */ | |||
data_stack_send_grow_event(alloc_size); | data_stack_send_grow_event(alloc_size); | |||
/* reset errno back to what it was */ | ||||
errno = old_errno; | ||||
} T_END; | } T_END; | |||
#ifdef DEBUG | #ifdef DEBUG | |||
memcpy(ret, &size, sizeof(size)); | memcpy(ret, &size, sizeof(size)); | |||
ret = PTR_OFFSET(ret, MEM_ALIGN(sizeof(size))); | ret = PTR_OFFSET(ret, MEM_ALIGN(sizeof(size))); | |||
/* make sure the sentry contains CLEAR_CHRs. it might not if we | /* make sure the sentry contains CLEAR_CHRs. it might not if we | |||
had used t_buffer_get(). */ | had used t_buffer_get(). */ | |||
memset(PTR_OFFSET(ret, size), CLEAR_CHR, | memset(PTR_OFFSET(ret, size), CLEAR_CHR, | |||
MEM_ALIGN(size + SENTRY_COUNT) - size); | MEM_ALIGN(size + SENTRY_COUNT) - size); | |||
/* we rely on errno not changing. it shouldn't. */ | /* we rely on errno not changing. it shouldn't. */ | |||
skipping to change at line 534 | skipping to change at line 563 | |||
bool ATTR_NO_SANITIZE_INTEGER | bool ATTR_NO_SANITIZE_INTEGER | |||
t_try_realloc(void *mem, size_t size) | t_try_realloc(void *mem, size_t size) | |||
{ | { | |||
size_t debug_adjust = 0, last_alloc_size; | size_t debug_adjust = 0, last_alloc_size; | |||
unsigned char *after_last_alloc; | unsigned char *after_last_alloc; | |||
if (unlikely(size == 0 || size > SSIZE_T_MAX)) | if (unlikely(size == 0 || size > SSIZE_T_MAX)) | |||
i_panic("Trying to allocate %zu bytes", size); | i_panic("Trying to allocate %zu bytes", size); | |||
block_canary_check(current_block); | block_canary_check(current_block); | |||
data_stack_last_buffer_reset(TRUE); | ||||
last_alloc_size = current_frame->last_alloc_size; | last_alloc_size = current_frame->last_alloc_size; | |||
/* see if we're trying to grow the memory we allocated last */ | /* see if we're trying to grow the memory we allocated last */ | |||
after_last_alloc = data_stack_after_last_alloc(current_block); | after_last_alloc = data_stack_after_last_alloc(current_block); | |||
#ifdef DEBUG | #ifdef DEBUG | |||
debug_adjust = MEM_ALIGN(sizeof(size_t)); | debug_adjust = MEM_ALIGN(sizeof(size_t)); | |||
#endif | #endif | |||
if (after_last_alloc - last_alloc_size + debug_adjust == mem) { | if (after_last_alloc - last_alloc_size + debug_adjust == mem) { | |||
/* yeah, see if we have space to grow */ | /* yeah, see if we have space to grow */ | |||
skipping to change at line 686 | skipping to change at line 716 | |||
} | } | |||
size_t data_stack_get_alloc_size(void) | size_t data_stack_get_alloc_size(void) | |||
{ | { | |||
struct stack_block *block; | struct stack_block *block; | |||
size_t size = 0; | size_t size = 0; | |||
i_assert(current_block->next == NULL); | i_assert(current_block->next == NULL); | |||
for (block = current_block; block != NULL; block = block->prev) | for (block = current_block; block != NULL; block = block->prev) | |||
size += current_block->size; | size += block->size; | |||
return size; | return size; | |||
} | } | |||
size_t data_stack_get_used_size(void) | size_t data_stack_get_used_size(void) | |||
{ | { | |||
struct stack_block *block; | struct stack_block *block; | |||
size_t size = 0; | size_t size = 0; | |||
i_assert(current_block->next == NULL); | i_assert(current_block->next == NULL); | |||
for (block = current_block; block != NULL; block = block->prev) | for (block = current_block; block != NULL; block = block->prev) | |||
size += current_block->size - current_block->left; | size += block->size - block->left; | |||
return size; | return size; | |||
} | } | |||
void data_stack_free_unused(void) | void data_stack_free_unused(void) | |||
{ | { | |||
free(unused_block); | free(unused_block); | |||
unused_block = NULL; | unused_block = NULL; | |||
} | } | |||
void data_stack_init(void) | void data_stack_init(void) | |||
End of changes. 10 change blocks. | ||||
8 lines changed or deleted | 40 lines changed or added |