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