mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-30 18:07:01 +00:00
Under GCC, enforce proper strbuf_local_buf() arg
Internally the strbuf_local_buf(x) macro uses sizeof(x) to determine the size of the buffer, but this will give the wrong behaviour if x is a pointer (char *x), not an array (char x[]). With this change, invoking it with a pointer will cause a compile error. The safety check makes use of the GCC extensions: __builtin_object_size() and __attribute__((alloc_size(n)). Under non-GCC compilers, the safety check will not be performed.
This commit is contained in:
parent
2ddbb86cb5
commit
fdc6156ec7
14
mem.h
14
mem.h
@ -29,8 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
#define malloc(X) _serval_debug_malloc(X,__WHENCE__)
|
#define malloc(X) _serval_debug_malloc(X,__WHENCE__)
|
||||||
#define calloc(X,Y) _serval_debug_calloc(X,Y,__WHENCE__)
|
#define calloc(X,Y) _serval_debug_calloc(X,Y,__WHENCE__)
|
||||||
#define free(X) _serval_debug_free(X,__WHENCE__)
|
#define free(X) _serval_debug_free(X,__WHENCE__)
|
||||||
void *_serval_debug_malloc(unsigned int bytes, struct __sourceloc whence);
|
void *_serval_debug_malloc(unsigned int bytes, struct __sourceloc whence) __attribute__ ((malloc, alloc_size(1)));
|
||||||
void *_serval_debug_calloc(unsigned int bytes, unsigned int count, struct __sourceloc whence);
|
void *_serval_debug_calloc(unsigned int bytes, unsigned int count, struct __sourceloc whence) __attribute__ ((malloc, alloc_size(1)));
|
||||||
void _serval_debug_free(void *p, struct __sourceloc whence);
|
void _serval_debug_free(void *p, struct __sourceloc whence);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -38,20 +38,20 @@ void _serval_debug_free(void *p, struct __sourceloc whence);
|
|||||||
*
|
*
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
*/
|
*/
|
||||||
void *_emalloc(struct __sourceloc, size_t bytes);
|
void *_emalloc(struct __sourceloc, size_t bytes) __attribute__ ((malloc, alloc_size(2), returns_nonnull));
|
||||||
|
|
||||||
/* Equivalent to realloc(3), but logs an error before returning NULL.
|
/* Equivalent to realloc(3), but logs an error before returning NULL.
|
||||||
*
|
*
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
*/
|
*/
|
||||||
void *_erealloc(struct __sourceloc __whence, void *ptr, size_t bytes);
|
void *_erealloc(struct __sourceloc __whence, void *ptr, size_t bytes) __attribute__ ((alloc_size(3), returns_nonnull));
|
||||||
|
|
||||||
/* Equivalent to malloc(3) followed by memset(3) to zerofill, but logs an error
|
/* Equivalent to malloc(3) followed by memset(3) to zerofill, but logs an error
|
||||||
* before returning NULL.
|
* before returning NULL.
|
||||||
*
|
*
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
*/
|
*/
|
||||||
void *_emalloc_zero(struct __sourceloc, size_t bytes);
|
void *_emalloc_zero(struct __sourceloc, size_t bytes) __attribute__ ((malloc, alloc_size(2), returns_nonnull));
|
||||||
|
|
||||||
/* Equivalent to strdup(3)/strndup(3), but logs an error before returning NULL.
|
/* Equivalent to strdup(3)/strndup(3), but logs an error before returning NULL.
|
||||||
*
|
*
|
||||||
@ -60,8 +60,8 @@ void *_emalloc_zero(struct __sourceloc, size_t bytes);
|
|||||||
*
|
*
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
*/
|
*/
|
||||||
char *_str_edup(struct __sourceloc, const char *str);
|
char *_str_edup(struct __sourceloc, const char *str) __attribute__ ((malloc, returns_nonnull));
|
||||||
char *_strn_edup(struct __sourceloc, const char *str, size_t len);
|
char *_strn_edup(struct __sourceloc, const char *str, size_t len) __attribute__ ((malloc, returns_nonnull));
|
||||||
|
|
||||||
#define emalloc(bytes) _emalloc(__HERE__, (bytes))
|
#define emalloc(bytes) _emalloc(__HERE__, (bytes))
|
||||||
#define erealloc(ptr, bytes) _erealloc(__HERE__, (ptr), (bytes))
|
#define erealloc(ptr, bytes) _erealloc(__HERE__, (ptr), (bytes))
|
||||||
|
34
strbuf.h
34
strbuf.h
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Serval string buffer primitives
|
Serval string buffer primitives
|
||||||
Copyright (C) 2012 Serval Project Inc.
|
Copyright (C) 2012-2015 Serval Project Inc.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License
|
modify it under the terms of the GNU General Public License
|
||||||
@ -238,9 +238,39 @@ typedef const struct strbuf *const_strbuf;
|
|||||||
* printf("%s\n", temp);
|
* printf("%s\n", temp);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
* WARNING: 'buf' must name a char[] array, not a char* pointer. The following
|
||||||
|
* code is wrong:
|
||||||
|
*
|
||||||
|
* char *p = malloc(50);
|
||||||
|
* ...
|
||||||
|
* strbuf b = strbuf_local_buf(p); // ERROR!
|
||||||
|
*
|
||||||
|
* In the above example, sizeof(p) will be 8 (4 on 32-bit architectures) which
|
||||||
|
* is NOT the size of the buffer that p points to (50), and not the desired
|
||||||
|
* effect: the string in strbuf b will be limited to 7 chars in length. If the
|
||||||
|
* buffer pointed to by p were less than 8 in size, then appending to strbuf b
|
||||||
|
* would cause memory corruption and a likely SIGSEGV.
|
||||||
|
*
|
||||||
|
* If compiled with the GNU C compiler, then the above example would result in
|
||||||
|
* an error at compile time.
|
||||||
|
*
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
*/
|
*/
|
||||||
#define strbuf_local_buf(buf) strbuf_local((char*)(buf), sizeof (buf))
|
#ifdef __GNUC__
|
||||||
|
#define strbuf_local_buf(buf) strbuf_local((char*)(buf), (sizeof(buf) == __builtin_object_size(buf, 1)) ? sizeof(buf) : __buffer_arg_is_not_array())
|
||||||
|
#else
|
||||||
|
#define strbuf_local_buf(buf) strbuf_local((char*)(buf), sizeof(buf))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
// If the following error occurs at compile time or this function is not found
|
||||||
|
// at link time, it means that the argument passed to strbuf_local_buf() was
|
||||||
|
// not an array whose size is known at compile time. The most common cause of
|
||||||
|
// this is passing a pointer as the argument. The solution is to use
|
||||||
|
// strbuf_local(b, len) instead of strbuf_local_buf(b), and supply the length
|
||||||
|
// of the buffer explicitly.
|
||||||
|
size_t __buffer_arg_is_not_array() __attribute__ ((error("argument to strbuf_local_buf() must be an array not a pointer")));
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Initialise a strbuf with a caller-supplied backing buffer. The current
|
/** Initialise a strbuf with a caller-supplied backing buffer. The current
|
||||||
* backing buffer and its contents are forgotten, and all strbuf operations
|
* backing buffer and its contents are forgotten, and all strbuf operations
|
||||||
|
Loading…
Reference in New Issue
Block a user