source: zzuf/trunk/src/load-stream.c @ 1543

Revision 1543, 8.7 KB checked in by sam, 6 years ago (diff)
  • The whole crap now builds on OS X. Now if it only agreed to run, too...
  • Property svn:keywords set to Id
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id$
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  load-stream.c: loaded stream functions
17 */
18
19#include "config.h"
20
21#define _GNU_SOURCE /* for getline() and getdelim() */
22
23#if defined HAVE_STDINT_H
24#   include <stdint.h>
25#elif defined HAVE_INTTYPES_H
26#   include <inttypes.h>
27#endif
28#include <stdlib.h>
29#include <dlfcn.h>
30
31#include <stdio.h>
32
33#include "libzzuf.h"
34#include "debug.h"
35#include "fuzz.h"
36#include "load.h"
37
38/* Library functions that we divert */
39static FILE *  (*fopen_orig)   (const char *path, const char *mode);
40#ifdef HAVE_FOPEN64
41static FILE *  (*fopen64_orig) (const char *path, const char *mode);
42#endif
43static int     (*fseek_orig)   (FILE *stream, long offset, int whence);
44static size_t  (*fread_orig)   (void *ptr, size_t size, size_t nmemb,
45                                FILE *stream);
46static int     (*getc_orig)    (FILE *stream);
47static int     (*fgetc_orig)   (FILE *stream);
48static char *  (*fgets_orig)   (char *s, int size, FILE *stream);
49static int     (*ungetc_orig)  (int c, FILE *stream);
50static int     (*fclose_orig)  (FILE *fp);
51
52/* Additional GNUisms */
53#ifdef HAVE_GETLINE
54static ssize_t (*getline_orig)    (char **lineptr, size_t *n, FILE *stream);
55#endif
56#ifdef HAVE_GETDELIM
57static ssize_t (*getdelim_orig)   (char **lineptr, size_t *n, int delim,
58                                   FILE *stream);
59#endif
60#ifdef HAVE___GETDELIM
61static ssize_t (*__getdelim_orig) (char **lineptr, size_t *n, int delim,
62                                   FILE *stream);
63#endif
64
65void _zz_load_stream(void)
66{
67    LOADSYM(fopen);
68#ifdef HAVE_FOPEN64
69    LOADSYM(fopen64);
70#endif
71    LOADSYM(fseek);
72    LOADSYM(fread);
73    LOADSYM(getc);
74    LOADSYM(fgetc);
75    LOADSYM(fgets);
76    LOADSYM(ungetc);
77    LOADSYM(fclose);
78#ifdef HAVE_GETLINE
79    LOADSYM(getline);
80#endif
81#ifdef HAVE_GETDELIM
82    LOADSYM(getdelim);
83#endif
84#ifdef HAVE___GETDELIM
85    LOADSYM(__getdelim);
86#endif
87}
88
89/* Our function wrappers */
90#define FOPEN(fn) \
91    do \
92    { \
93        if(!_zz_ready) \
94        { \
95            LOADSYM(fn); \
96            return ORIG(fn)(path, mode); \
97        } \
98        ret = ORIG(fn)(path, mode); \
99        if(ret && _zz_mustwatch(path)) \
100        { \
101            int fd = fileno(ret); \
102            _zz_register(fd); \
103            debug(STR(fn) "(\"%s\", \"%s\") = %p", path, mode, ret); \
104        } \
105    } while(0)
106
107FILE *fopen(const char *path, const char *mode)
108{
109    FILE *ret; FOPEN(fopen); return ret;
110}
111
112#ifdef HAVE_FOPEN64
113FILE *fopen64(const char *path, const char *mode)
114{
115    FILE *ret; FOPEN(fopen64); return ret;
116}
117#endif
118
119int fseek(FILE *stream, long offset, int whence)
120{
121    int ret, fd;
122
123    if(!_zz_ready)
124        LOADSYM(fseek);
125    fd = fileno(stream);
126    if(!_zz_ready || !_zz_iswatched(fd))
127        return fseek_orig(stream, offset, whence);
128
129    ret = fseek_orig(stream, offset, whence);
130    debug("fseek(%p, %li, %i) = %i", stream, offset, whence, ret);
131    if(ret != 0)
132        return ret;
133
134    switch(whence)
135    {
136        case SEEK_END:
137            offset = ftell(stream);
138            /* fall through */
139        case SEEK_SET:
140            _zz_setpos(fd, offset);
141            break;
142        case SEEK_CUR:
143            _zz_addpos(fd, offset);
144            break;
145    }
146    return 0;
147}
148
149size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
150{
151    long int pos;
152    size_t ret;
153    int fd;
154
155    if(!_zz_ready)
156        LOADSYM(fread);
157    fd = fileno(stream);
158    if(!_zz_ready || !_zz_iswatched(fd))
159        return fread_orig(ptr, size, nmemb, stream);
160
161    pos = ftell(stream);
162    ret = fread_orig(ptr, size, nmemb, stream);
163    debug("fread(%p, %li, %li, %p) = %li",
164          ptr, (long int)size, (long int)nmemb, stream, (long int)ret);
165    if(ret >= 0)
166    {
167        /* XXX: the number of bytes read is not ret * size, because
168         * a partial read may have advanced the stream pointer */
169        long int newpos = ftell(stream);
170        _zz_fuzz(fd, ptr, newpos - pos);
171        _zz_setpos(fd, newpos);
172    }
173    return ret;
174}
175
176#define FGETC(fn) \
177    do { \
178        int fd; \
179        if(!_zz_ready) \
180            LOADSYM(fn); \
181        fd = fileno(stream); \
182        if(!_zz_ready || !_zz_iswatched(fd)) \
183            return ORIG(fn)(stream); \
184        ret = ORIG(fn)(stream); \
185        if(ret != EOF) \
186        { \
187            uint8_t ch = ret; \
188            _zz_fuzz(fd, &ch, 1); \
189            _zz_addpos(fd, 1); \
190            ret = ch; \
191        } \
192        debug(STR(fn)"(%p) = 0x%02x", stream, ret); \
193    } while(0)
194
195int getc(FILE *stream)
196{
197    int ret; FGETC(getc); return ret;
198}
199
200int fgetc(FILE *stream)
201{
202    int ret; FGETC(fgetc); return ret;
203}
204
205char *fgets(char *s, int size, FILE *stream)
206{
207    char *ret = s;
208    int i, fd;
209
210    if(!_zz_ready)
211        LOADSYM(fgets);
212    fd = fileno(stream);
213    if(!_zz_ready || !_zz_iswatched(fd))
214        return fgets_orig(s, size, stream);
215
216    if(size <= 0)
217        ret = NULL;
218    else if(size == 1)
219        s[0] = '\0';
220    else
221    {
222        for(i = 0; i < size - 1; i++)
223        {
224            int ch = fgetc_orig(stream);
225
226            if(ch == EOF)
227            {
228                s[i] = '\0';
229                if(!i)
230                    ret = NULL;
231                break;
232            }
233            s[i] = (char)(unsigned char)ch;
234            _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
235            _zz_addpos(fd, 1);
236            if(s[i] == '\n')
237            {
238                s[i + 1] = '\0';
239                break;
240            }
241        }
242    }
243
244    debug("fgets(%p, %i, %p) = %p", s, size, stream, ret);
245    return ret;
246}
247
248int ungetc(int c, FILE *stream)
249{
250    unsigned char ch = c;
251    int ret, fd;
252
253    if(!_zz_ready)
254        LOADSYM(ungetc);
255    fd = fileno(stream);
256    if(!_zz_ready || !_zz_iswatched(fd))
257        return ungetc_orig(c, stream);
258
259    _zz_addpos(fd, -1);
260    _zz_fuzz(fd, &ch, 1);
261    ret = ungetc_orig((int)ch, stream);
262    if(ret >= 0)
263        ret = c;
264    else
265        _zz_addpos(fd, 1); /* revert what we did */
266    debug("ungetc(0x%02x, %p) = 0x%02x", c, stream, ret);
267    return ret;
268}
269
270int fclose(FILE *fp)
271{
272    int ret, fd;
273
274    if(!_zz_ready)
275        LOADSYM(fclose);
276    fd = fileno(fp);
277    if(!_zz_ready || !_zz_iswatched(fd))
278        return fclose_orig(fp);
279
280    ret = fclose_orig(fp);
281    debug("fclose(%p) = %i", fp, ret);
282    _zz_unregister(fd);
283
284    return ret;
285}
286
287#define GETDELIM(fn, delim, need_delim) \
288    do { \
289        char *line; \
290        ssize_t done, size; \
291        int fd, finished = 0; \
292        if(!_zz_ready) \
293            LOADSYM(fn); \
294        fd = fileno(stream); \
295        if(!_zz_ready || !_zz_iswatched(fd)) \
296            return getdelim_orig(lineptr, n, delim, stream); \
297        line = *lineptr; \
298        size = line ? *n : 0; \
299        ret = done = finished = 0; \
300        for(;;) \
301        { \
302            int ch; \
303            if(done >= size) /* highly inefficient but I don't care */ \
304                line = realloc(line, size = done + 1); \
305            if(finished) \
306            { \
307                line[done] = '\0'; \
308                *n = size; \
309                *lineptr = line; \
310                break; \
311            } \
312            ch = fgetc_orig(stream); \
313            if(ch == EOF) \
314            { \
315                finished = 1; \
316                ret = done; \
317            } \
318            else \
319            { \
320                unsigned char c = ch; \
321                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
322                line[done++] = c; \
323                _zz_addpos(fd, 1); \
324                if(c == delim) \
325                { \
326                    finished = 1; \
327                    ret = done; \
328                } \
329            } \
330        } \
331        if(need_delim) \
332            debug(STR(fn) "(%p, %p, 0x%02x, %p) = %li", \
333                  lineptr, n, delim, stream, (long int)ret); \
334        else \
335            debug(STR(fn) "(%p, %p, %p) = %li", \
336                  lineptr, n, stream, (long int)ret); \
337        return ret; \
338    } while(0)
339
340#ifdef HAVE_GETLINE
341ssize_t getline(char **lineptr, size_t *n, FILE *stream)
342{
343    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
344}
345#endif
346
347#ifdef HAVE_GETDELIM
348ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
349{
350    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
351}
352#endif
353
354#ifdef HAVE___GETDELIM
355ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
356{
357    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
358}
359#endif
360
Note: See TracBrowser for help on using the repository browser.