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 }