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

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