From 89c6daca1cf13ef870cb30e39f397b874659e7f8 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 24 Nov 2014 11:39:34 +0100 Subject: MEDIUM: buffers: always assign a dummy empty buffer to channels Channels are now created with a valid pointer to a buffer before the buffer is allocated. This buffer is a global one called "buf_empty" and of size zero. Thus it prevents any activity from being performed on the buffer and still ensures that chn->buf may always be dereferenced. b_free() also resets the buffer to &buf_empty, and was split into b_drop() which does not reset the buffer. --- include/common/buffer.h | 21 ++++++++++++++++++--- include/proto/channel.h | 1 + src/buffer.c | 4 ++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/common/buffer.h b/include/common/buffer.h index f325aed..e667574 100644 --- a/include/common/buffer.h +++ b/include/common/buffer.h @@ -40,6 +40,7 @@ struct buffer { }; extern struct pool_head *pool2_buffer; +extern struct buffer buf_empty; int init_buffer(); int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len); @@ -409,13 +410,27 @@ static inline struct buffer *b_alloc(struct buffer **buf) return *buf; } -/* Releases buffer *buf. - */ -static inline void b_free(struct buffer **buf) +/* Releases buffer *buf (no check of emptiness) */ +static inline void __b_drop(struct buffer **buf) { pool_free2(pool2_buffer, *buf); } +/* Releases buffer *buf if allocated. */ +static inline void b_drop(struct buffer **buf) +{ + if (!(*buf)->size) + return; + __b_drop(buf); +} + +/* Releases buffer *buf if allocated, and replaces it with &buf_empty. */ +static inline void b_free(struct buffer **buf) +{ + b_drop(buf); + *buf = &buf_empty; +} + #endif /* _COMMON_BUFFER_H */ /* diff --git a/include/proto/channel.h b/include/proto/channel.h index cf7b413..1c175e9 100644 --- a/include/proto/channel.h +++ b/include/proto/channel.h @@ -51,6 +51,7 @@ int bo_getblk(struct channel *chn, char *blk, int len, int offset); /* Initialize all fields in the channel. */ static inline void channel_init(struct channel *chn) { + chn->buf = &buf_empty; chn->to_forward = 0; chn->last_read = now_ms; chn->xfer_small = chn->xfer_large = 0; diff --git a/src/buffer.c b/src/buffer.c index 9037dd3..7691026 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -22,6 +22,10 @@ struct pool_head *pool2_buffer; +/* this buffer is used to have a valid pointer to an empty buffer in channels + * which convey no more data. + */ +struct buffer buf_empty = { .p = buf_empty.data }; /* perform minimal intializations, report 0 in case of error, 1 if OK. */ int init_buffer() -- 1.7.12.1