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

Last change on this file since 1532 was 1527, checked in by Sam Hocevar, 16 years ago
  • Factored regex matching stuff.
  • Property svn:keywords set to Id
File size: 8.4 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: load-stream.c 1527 2006-12-29 17:49:11Z sam $
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);
40static FILE *  (*fopen64_orig) (const char *path, const char *mode);
41static int     (*fseek_orig)   (FILE *stream, long offset, int whence);
42static size_t  (*fread_orig)   (void *ptr, size_t size, size_t nmemb,
43                                FILE *stream);
44static int     (*getc_orig)    (FILE *stream);
45static int     (*fgetc_orig)   (FILE *stream);
46static char *  (*fgets_orig)   (char *s, int size, FILE *stream);
47static int     (*ungetc_orig)  (int c, FILE *stream);
48static int     (*fclose_orig)  (FILE *fp);
49
50/* Additional GNUisms */
51static ssize_t (*getline_orig)    (char **lineptr, size_t *n, FILE *stream);
52static ssize_t (*getdelim_orig)   (char **lineptr, size_t *n, int delim,
53                                   FILE *stream);
54static ssize_t (*__getdelim_orig) (char **lineptr, size_t *n, int delim,
55                                   FILE *stream);
56
57void _zz_load_stream(void)
58{
59    LOADSYM(fopen);
60    LOADSYM(fopen64);
61    LOADSYM(fseek);
62    LOADSYM(fread);
63    LOADSYM(getc);
64    LOADSYM(fgetc);
65    LOADSYM(fgets);
66    LOADSYM(ungetc);
67    LOADSYM(fclose);
68
69    LOADSYM(getline);
70    LOADSYM(getdelim);
71    LOADSYM(__getdelim);
72}
73
74/* Our function wrappers */
75#define FOPEN(fn) \
76    do \
77    { \
78        if(!_zz_ready) \
79        { \
80            LOADSYM(fn); \
81            return ORIG(fn)(path, mode); \
82        } \
83        ret = ORIG(fn)(path, mode); \
84        if(ret && _zz_mustwatch(path)) \
85        { \
86            int fd = fileno(ret); \
87            _zz_register(fd); \
88            debug(STR(fn) "(\"%s\", \"%s\") = %p", path, mode, ret); \
89        } \
90    } while(0)
91
92FILE *fopen(const char *path, const char *mode)
93{
94    FILE *ret; FOPEN(fopen); return ret;
95}
96
97FILE *fopen64(const char *path, const char *mode)
98{
99    FILE *ret; FOPEN(fopen64); return ret;
100}
101
102int fseek(FILE *stream, long offset, int whence)
103{
104    int ret, fd;
105
106    if(!_zz_ready)
107        LOADSYM(fseek);
108    fd = fileno(stream);
109    if(!_zz_ready || !_zz_iswatched(fd))
110        return fseek_orig(stream, offset, whence);
111
112    ret = fseek_orig(stream, offset, whence);
113    debug("fseek(%p, %li, %i) = %i", stream, offset, whence, ret);
114    if(ret != 0)
115        return ret;
116
117    switch(whence)
118    {
119        case SEEK_END:
120            offset = ftell(stream);
121            /* fall through */
122        case SEEK_SET:
123            _zz_setpos(fd, offset);
124            break;
125        case SEEK_CUR:
126            _zz_addpos(fd, offset);
127            break;
128    }
129    return 0;
130}
131
132size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
133{
134    long int pos;
135    size_t ret;
136    int fd;
137
138    if(!_zz_ready)
139        LOADSYM(fread);
140    fd = fileno(stream);
141    if(!_zz_ready || !_zz_iswatched(fd))
142        return fread_orig(ptr, size, nmemb, stream);
143
144    pos = ftell(stream);
145    ret = fread_orig(ptr, size, nmemb, stream);
146    debug("fread(%p, %li, %li, %p) = %li",
147          ptr, (long int)size, (long int)nmemb, stream, (long int)ret);
148    if(ret >= 0)
149    {
150        /* XXX: the number of bytes read is not ret * size, because
151         * a partial read may have advanced the stream pointer */
152        long int newpos = ftell(stream);
153        _zz_fuzz(fd, ptr, newpos - pos);
154        _zz_setpos(fd, newpos);
155    }
156    return ret;
157}
158
159#define FGETC(fn) \
160    do { \
161        int fd; \
162        if(!_zz_ready) \
163            LOADSYM(fn); \
164        fd = fileno(stream); \
165        if(!_zz_ready || !_zz_iswatched(fd)) \
166            return ORIG(fn)(stream); \
167        ret = ORIG(fn)(stream); \
168        if(ret != EOF) \
169        { \
170            uint8_t ch = ret; \
171            _zz_fuzz(fd, &ch, 1); \
172            _zz_addpos(fd, 1); \
173            ret = ch; \
174        } \
175        debug(STR(fn)"(%p) = 0x%02x", stream, ret); \
176    } while(0)
177
178int getc(FILE *stream)
179{
180    int ret; FGETC(getc); return ret;
181}
182
183int fgetc(FILE *stream)
184{
185    int ret; FGETC(fgetc); return ret;
186}
187
188char *fgets(char *s, int size, FILE *stream)
189{
190    char *ret = s;
191    int i, fd;
192
193    if(!_zz_ready)
194        LOADSYM(fgets);
195    fd = fileno(stream);
196    if(!_zz_ready || !_zz_iswatched(fd))
197        return fgets_orig(s, size, stream);
198
199    if(size <= 0)
200        ret = NULL;
201    else if(size == 1)
202        s[0] = '\0';
203    else
204    {
205        for(i = 0; i < size - 1; i++)
206        {
207            int ch = fgetc_orig(stream);
208
209            if(ch == EOF)
210            {
211                s[i] = '\0';
212                if(!i)
213                    ret = NULL;
214                break;
215            }
216            s[i] = (char)(unsigned char)ch;
217            _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
218            _zz_addpos(fd, 1);
219            if(s[i] == '\n')
220            {
221                s[i + 1] = '\0';
222                break;
223            }
224        }
225    }
226
227    debug("fgets(%p, %i, %p) = %p", s, size, stream, ret);
228    return ret;
229}
230
231int ungetc(int c, FILE *stream)
232{
233    unsigned char ch = c;
234    int ret, fd;
235
236    if(!_zz_ready)
237        LOADSYM(ungetc);
238    fd = fileno(stream);
239    if(!_zz_ready || !_zz_iswatched(fd))
240        return ungetc_orig(c, stream);
241
242    _zz_addpos(fd, -1);
243    _zz_fuzz(fd, &ch, 1);
244    ret = ungetc_orig((int)ch, stream);
245    if(ret >= 0)
246        ret = c;
247    else
248        _zz_addpos(fd, 1); /* revert what we did */
249    debug("ungetc(0x%02x, %p) = 0x%02x", c, stream, ret);
250    return ret;
251}
252
253int fclose(FILE *fp)
254{
255    int ret, fd;
256
257    if(!_zz_ready)
258        LOADSYM(fclose);
259    fd = fileno(fp);
260    if(!_zz_ready || !_zz_iswatched(fd))
261        return fclose_orig(fp);
262
263    ret = fclose_orig(fp);
264    debug("fclose(%p) = %i", fp, ret);
265    _zz_unregister(fd);
266
267    return ret;
268}
269
270#define GETDELIM(fn, delim, need_delim) \
271    do { \
272        char *line; \
273        ssize_t done, size; \
274        int fd, finished = 0; \
275        if(!_zz_ready) \
276            LOADSYM(fn); \
277        fd = fileno(stream); \
278        if(!_zz_ready || !_zz_iswatched(fd)) \
279            return getdelim_orig(lineptr, n, delim, stream); \
280        line = *lineptr; \
281        size = line ? *n : 0; \
282        ret = done = finished = 0; \
283        for(;;) \
284        { \
285            int ch; \
286            if(done >= size) /* highly inefficient but I don't care */ \
287                line = realloc(line, size = done + 1); \
288            if(finished) \
289            { \
290                line[done] = '\0'; \
291                *n = size; \
292                *lineptr = line; \
293                break; \
294            } \
295            ch = fgetc_orig(stream); \
296            if(ch == EOF) \
297            { \
298                finished = 1; \
299                ret = done; \
300            } \
301            else \
302            { \
303                unsigned char c = ch; \
304                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
305                line[done++] = c; \
306                _zz_addpos(fd, 1); \
307                if(c == delim) \
308                { \
309                    finished = 1; \
310                    ret = done; \
311                } \
312            } \
313        } \
314        if(need_delim) \
315            debug(STR(fn) "(%p, %p, 0x%02x, %p) = %li", \
316                  lineptr, n, delim, stream, (long int)ret); \
317        else \
318            debug(STR(fn) "(%p, %p, %p) = %li", \
319                  lineptr, n, stream, (long int)ret); \
320        return ret; \
321    } while(0)
322
323ssize_t getline(char **lineptr, size_t *n, FILE *stream)
324{
325    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
326}
327
328ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
329{
330    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
331}
332
333ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
334{
335    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
336}
337
Note: See TracBrowser for help on using the repository browser.