buffer.c (dovecot-2.3.16) | : | buffer.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 17 | skipping to change at line 17 | |||
struct real_buffer { | struct real_buffer { | |||
union { | union { | |||
struct buffer buf; | struct buffer buf; | |||
struct { | struct { | |||
/* public: */ | /* public: */ | |||
const void *r_buffer; | const void *r_buffer; | |||
size_t used; | size_t used; | |||
/* private: */ | /* private: */ | |||
unsigned char *w_buffer; | unsigned char *w_buffer; | |||
size_t dirty, alloc, max_size; | size_t dirty, alloc, writable_size, max_size; | |||
pool_t pool; | pool_t pool; | |||
bool alloced:1; | bool alloced:1; | |||
bool dynamic:1; | bool dynamic:1; | |||
}; | }; | |||
}; | }; | |||
}; | }; | |||
typedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1]; | typedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1]; | |||
skipping to change at line 42 | skipping to change at line 42 | |||
if (size == buf->alloc) | if (size == buf->alloc) | |||
return; | return; | |||
i_assert(size > buf->alloc); | i_assert(size > buf->alloc); | |||
if (buf->w_buffer == NULL) | if (buf->w_buffer == NULL) | |||
buf->w_buffer = p_malloc(buf->pool, size); | buf->w_buffer = p_malloc(buf->pool, size); | |||
else | else | |||
buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, s ize); | buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, s ize); | |||
buf->alloc = size; | buf->alloc = size; | |||
buf->writable_size = size-1; /* -1 for str_c() NUL */ | ||||
buf->r_buffer = buf->w_buffer; | buf->r_buffer = buf->w_buffer; | |||
buf->alloced = TRUE; | buf->alloced = TRUE; | |||
} | } | |||
static inline void | static inline void | |||
buffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size) | buffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size) | |||
{ | { | |||
unsigned int extra; | ||||
size_t new_size; | size_t new_size; | |||
if (unlikely(buf->max_size - pos < data_size)) | if (unlikely(buf->max_size - pos < data_size)) | |||
i_panic("Buffer write out of range (%zu + %zu)", pos, data_size); | i_panic("Buffer write out of range (%zu + %zu)", pos, data_size); | |||
new_size = pos + data_size; | new_size = pos + data_size; | |||
if (new_size > buf->used && buf->used < buf->dirty) { | if (new_size > buf->used && buf->used < buf->dirty) { | |||
/* clear used..dirty area */ | /* clear used..dirty area */ | |||
size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size); | size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size); | |||
memset(buf->w_buffer + buf->used, 0, max - buf->used); | memset(buf->w_buffer + buf->used, 0, max - buf->used); | |||
} | } | |||
/* always keep +1 byte allocated available in case str_c() is called | /* Use buf->writable_size instead of buf->alloc to always keep +1 byte | |||
for this buffer. this is mainly for cases where the buffer is | available in case str_c() is called for this buffer. This is mainly | |||
allocated from data stack, and str_c() is called in a separate stack | for cases where the buffer is allocated from data stack, and str_c() | |||
frame. */ | is called in a separate stack frame. */ | |||
extra = buf->dynamic ? 1 : 0; | if (new_size > buf->writable_size) { | |||
if (new_size + extra > buf->alloc) { | ||||
if (unlikely(!buf->dynamic)) { | if (unlikely(!buf->dynamic)) { | |||
i_panic("Buffer full (%zu > %zu, pool %s)", | i_panic("Buffer full (%zu > %zu, pool %s)", | |||
pos + data_size, buf->alloc, | pos + data_size, buf->alloc, | |||
buf->pool == NULL ? "<none>" : | buf->pool == NULL ? "<none>" : | |||
pool_get_name(buf->pool)); | pool_get_name(buf->pool)); | |||
} | } | |||
buffer_alloc(buf, pool_get_exp_grown_size(buf->pool, buf->alloc, | size_t new_alloc_size = | |||
new_size + extra)); | pool_get_exp_grown_size(buf->pool, buf->alloc, | |||
new_size + 1); | ||||
if (new_alloc_size > buf->max_size) { | ||||
/* limit to max_size, but do include +1 for | ||||
str_c() NUL */ | ||||
new_alloc_size = buf->max_size + 1; | ||||
} | ||||
buffer_alloc(buf, new_alloc_size); | ||||
} | } | |||
#if 0 | #if 0 | |||
else if (new_size > buf->used && buf->alloced && | else if (new_size > buf->used && buf->alloced && | |||
!buf->pool->alloconly_pool && !buf->pool->datastack_pool) { | !buf->pool->alloconly_pool && !buf->pool->datastack_pool) { | |||
void *new_buf; | void *new_buf; | |||
/* buffer's size increased: move the buffer's memory elsewhere. | /* buffer's size increased: move the buffer's memory elsewhere. | |||
this should help catch bugs where old pointers are tried to | this should help catch bugs where old pointers are tried to | |||
be used to access the buffer's memory */ | be used to access the buffer's memory */ | |||
new_buf = p_malloc(buf->pool, buf->alloc); | new_buf = p_malloc(buf->pool, buf->alloc); | |||
skipping to change at line 104 | skipping to change at line 110 | |||
buf->r_buffer = new_buf; | buf->r_buffer = new_buf; | |||
} | } | |||
#endif | #endif | |||
if (new_size > buf->used) | if (new_size > buf->used) | |||
buf->used = new_size; | buf->used = new_size; | |||
i_assert(buf->used <= buf->alloc); | i_assert(buf->used <= buf->alloc); | |||
i_assert(buf->w_buffer != NULL); | i_assert(buf->w_buffer != NULL); | |||
} | } | |||
static inline void | ||||
buffer_check_append_limits(struct real_buffer *buf, size_t data_size) | ||||
{ | ||||
/* Fast path: See if data to be appended fits into allocated buffer. | ||||
If it does, we don't even need to memset() the dirty buffer since | ||||
it's going to be filled with the newly appended data. */ | ||||
if (buf->writable_size - buf->used < data_size) | ||||
buffer_check_limits(buf, buf->used, data_size); | ||||
else | ||||
buf->used += data_size; | ||||
} | ||||
#undef buffer_create_from_data | #undef buffer_create_from_data | |||
void buffer_create_from_data(buffer_t *buffer, void *data, size_t size) | void buffer_create_from_data(buffer_t *buffer, void *data, size_t size) | |||
{ | { | |||
struct real_buffer *buf; | struct real_buffer *buf; | |||
i_assert(sizeof(*buffer) >= sizeof(struct real_buffer)); | i_assert(sizeof(*buffer) >= sizeof(struct real_buffer)); | |||
buf = (struct real_buffer *)buffer; | buf = container_of(buffer, struct real_buffer, buf); | |||
i_zero(buf); | i_zero(buf); | |||
buf->alloc = buf->max_size = size; | buf->alloc = buf->writable_size = buf->max_size = size; | |||
buf->r_buffer = buf->w_buffer = data; | buf->r_buffer = buf->w_buffer = data; | |||
/* clear the whole memory area. unnecessary usually, but if the | /* clear the whole memory area. unnecessary usually, but if the | |||
buffer is used by e.g. str_c() it tries to access uninitialized | buffer is used by e.g. str_c() it tries to access uninitialized | |||
memory */ | memory */ | |||
memset(data, 0, size); | memset(data, 0, size); | |||
} | } | |||
#undef buffer_create_from_const_data | #undef buffer_create_from_const_data | |||
void buffer_create_from_const_data(buffer_t *buffer, | void buffer_create_from_const_data(buffer_t *buffer, | |||
const void *data, size_t size) | const void *data, size_t size) | |||
{ | { | |||
struct real_buffer *buf; | struct real_buffer *buf; | |||
i_assert(sizeof(*buffer) >= sizeof(struct real_buffer)); | i_assert(sizeof(*buffer) >= sizeof(struct real_buffer)); | |||
buf = (struct real_buffer *)buffer; | buf = container_of(buffer, struct real_buffer, buf); | |||
i_zero(buf); | i_zero(buf); | |||
buf->used = buf->alloc = buf->max_size = size; | buf->used = buf->alloc = buf->writable_size = buf->max_size = size; | |||
buf->r_buffer = data; | buf->r_buffer = data; | |||
i_assert(buf->w_buffer == NULL); | i_assert(buf->w_buffer == NULL); | |||
} | } | |||
buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size) | buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size) | |||
{ | { | |||
return buffer_create_dynamic_max(pool, init_size, SIZE_MAX); | return buffer_create_dynamic_max(pool, init_size, SIZE_MAX); | |||
} | } | |||
buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size, | buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size, | |||
skipping to change at line 164 | skipping to change at line 182 | |||
#endif | #endif | |||
buf = p_new(pool, struct real_buffer, 1); | buf = p_new(pool, struct real_buffer, 1); | |||
buf->pool = pool; | buf->pool = pool; | |||
buf->dynamic = TRUE; | buf->dynamic = TRUE; | |||
buf->max_size = max_size; | buf->max_size = max_size; | |||
/* buffer_alloc() reserves +1 for str_c() NIL, so add +1 here to | /* buffer_alloc() reserves +1 for str_c() NIL, so add +1 here to | |||
init_size so we can actually write that much to the buffer without | init_size so we can actually write that much to the buffer without | |||
realloc */ | realloc */ | |||
buffer_alloc(buf, init_size+1); | buffer_alloc(buf, init_size+1); | |||
return (buffer_t *)buf; | return &buf->buf; | |||
} | } | |||
void buffer_free(buffer_t **_buf) | void buffer_free(buffer_t **_buf) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)*_buf; | struct real_buffer *buf = container_of(*_buf, struct real_buffer, buf); | |||
if (buf == NULL) | if (buf == NULL) | |||
return; | return; | |||
*_buf = NULL; | *_buf = NULL; | |||
if (buf->alloced) | if (buf->alloced) | |||
p_free(buf->pool, buf->w_buffer); | p_free(buf->pool, buf->w_buffer); | |||
if (buf->pool != NULL) | if (buf->pool != NULL) | |||
p_free(buf->pool, buf); | p_free(buf->pool, buf); | |||
} | } | |||
void *buffer_free_without_data(buffer_t **_buf) | void *buffer_free_without_data(buffer_t **_buf) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)*_buf; | struct real_buffer *buf = container_of(*_buf, struct real_buffer, buf); | |||
void *data; | void *data; | |||
*_buf = NULL; | *_buf = NULL; | |||
data = buf->w_buffer; | data = buf->w_buffer; | |||
p_free(buf->pool, buf); | p_free(buf->pool, buf); | |||
return data; | return data; | |||
} | } | |||
pool_t buffer_get_pool(const buffer_t *_buf) | pool_t buffer_get_pool(const buffer_t *_buf) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, const struct real_buffer, buf); | ||||
return buf->pool; | return buf->pool; | |||
} | } | |||
void buffer_write(buffer_t *_buf, size_t pos, | void buffer_write(buffer_t *_buf, size_t pos, | |||
const void *data, size_t data_size) | const void *data, size_t data_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
buffer_check_limits(buf, pos, data_size); | buffer_check_limits(buf, pos, data_size); | |||
if (data_size > 0) | if (data_size > 0) | |||
memcpy(buf->w_buffer + pos, data, data_size); | memcpy(buf->w_buffer + pos, data, data_size); | |||
} | } | |||
void buffer_append(buffer_t *buf, const void *data, size_t data_size) | void buffer_append(buffer_t *_buf, const void *data, size_t data_size) | |||
{ | { | |||
buffer_write(buf, buf->used, data, data_size); | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
if (data_size > 0) { | ||||
size_t pos = buf->used; | ||||
buffer_check_append_limits(buf, data_size); | ||||
memcpy(buf->w_buffer + pos, data, data_size); | ||||
} | ||||
} | } | |||
void buffer_append_c(buffer_t *buf, unsigned char chr) | void buffer_append_c(buffer_t *_buf, unsigned char chr) | |||
{ | { | |||
buffer_append(buf, &chr, 1); | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
size_t pos = buf->used; | ||||
buffer_check_append_limits(buf, 1); | ||||
buf->w_buffer[pos] = chr; | ||||
} | } | |||
void buffer_insert(buffer_t *_buf, size_t pos, | void buffer_insert(buffer_t *_buf, size_t pos, | |||
const void *data, size_t data_size) | const void *data, size_t data_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
if (pos >= buf->used) | if (pos >= buf->used) | |||
buffer_write(_buf, pos, data, data_size); | buffer_write(_buf, pos, data, data_size); | |||
else { | else { | |||
buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX); | buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX); | |||
memcpy(buf->w_buffer + pos, data, data_size); | memcpy(buf->w_buffer + pos, data, data_size); | |||
} | } | |||
} | } | |||
void buffer_delete(buffer_t *_buf, size_t pos, size_t size) | void buffer_delete(buffer_t *_buf, size_t pos, size_t size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
size_t end_size; | size_t end_size; | |||
if (pos >= buf->used) | if (pos >= buf->used) | |||
return; | return; | |||
end_size = buf->used - pos; | end_size = buf->used - pos; | |||
if (size < end_size) { | if (size < end_size) { | |||
/* delete from between */ | /* delete from between */ | |||
end_size -= size; | end_size -= size; | |||
memmove(buf->w_buffer + pos, | memmove(buf->w_buffer + pos, | |||
skipping to change at line 258 | skipping to change at line 287 | |||
/* delete the rest of the buffer */ | /* delete the rest of the buffer */ | |||
end_size = 0; | end_size = 0; | |||
} | } | |||
buffer_set_used_size(_buf, pos + end_size); | buffer_set_used_size(_buf, pos + end_size); | |||
} | } | |||
void buffer_replace(buffer_t *_buf, size_t pos, size_t size, | void buffer_replace(buffer_t *_buf, size_t pos, size_t size, | |||
const void *data, size_t data_size) | const void *data, size_t data_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
size_t end_size; | size_t end_size; | |||
if (pos >= buf->used) { | if (pos >= buf->used) { | |||
buffer_write(_buf, pos, data, data_size); | buffer_write(_buf, pos, data, data_size); | |||
return; | return; | |||
} | } | |||
end_size = buf->used - pos; | end_size = buf->used - pos; | |||
if (size < end_size) { | if (size < end_size) { | |||
end_size -= size; | end_size -= size; | |||
skipping to change at line 290 | skipping to change at line 319 | |||
/* overwrite the end */ | /* overwrite the end */ | |||
end_size = 0; | end_size = 0; | |||
buffer_write(_buf, pos, data, data_size); | buffer_write(_buf, pos, data, data_size); | |||
} | } | |||
buffer_set_used_size(_buf, pos + data_size + end_size); | buffer_set_used_size(_buf, pos + data_size + end_size); | |||
} | } | |||
void buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size) | void buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
buffer_check_limits(buf, pos, data_size); | buffer_check_limits(buf, pos, data_size); | |||
memset(buf->w_buffer + pos, 0, data_size); | memset(buf->w_buffer + pos, 0, data_size); | |||
} | } | |||
void buffer_append_zero(buffer_t *buf, size_t data_size) | void buffer_append_zero(buffer_t *_buf, size_t data_size) | |||
{ | { | |||
buffer_write_zero(buf, buf->used, data_size); | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
/* NOTE: When appending it's enough to check that the limits are | ||||
valid, because the data is already guaranteed to be zero-filled. */ | ||||
buffer_check_limits(buf, buf->used, data_size); | ||||
} | } | |||
void buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size) | void buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
if (pos >= buf->used) | if (pos >= buf->used) | |||
buffer_write_zero(_buf, pos, data_size); | buffer_write_zero(_buf, pos, data_size); | |||
else { | else { | |||
buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX); | buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX); | |||
memset(buf->w_buffer + pos, 0, data_size); | memset(buf->w_buffer + pos, 0, data_size); | |||
} | } | |||
} | } | |||
void buffer_copy(buffer_t *_dest, size_t dest_pos, | void buffer_copy(buffer_t *_dest, size_t dest_pos, | |||
const buffer_t *_src, size_t src_pos, size_t copy_size) | const buffer_t *_src, size_t src_pos, size_t copy_size) | |||
{ | { | |||
struct real_buffer *dest = (struct real_buffer *)_dest; | struct real_buffer *dest = container_of(_dest, struct real_buffer, buf); | |||
const struct real_buffer *src = (const struct real_buffer *)_src; | const struct real_buffer *src = | |||
container_of(_src, const struct real_buffer, buf); | ||||
size_t max_size; | size_t max_size; | |||
i_assert(src_pos <= src->used); | i_assert(src_pos <= src->used); | |||
max_size = src->used - src_pos; | max_size = src->used - src_pos; | |||
if (copy_size > max_size) | if (copy_size > max_size) | |||
copy_size = max_size; | copy_size = max_size; | |||
buffer_check_limits(dest, dest_pos, copy_size); | buffer_check_limits(dest, dest_pos, copy_size); | |||
i_assert(src->r_buffer != NULL); | i_assert(src->r_buffer != NULL); | |||
skipping to change at line 346 | skipping to change at line 380 | |||
} | } | |||
void buffer_append_buf(buffer_t *dest, const buffer_t *src, | void buffer_append_buf(buffer_t *dest, const buffer_t *src, | |||
size_t src_pos, size_t copy_size) | size_t src_pos, size_t copy_size) | |||
{ | { | |||
buffer_copy(dest, dest->used, src, src_pos, copy_size); | buffer_copy(dest, dest->used, src, src_pos, copy_size); | |||
} | } | |||
void *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size) | void *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
buffer_check_limits(buf, pos, size); | buffer_check_limits(buf, pos, size); | |||
return buf->w_buffer + pos; | return buf->w_buffer + pos; | |||
} | } | |||
void *buffer_append_space_unsafe(buffer_t *buf, size_t size) | void *buffer_append_space_unsafe(buffer_t *buf, size_t size) | |||
{ | { | |||
/* NOTE: can't use buffer_check_append_limits() here because it doesn't | ||||
guarantee that the buffer is zero-filled. */ | ||||
return buffer_get_space_unsafe(buf, buf->used, size); | return buffer_get_space_unsafe(buf, buf->used, size); | |||
} | } | |||
void *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r) | void *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, const struct real_buffer, buf); | ||||
if (used_size_r != NULL) | if (used_size_r != NULL) | |||
*used_size_r = buf->used; | *used_size_r = buf->used; | |||
i_assert(buf->used == 0 || buf->w_buffer != NULL); | i_assert(buf->used == 0 || buf->w_buffer != NULL); | |||
return buf->w_buffer; | return buf->w_buffer; | |||
} | } | |||
void buffer_set_used_size(buffer_t *_buf, size_t used_size) | void buffer_set_used_size(buffer_t *_buf, size_t used_size) | |||
{ | { | |||
struct real_buffer *buf = (struct real_buffer *)_buf; | struct real_buffer *buf = container_of(_buf, struct real_buffer, buf); | |||
i_assert(used_size <= buf->alloc); | i_assert(used_size <= buf->alloc); | |||
if (buf->used > buf->dirty) | if (buf->used > buf->dirty) | |||
buf->dirty = buf->used; | buf->dirty = buf->used; | |||
buf->used = used_size; | buf->used = used_size; | |||
} | } | |||
size_t buffer_get_size(const buffer_t *_buf) | size_t buffer_get_size(const buffer_t *_buf) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, const struct real_buffer, buf); | ||||
return buf->alloc; | return buf->alloc; | |||
} | } | |||
size_t buffer_get_writable_size(const buffer_t *_buf) | size_t buffer_get_writable_size(const buffer_t *_buf) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, const struct real_buffer, buf); | ||||
if (!buf->dynamic || buf->alloc == 0) | ||||
return buf->alloc; | ||||
/* we reserve +1 for str_c() NUL in buffer_check_limits(), so don't | /* Use buf->writable_size instead of buf->alloc to reserve +1 for | |||
include that in our return value. otherwise the caller might | str_c() NUL in buffer_check_limits(). Otherwise the caller might | |||
increase the buffer's alloc size unnecessarily when it just wants | increase the buffer's alloc size unnecessarily when it just wants | |||
to access the entire buffer. */ | to access the entire buffer. */ | |||
return buf->alloc-1; | return buf->writable_size; | |||
} | } | |||
size_t buffer_get_avail_size(const buffer_t *_buf) | size_t buffer_get_avail_size(const buffer_t *_buf) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, const struct real_buffer, buf); | ||||
i_assert(buf->alloc >= buf->used); | i_assert(buf->alloc >= buf->used); | |||
return ((buf->dynamic ? SIZE_MAX : buf->alloc) - buf->used); | return ((buf->dynamic ? SIZE_MAX : buf->alloc) - buf->used); | |||
} | } | |||
bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2) | bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2) | |||
{ | { | |||
if (buf1->used != buf2->used) | if (buf1->used != buf2->used) | |||
return FALSE; | return FALSE; | |||
if (buf1->used == 0) | if (buf1->used == 0) | |||
return TRUE; | return TRUE; | |||
return memcmp(buf1->data, buf2->data, buf1->used) == 0; | return memcmp(buf1->data, buf2->data, buf1->used) == 0; | |||
} | } | |||
void buffer_verify_pool(buffer_t *_buf) | void buffer_verify_pool(buffer_t *_buf) | |||
{ | { | |||
const struct real_buffer *buf = (const struct real_buffer *)_buf; | const struct real_buffer *buf = | |||
container_of(_buf, struct real_buffer, buf); | ||||
void *ret; | void *ret; | |||
if (buf->pool != NULL && buf->pool->datastack_pool && buf->alloc > 0) { | if (buf->pool != NULL && buf->pool->datastack_pool && buf->alloc > 0) { | |||
/* this doesn't really do anything except verify the | /* this doesn't really do anything except verify the | |||
stack frame */ | stack frame */ | |||
ret = p_realloc(buf->pool, buf->w_buffer, | ret = p_realloc(buf->pool, buf->w_buffer, | |||
buf->alloc, buf->alloc); | buf->alloc, buf->alloc); | |||
i_assert(ret == buf->w_buffer); | i_assert(ret == buf->w_buffer); | |||
} | } | |||
} | } | |||
End of changes. 37 change blocks. | ||||
45 lines changed or deleted | 83 lines changed or added |