1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 /**********************************************************************
15 *
16 * This module contains freeciv-specific memory management functions
17 *
18 **********************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include <fc_config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 /* utility */
28 #include "fcintl.h"
29 #include "log.h"
30 #include "shared.h" /* TRUE, FALSE */
31
32 #include "mem.h"
33
34 /**********************************************************************
35 Do whatever we should do when malloc fails.
36 At the moment this just prints a log message and calls exit(EXIT_FAILURE)
37 **********************************************************************/
handle_alloc_failure(size_t size,const char * called_as,int line,const char * file)38 static void handle_alloc_failure(size_t size, const char *called_as,
39 int line, const char *file)
40 {
41 log_fatal("Out of memory trying to %s %lu bytes at line %d of %s.",
42 called_as, (unsigned long) size, line, file);
43 exit(EXIT_FAILURE);
44 }
45
46 #ifdef FREECIV_DEBUG
47 /****************************************************************************
48 Check the size for sanity.
49 ****************************************************************************/
sanity_check_size(size_t size,const char * called_as,int line,const char * file)50 static void sanity_check_size(size_t size, const char *called_as,
51 int line, const char *file)
52 {
53 /* There used to be a sanity check here that would abort if more than
54 * 30 megabytes were allocated. Unfortunately this didn't work because
55 * savegame loading can potentially use a huge amount of memory for large
56 * games. Another problem is it doesn't help much because there's nothing
57 * preventing a large number of smaller allocations. */
58
59 if (size == 0) {
60 log_verbose("Warning: %s with size %lu at line %d of %s",
61 called_as, (unsigned long) size, line, file);
62 }
63 }
64 #endif /* FREECIV_DEBUG */
65
66 /*******************************************************************************
67 Function used by fc_malloc macro, malloc() replacement
68
69 There's no need for the caller to check return value; this function will
70 always return a valid pointer (even for a 0-byte malloc).
71 *******************************************************************************/
fc_real_malloc(size_t size,const char * called_as,int line,const char * file)72 void *fc_real_malloc(size_t size,
73 const char *called_as, int line, const char *file)
74 {
75 void *ptr;
76
77 #ifdef FREECIV_DEBUG
78 sanity_check_size(size, called_as, line, file);
79 #endif /* FREECIV_DEBUG */
80
81 /* Some systems return NULL on malloc(0)
82 * According to ANSI C, the return is implementation-specific,
83 * this is a safe guard. Having the extra byte is, of course, harmless. */
84 #ifndef MALLOC_ZERO_OK
85 size = MAX(size, 1);
86 #endif
87
88 ptr = malloc(size);
89 if (ptr == NULL) {
90 handle_alloc_failure(size, called_as, line, file);
91 }
92
93 return ptr;
94 }
95
96 /**********************************************************************
97 Function used by fc_realloc macro, realloc() replacement
98 No need to check return value.
99 **********************************************************************/
fc_real_realloc(void * ptr,size_t size,const char * called_as,int line,const char * file)100 void *fc_real_realloc(void *ptr, size_t size,
101 const char *called_as, int line, const char *file)
102 {
103 void *new_ptr;
104
105 if (!ptr) {
106 return fc_real_malloc(size, called_as, line, file);
107 }
108
109 #ifdef FREECIV_DEBUG
110 sanity_check_size(size, called_as, line, file);
111 #endif /* FREECIV_DEBUG */
112
113 new_ptr = realloc(ptr, size);
114 if (!new_ptr) {
115 handle_alloc_failure(size, called_as, line, file);
116 }
117 return new_ptr;
118 }
119
120 /**********************************************************************
121 Function used by fc_calloc macro, calloc() replacement
122 No need to check return value.
123
124 I'm pretty sure only the product of nelem and elsize can ever
125 matter here, and not their individual values. (As a matter of C.)
126 Except this function doesn't support calloc-ing more memory than
127 can be expressing using a single size_t, but that's not likely
128 to be a problem.
129 **********************************************************************/
fc_real_calloc(size_t nelem,size_t elsize,const char * called_as,int line,const char * file)130 void *fc_real_calloc(size_t nelem, size_t elsize,
131 const char *called_as, int line, const char *file)
132 {
133 size_t size = nelem*elsize; /* potential overflow */
134 void *ptr;
135
136 ptr = fc_real_malloc(size, called_as, line, file);
137 memset(ptr, 0, size);
138 return ptr;
139 }
140
141 /***************************************************************
142 Function used by fc_strdup macro, strdup() replacement
143 No need to check return value.
144 ***************************************************************/
real_fc_strdup(const char * str,const char * called_as,int line,const char * file)145 char *real_fc_strdup(const char *str,
146 const char *called_as, int line, const char *file)
147 {
148 char *dest = fc_real_malloc(strlen(str)+1, called_as, line, file);
149
150 /* no need to check whether dest is non-NULL! */
151 strcpy(dest, str);
152 return dest;
153 }
154