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

Last change on this file since 1551 was 1551, checked in by Sam Hocevar, 14 years ago
  • Better debug messages in load-stream.c.
  • Property svn:keywords set to Id
File size: 8.9 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 1551 2007-01-03 22:12:02Z 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);
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\") = [%i]", path, mode, fd); \
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([%i], %li, %i) = %i", fd, 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, [%i]) = %li",
164          ptr, (long int)size, (long int)nmemb, fd, (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        if(ret >= 0x20 && ret <= 0x7f) \
193            debug(STR(fn)"([%i]) = 0x%02x '%c'", fd, ret, (char)ret); \
194        else \
195            debug(STR(fn)"([%i]) = 0x%02x", fd, ret); \
196    } while(0)
197
198int getc(FILE *stream)
199{
200    int ret; FGETC(getc); return ret;
201}
202
203int fgetc(FILE *stream)
204{
205    int ret; FGETC(fgetc); return ret;
206}
207
208char *fgets(char *s, int size, FILE *stream)
209{
210    char *ret = s;
211    int i, fd;
212
213    if(!_zz_ready)
214        LOADSYM(fgets);
215    fd = fileno(stream);
216    if(!_zz_ready || !_zz_iswatched(fd))
217        return fgets_orig(s, size, stream);
218
219    if(size <= 0)
220        ret = NULL;
221    else if(size == 1)
222        s[0] = '\0';
223    else
224    {
225        for(i = 0; i < size - 1; i++)
226        {
227            int ch = fgetc_orig(stream);
228
229            if(ch == EOF)
230            {
231                s[i] = '\0';
232                if(!i)
233                    ret = NULL;
234                break;
235            }
236            s[i] = (char)(unsigned char)ch;
237            _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
238            _zz_addpos(fd, 1);
239            if(s[i] == '\n')
240            {
241                s[i + 1] = '\0';
242                break;
243            }
244        }
245    }
246
247    debug("fgets(%p, %i, [%i]) = %p", s, size, fd, ret);
248    return ret;
249}
250
251int ungetc(int c, FILE *stream)
252{
253    unsigned char ch = c;
254    int ret, fd;
255
256    if(!_zz_ready)
257        LOADSYM(ungetc);
258    fd = fileno(stream);
259    if(!_zz_ready || !_zz_iswatched(fd))
260        return ungetc_orig(c, stream);
261
262    _zz_addpos(fd, -1);
263    _zz_fuzz(fd, &ch, 1);
264    ret = ungetc_orig((int)ch, stream);
265    if(ret >= 0)
266        ret = c;
267    else
268        _zz_addpos(fd, 1); /* revert what we did */
269    if(ret >= 0x20 && ret <= 0x7f)
270        debug("ungetc(0x%02x, [%i]) = 0x%02x '%c'", c, fd, ret, ret);
271    else
272        debug("ungetc(0x%02x, [%i]) = 0x%02x", c, fd, ret);
273    return ret;
274}
275
276int fclose(FILE *fp)
277{
278    int ret, fd;
279
280    if(!_zz_ready)
281        LOADSYM(fclose);
282    fd = fileno(fp);
283    if(!_zz_ready || !_zz_iswatched(fd))
284        return fclose_orig(fp);
285
286    ret = fclose_orig(fp);
287    debug("fclose([%i]) = %i", fd, ret);
288    _zz_unregister(fd);
289
290    return ret;
291}
292
293#define GETDELIM(fn, delim, need_delim) \
294    do { \
295        char *line; \
296        ssize_t done, size; \
297        int fd, finished = 0; \
298        if(!_zz_ready) \
299            LOADSYM(fn); \
300        fd = fileno(stream); \
301        if(!_zz_ready || !_zz_iswatched(fd)) \
302            return getdelim_orig(lineptr, n, delim, stream); \
303        line = *lineptr; \
304        size = line ? *n : 0; \
305        ret = done = finished = 0; \
306        for(;;) \
307        { \
308            int ch; \
309            if(done >= size) /* highly inefficient but I don't care */ \
310                line = realloc(line, size = done + 1); \
311            if(finished) \
312            { \
313                line[done] = '\0'; \
314                *n = size; \
315                *lineptr = line; \
316                break; \
317            } \
318            ch = fgetc_orig(stream); \
319            if(ch == EOF) \
320            { \
321                finished = 1; \
322                ret = done; \
323            } \
324            else \
325            { \
326                unsigned char c = ch; \
327                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
328                line[done++] = c; \
329                _zz_addpos(fd, 1); \
330                if(c == delim) \
331                { \
332                    finished = 1; \
333                    ret = done; \
334                } \
335            } \
336        } \
337        if(need_delim) \
338            debug(STR(fn) "(%p, %p, 0x%02x, [%i]) = %li", \
339                  lineptr, n, delim, fd, (long int)ret); \
340        else \
341            debug(STR(fn) "(%p, %p, [%i]) = %li", \
342                  lineptr, n, fd, (long int)ret); \
343        return ret; \
344    } while(0)
345
346#ifdef HAVE_GETLINE
347ssize_t getline(char **lineptr, size_t *n, FILE *stream)
348{
349    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
350}
351#endif
352
353#ifdef HAVE_GETDELIM
354ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
355{
356    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
357}
358#endif
359
360#ifdef HAVE___GETDELIM
361ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
362{
363    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
364}
365#endif
366
Note: See TracBrowser for help on using the repository browser.