Fix warnings: memory.c: xcalloc(): 0 size calloc: CW.

Problem    : Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)
             @ 148.
Diagnostic : Cautionary warning.
Rationale  : Reported circumstance (calling calloc with requesting 0
             size allocation) can occur, and it's not an issue. It's
             perfectly legal doing so, though result is implementation
             dependant. A given implementation can return NULL or a
             valid pointer, so that free() can be called on it later the
             same as if it was a real pointer. Such a pointer should not
             be dereferenced, though.
             Now, for some reason I can't explain, compiler is warning
             us in the case of calloc, but not in the case of malloc,
             which is doing the same.
Resolution : Refactor memory functions to avoid using implementation
             dependant behaviour.
             Proposed code is neater to read, and it avoids calling
             system memory functions with size 0, thus behaving the same
             everywhere.
             Note that semantics for xmalloc/xcalloc is slightly
             changed:
             - Previously, an implementation that returns a valid
               pointer on malloc/calloc with 0 size, would return that
               pointer to xmalloc/xcalloc caller.
             - Currently, a regular pointer is always returned.
This commit is contained in:
Eliseo Martínez
2014-11-10 14:37:31 +01:00
parent 51080737df
commit 8bb2c2c074

View File

@@ -78,17 +78,11 @@ static void try_to_free_memory(void)
/// @return pointer to allocated space. NULL if out of memory /// @return pointer to allocated space. NULL if out of memory
void *try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1) void *try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1)
{ {
size = size ? size : 1;
void *ret = malloc(size); void *ret = malloc(size);
if (!ret && !size) {
ret = malloc(1);
}
if (!ret) { if (!ret) {
try_to_free_memory(); try_to_free_memory();
ret = malloc(size); ret = malloc(size);
if (!ret && !size) {
ret = malloc(1);
}
} }
return ret; return ret;
} }
@@ -120,7 +114,6 @@ void *xmalloc(size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1) FUNC_ATTR_NONNULL_RET
{ {
void *ret = try_malloc(size); void *ret = try_malloc(size);
if (!ret) { if (!ret) {
OUT_STR(e_outofmem); OUT_STR(e_outofmem);
out_char('\n'); out_char('\n');
@@ -138,23 +131,16 @@ void *xmalloc(size_t size)
void *xcalloc(size_t count, size_t size) void *xcalloc(size_t count, size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE_PROD(1, 2) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE_PROD(1, 2) FUNC_ATTR_NONNULL_RET
{ {
void *ret = calloc(count, size); void *ret = count && size ? calloc(count, size) : calloc(1, 1);
if (!ret && (!count || !size))
ret = calloc(1, 1);
if (!ret) { if (!ret) {
try_to_free_memory(); try_to_free_memory();
ret = calloc(count, size); ret = count && size ? calloc(count, size) : calloc(1, 1);
if (!ret && (!count || !size))
ret = calloc(1, 1);
if (!ret) { if (!ret) {
OUT_STR(e_outofmem); OUT_STR(e_outofmem);
out_char('\n'); out_char('\n');
preserve_exit(); preserve_exit();
} }
} }
return ret; return ret;
} }
@@ -166,23 +152,16 @@ void *xcalloc(size_t count, size_t size)
void *xrealloc(void *ptr, size_t size) void *xrealloc(void *ptr, size_t size)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALLOC_SIZE(2) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALLOC_SIZE(2) FUNC_ATTR_NONNULL_RET
{ {
void *ret = realloc(ptr, size); void *ret = size ? realloc(ptr, size) : realloc(ptr, 1);
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) { if (!ret) {
try_to_free_memory(); try_to_free_memory();
ret = realloc(ptr, size); ret = size ? realloc(ptr, size) : realloc(ptr, 1);
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) { if (!ret) {
OUT_STR(e_outofmem); OUT_STR(e_outofmem);
out_char('\n'); out_char('\n');
preserve_exit(); preserve_exit();
} }
} }
return ret; return ret;
} }
@@ -195,14 +174,12 @@ void *xmallocz(size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
{ {
size_t total_size = size + 1; size_t total_size = size + 1;
void *ret;
if (total_size < size) { if (total_size < size) {
OUT_STR(_("Vim: Data too large to fit into virtual memory space\n")); OUT_STR(_("Vim: Data too large to fit into virtual memory space\n"));
preserve_exit(); preserve_exit();
} }
ret = xmalloc(total_size); void *ret = xmalloc(total_size);
((char*)ret)[size] = 0; ((char*)ret)[size] = 0;
return ret; return ret;