File indexing completed on 2024-04-28 16:08:40
0001 /*************************************************************************** 0002 * Copyright (C) 2013 by Linuxstopmotion contributors; * 0003 * see the AUTHORS file for details. * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 0021 #include <dlfcn.h> 0022 #include <assert.h> 0023 0024 #include "oomtestutil.h" 0025 0026 // make malloc_t a type alias for the type of the malloc function. Now we can 0027 // declare a pointer to a malloc function with something like: 0028 // malloc_t* mallocFnPtr; 0029 typedef void* malloc_t (size_t); 0030 0031 extern "C" { 0032 malloc_t malloc; 0033 void init(); 0034 void realSetMallocsUntilFailure(int); 0035 long realMallocsSoFar(); 0036 void realWrapFileSystem(MockableFileSystem* mfs); 0037 FILE* fopen(const char* filename, const char* mode); 0038 FILE* freopen(const char* filename, const char* mode, FILE* fh); 0039 int fclose(FILE* fh); 0040 int fflush(FILE* fh); 0041 size_t fread(void *out, size_t s, size_t n, FILE *fh); 0042 size_t fwrite(const void *in, size_t s, size_t n, FILE *fh); 0043 int access(const char *name, int type); 0044 int ferror(FILE* fh) throw(); 0045 int unlink(const char *name); 0046 char *getenv(const char *name); 0047 } 0048 0049 // Which future malloc should return 0 instead of attempting to allocate memory 0050 long mallocsUntilFailure; 0051 long mallocCount; 0052 0053 // Pointer to the original libc malloc function, set up by Init(). 0054 malloc_t* realMalloc; 0055 0056 // Pointer to the facade of the file system, set up by Init(). 0057 MockableFileSystem* realFs; 0058 0059 // Pointer to the mock file system if requested, or the facade to the real file 0060 // system if not. 0061 MockableFileSystem* requiredFs; 0062 0063 MockableFileSystem::~MockableFileSystem() { 0064 } 0065 0066 class RealFileSystem : public MockableFileSystem { 0067 typedef FILE* fopen_t(const char*, const char*); 0068 typedef FILE* freopen_t(const char*, const char*, FILE*); 0069 typedef int fclose_t(FILE*); 0070 typedef int fflush_t(FILE*); 0071 typedef size_t fread_t(void *, size_t, size_t, FILE*); 0072 typedef size_t fwrite_t(const void*, size_t, size_t, FILE*); 0073 typedef int access_t(const char*, int); 0074 typedef int ferror_t(FILE*); 0075 typedef int unlink_t(const char *); 0076 typedef char *getenv_t(const char *name); 0077 fopen_t* rfopen; 0078 freopen_t* rfreopen; 0079 fclose_t* rfclose; 0080 fflush_t* rfflush; 0081 fread_t* rfread; 0082 fwrite_t* rfwrite; 0083 access_t* raccess; 0084 ferror_t* rferror; 0085 unlink_t* runlink; 0086 getenv_t* rgetenv; 0087 public: 0088 RealFileSystem() : rfopen(0), rfreopen(0), rfclose(0), rfflush(0), 0089 rfread(0), rfwrite(0), raccess(0), rferror(0), rgetenv(0) { 0090 rfopen = (fopen_t*)dlsym(RTLD_NEXT, "fopen"); 0091 assert(rfopen); 0092 rfreopen = (freopen_t*)dlsym(RTLD_NEXT, "freopen"); 0093 assert(rfreopen); 0094 rfclose = (fclose_t*)dlsym(RTLD_NEXT, "fclose"); 0095 assert(rfclose); 0096 rfflush = (fflush_t*)dlsym(RTLD_NEXT, "fflush"); 0097 assert(rfflush); 0098 rfread = (fread_t*)dlsym(RTLD_NEXT, "fread"); 0099 assert(rfread); 0100 rfwrite = (fwrite_t*)dlsym(RTLD_NEXT, "fwrite"); 0101 assert(rfwrite); 0102 raccess = (access_t*)dlsym(RTLD_NEXT, "access"); 0103 assert(raccess); 0104 rferror = (ferror_t*)dlsym(RTLD_NEXT, "ferror"); 0105 assert(rferror); 0106 runlink = (unlink_t*)dlsym(RTLD_NEXT, "unlink"); 0107 assert(runlink); 0108 rgetenv = (getenv_t*)dlsym(RTLD_NEXT, "getenv"); 0109 assert(rgetenv); 0110 } 0111 ~RealFileSystem() { 0112 } 0113 void setDelegate(MockableFileSystem*) { 0114 } 0115 FILE* fopen(const char* filename, const char* mode) { 0116 return rfopen(filename, mode); 0117 } 0118 FILE* freopen(const char* filename, const char* mode, FILE* fh) { 0119 return rfreopen(filename, mode, fh); 0120 } 0121 int fclose(FILE* fh) { 0122 return rfclose(fh); 0123 } 0124 int fflush(FILE* fh) { 0125 return rfflush(fh); 0126 } 0127 size_t fread(void *out, size_t s, size_t n, FILE *fh) { 0128 return rfread(out, s, n, fh); 0129 } 0130 size_t fwrite(const void *in, size_t s, size_t n, FILE *fh) { 0131 return rfwrite(in, s, n, fh); 0132 } 0133 int access(const char *name, int type) { 0134 return raccess(name, type); 0135 } 0136 int ferror(FILE* fh) throw() { 0137 return rferror(fh); 0138 } 0139 int unlink(const char *name) { 0140 return runlink(name); 0141 } 0142 char *getenv(const char *name) { 0143 return rgetenv(name); 0144 } 0145 }; 0146 0147 // Initialization function sets up the pointer to the original malloc function. 0148 void init() { 0149 if (!realMalloc) { 0150 realMalloc = (malloc_t*)dlsym(RTLD_NEXT, "malloc"); 0151 assert(realMalloc); 0152 } 0153 if (!realFs) { 0154 realFs = new RealFileSystem(); 0155 assert(realFs); 0156 } 0157 if (!requiredFs) { 0158 requiredFs = realFs; 0159 } 0160 } 0161 0162 MockableFileSystem* getFileSystem() { 0163 // This should probably be locked, otherwise we could init twice, 0164 // but that would not be too serious. 0165 if (!requiredFs) { 0166 init(); 0167 } 0168 return requiredFs; 0169 } 0170 0171 void realWrapFileSystem(MockableFileSystem* mfs) { 0172 if (mfs) { 0173 mfs->setDelegate(requiredFs); 0174 requiredFs = mfs; 0175 } else { 0176 requiredFs = realFs; 0177 } 0178 } 0179 0180 // Our malloc does its own processing, then calls the libc malloc, if 0181 // applicable. 0182 void* malloc(size_t bytes) { 0183 __sync_add_and_fetch(&mallocCount, 1); 0184 if (0 < mallocsUntilFailure && 0185 0 == __sync_sub_and_fetch(&mallocsUntilFailure, 1)) 0186 return 0; 0187 if (!realMalloc) 0188 init(); 0189 return realMalloc(bytes); 0190 } 0191 0192 void realSetMallocsUntilFailure(int successes) { 0193 mallocsUntilFailure = successes + 1; 0194 } 0195 0196 long realMallocsSoFar() { 0197 return mallocCount; 0198 } 0199 0200 FILE* fopen(const char* filename, const char* mode) { 0201 return getFileSystem()->fopen(filename, mode); 0202 } 0203 0204 FILE* freopen(const char* filename, const char* mode, FILE* fh) { 0205 return getFileSystem()->freopen(filename, mode, fh); 0206 } 0207 0208 int fclose(FILE* fh) { 0209 return getFileSystem()->fclose(fh); 0210 } 0211 0212 int fflush(FILE* fh) { 0213 return getFileSystem()->fflush(fh); 0214 } 0215 0216 size_t fread(void *out, size_t s, size_t n, FILE *fh) { 0217 return getFileSystem()->fread(out, s, n, fh); 0218 } 0219 0220 size_t fwrite(const void *in, size_t s, size_t n, FILE *fh) { 0221 return getFileSystem()->fwrite(in, s, n, fh); 0222 } 0223 0224 int access(const char *name, int type) { 0225 return getFileSystem()->access(name, type); 0226 } 0227 0228 int ferror(FILE* fh) throw() { 0229 return getFileSystem()->ferror(fh); 0230 } 0231 0232 int unlink(const char *name) { 0233 return getFileSystem()->unlink(name); 0234 } 0235 0236 char *getenv(const char *name) { 0237 return getFileSystem()->getenv(name); 0238 }