1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-18 20:10:29 +01:00
Files
wmaker/WINGs/memory.c
Christophe CURIS 816fa00625 WUtil: Make sure wmalloc/wrealloc won't fail because of the abort handler
As pointed by Coverity (#50074), despite the expected behaviour that
'wmalloc' should never return NULL, it may still happen if an abort handler
set by user (with wsetabort) does not call exit() as expected. In such
case we make sure the NULL pointer dereference does not happen inside
WINGs code because we assume it is a known user choice.

Signed-off-by: Christophe CURIS <christophe.curis@free.fr>
2021-05-18 17:49:17 +01:00

224 lines
4.3 KiB
C

/*
* Window Maker miscelaneous function library
*
* Copyright (c) 1997-2003 Alfredo K. Kojima
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include "wconfig.h"
#include "WUtil.h"
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#ifdef HAVE_STDNORETURN
#include <stdnoreturn.h>
#endif
#ifdef USE_BOEHM_GC
#ifndef GC_DEBUG
#define GC_DEBUG
#endif /* !GC_DEBUG */
#include <gc/gc.h>
#endif /* USE_BOEHM_GC */
#ifndef False
# define False 0
#endif
#ifndef True
# define True 1
#endif
static void defaultHandler(int bla)
{
if (bla)
kill(getpid(), SIGABRT);
else
exit(1);
}
static waborthandler *aborthandler = defaultHandler;
static inline noreturn void wAbort(int bla)
{
(*aborthandler)(bla);
exit(-1);
}
waborthandler *wsetabort(waborthandler * handler)
{
waborthandler *old = aborthandler;
aborthandler = handler;
return old;
}
static int Aborting = 0; /* if we're in the middle of an emergency exit */
static WMHashTable *table = NULL;
void *wmalloc(size_t size)
{
void *tmp;
assert(size > 0);
#ifdef USE_BOEHM_GC
tmp = GC_MALLOC(size);
#else
tmp = malloc(size);
#endif
if (tmp == NULL) {
wwarning("malloc() failed. Retrying after 2s.");
sleep(2);
#ifdef USE_BOEHM_GC
tmp = GC_MALLOC(size);
#else
tmp = malloc(size);
#endif
if (tmp == NULL) {
if (Aborting) {
fputs("Really Bad Error: recursive malloc() failure.", stderr);
exit(-1);
} else {
wfatal("virtual memory exhausted");
Aborting = 1;
wAbort(False);
}
}
}
if (tmp != NULL)
memset(tmp, 0, size);
return tmp;
}
void *wrealloc(void *ptr, size_t newsize)
{
void *nptr;
if (!ptr) {
nptr = wmalloc(newsize);
} else if (newsize == 0) {
wfree(ptr);
nptr = NULL;
} else {
#ifdef USE_BOEHM_GC
nptr = GC_REALLOC(ptr, newsize);
#else
nptr = realloc(ptr, newsize);
#endif
if (nptr == NULL) {
wwarning("realloc() failed. Retrying after 2s.");
sleep(2);
#ifdef USE_BOEHM_GC
nptr = GC_REALLOC(ptr, newsize);
#else
nptr = realloc(ptr, newsize);
#endif
if (nptr == NULL) {
if (Aborting) {
fputs("Really Bad Error: recursive realloc() failure.", stderr);
exit(-1);
} else {
wfatal("virtual memory exhausted");
Aborting = 1;
wAbort(False);
}
}
}
}
return nptr;
}
void *wretain(void *ptr)
{
int *refcount;
if (!table) {
table = WMCreateHashTable(WMIntHashCallbacks);
}
refcount = WMHashGet(table, ptr);
if (!refcount) {
refcount = wmalloc(sizeof(int));
*refcount = 1;
WMHashInsert(table, ptr, refcount);
#ifdef VERBOSE
printf("== %i (%p)\n", *refcount, ptr);
#endif
} else {
(*refcount)++;
#ifdef VERBOSE
printf("+ %i (%p)\n", *refcount, ptr);
#endif
}
return ptr;
}
void wfree(void *ptr)
{
if (ptr)
#ifdef USE_BOEHM_GC
/* This should eventually be removed, once the criss-cross
* of wmalloc()d memory being free()d, malloc()d memory being
* wfree()d, various misuses of calling wfree() on objects
* allocated by libc malloc() and calling libc free() on
* objects allocated by Boehm GC (think external libraries)
* is cleaned up.
*/
if (GC_base(ptr) != 0)
GC_FREE(ptr);
else
free(ptr);
#else
free(ptr);
#endif
ptr = NULL;
}
void wrelease(void *ptr)
{
int *refcount;
refcount = WMHashGet(table, ptr);
if (!refcount) {
wwarning("trying to release unexisting data %p", ptr);
} else {
(*refcount)--;
if (*refcount < 1) {
#ifdef VERBOSE
printf("RELEASING %p\n", ptr);
#endif
WMHashRemove(table, ptr);
wfree(refcount);
wfree(ptr);
}
#ifdef VERBOSE
else {
printf("- %i (%p)\n", *refcount, ptr);
}
#endif
}
}