source: zzuf/trunk/src/lib-stream.c @ 4032

Last change on this file since 4032 was 4032, checked in by Sam Hocevar, 11 years ago

Minor refactoring in lib-stream.c.

  • Property svn:keywords set to Id
File size: 26.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: lib-stream.c 4032 2009-11-25 00:42:32Z 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/* Needed for getline() and getdelim() */
22#define _GNU_SOURCE
23/* Needed for getc_unlocked() on OpenSolaris */
24#define __EXTENSIONS__
25
26/* Define if stdio operations use *only* the refill mechanism */
27#if defined HAVE___SREFILL
28#   define HAVE_DARWIN_STDIO
29#elif defined HAVE___FILBUF || defined HAVE___SRGET || defined HAVE___UFLOW
30#   define HAVE_BSD_STDIO
31#endif
32
33#if defined HAVE_STDINT_H
34#   include <stdint.h>
35#elif defined HAVE_INTTYPES_H
36#   include <inttypes.h>
37#endif
38#include <stdlib.h>
39
40#include <stdio.h>
41#include <sys/types.h>
42#if defined HAVE_UNISTD_H
43#   include <unistd.h> /* Needed for __srefill’s lseek() call */
44#endif
45
46#include "libzzuf.h"
47#include "lib-load.h"
48#include "debug.h"
49#include "fuzz.h"
50#include "fd.h"
51
52#if defined HAVE___SREFILL
53int NEW(__srefill)(FILE *fp);
54#endif
55
56#if defined HAVE___FILBUF
57int NEW(__filbuf)(FILE *fp);
58#endif
59
60#if defined HAVE___SRGET && !defined HAVE___SREFILL
61int NEW(__srget)(FILE *fp);
62#endif
63
64#if defined HAVE___UFLOW
65int NEW(__uflow)(FILE *fp);
66#endif
67
68/* Library functions that we divert */
69static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
70#if defined HAVE_FOPEN64
71static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
72#endif
73#if defined HAVE___FOPEN64
74static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
75#endif
76static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
77                                  FILE *stream);
78#if defined HAVE_FREOPEN64
79static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
80                                  FILE *stream);
81#endif
82#if defined HAVE___FREOPEN64
83static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
84                                     FILE *stream);
85#endif
86static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
87#if defined HAVE_FSEEKO
88static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
89#endif
90#if defined HAVE_FSEEKO64
91static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
92#endif
93#if defined HAVE___FSEEKO64
94static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
95#endif
96#if defined HAVE_FSETPOS64
97static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
98#endif
99#if defined HAVE___FSETPOS64
100static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
101#endif
102static void    (*ORIG(rewind))   (FILE *stream);
103static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
104                                  FILE *stream);
105#if defined HAVE_FREAD_UNLOCKED
106static size_t  (*ORIG(fread_unlocked))  (void *ptr, size_t size, size_t nmemb,
107                                         FILE *stream);
108#endif
109static int     (*ORIG(getc))     (FILE *stream);
110static int     (*ORIG(getchar))  (void);
111static int     (*ORIG(fgetc))    (FILE *stream);
112#if defined HAVE__IO_GETC
113static int     (*ORIG(_IO_getc)) (FILE *stream);
114#endif
115#if defined HAVE_GETC_UNLOCKED
116static int     (*ORIG(getc_unlocked))    (FILE *stream);
117#endif
118#if defined HAVE_GETCHAR_UNLOCKED
119static int     (*ORIG(getchar_unlocked)) (void);
120#endif
121#if defined HAVE_FGETC_UNLOCKED
122static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
123#endif
124static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
125#if defined HAVE_FGETS_UNLOCKED
126static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
127#endif
128static int     (*ORIG(ungetc))   (int c, FILE *stream);
129static int     (*ORIG(fclose))   (FILE *fp);
130
131/* Additional GNUisms */
132#if defined HAVE_GETLINE
133static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
134#endif
135#if defined HAVE_GETDELIM
136static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
137                                    FILE *stream);
138#endif
139#if defined HAVE___GETDELIM
140static ssize_t (*ORIG(__getdelim)) (char **lineptr, size_t *n, int delim,
141                                    FILE *stream);
142#endif
143#if defined HAVE___UFLOW
144static int     (*ORIG(__uflow))    (FILE *fp);
145#endif
146
147/* Additional BSDisms */
148#if defined HAVE_FGETLN
149static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
150#endif
151#if defined HAVE___SREFILL
152int            (*ORIG(__srefill)) (FILE *fp);
153#endif
154#if defined HAVE___SRGET && !defined HAVE___SREFILL
155int            (*ORIG(__srget))   (FILE *fp);
156#endif
157
158/* Additional HP-UXisms */
159#if defined HAVE___FILBUF
160int            (*ORIG(__filbuf))  (FILE *fp);
161#endif
162
163/* Helper functions for refill-like functions */
164static inline uint8_t *get_stream_ptr(FILE *stream)
165{
166#if defined HAVE_BSD_STDIO
167    return (uint8_t *)stream->FILE_PTR;
168#else
169    return NULL;
170#endif
171}
172
173static inline int get_stream_off(FILE *stream)
174{
175#if defined HAVE_BSD_STDIO
176    return (int)((uint8_t *)stream->FILE_PTR - (uint8_t *)stream->FILE_BASE);
177#else
178    return 0;
179#endif
180}
181
182static inline int get_stream_cnt(FILE *stream)
183{
184#if defined HAVE_GLIBC_FP
185    return (int)((uint8_t *)stream->FILE_CNT - (uint8_t *)stream->FILE_PTR);
186#elif defined HAVE_BSD_STDIO
187    return stream->FILE_CNT;
188#else
189    return 0;
190#endif
191}
192
193#define DEBUG_STREAM(prefix, fp) \
194    debug2(prefix "stream([%i], %p, %i)", fileno(fp), \
195           get_stream_ptr(fp), get_stream_cnt(fp));
196
197/*
198 * fopen, fopen64 etc.
199 */
200
201#if defined HAVE_DARWIN_STDIO /* Fuzz fp if we have __srefill() */
202#   define FOPEN_FUZZ() \
203    _zz_fuzz(fd, get_stream_ptr(ret), get_stream_cnt(ret))
204#else
205#   define FOPEN_FUZZ()
206#endif
207
208#define FOPEN(myfopen) \
209    do \
210    { \
211        LOADSYM(myfopen); \
212        if(!_zz_ready) \
213            return ORIG(myfopen)(path, mode); \
214        _zz_lock(-1); \
215        ret = ORIG(myfopen)(path, mode); \
216        _zz_unlock(-1); \
217        if(ret && _zz_mustwatch(path)) \
218        { \
219            int fd = fileno(ret); \
220            _zz_register(fd); \
221            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
222            DEBUG_STREAM("new", ret); \
223            FOPEN_FUZZ(); \
224        } \
225    } while(0)
226
227FILE *NEW(fopen)(const char *path, const char *mode)
228{
229    FILE *ret; FOPEN(fopen); return ret;
230}
231
232#if defined HAVE_FOPEN64
233FILE *NEW(fopen64)(const char *path, const char *mode)
234{
235    FILE *ret; FOPEN(fopen64); return ret;
236}
237#endif
238
239#if defined HAVE___FOPEN64
240FILE *NEW(__fopen64)(const char *path, const char *mode)
241{
242    FILE *ret; FOPEN(__fopen64); return ret;
243}
244#endif
245
246/*
247 * freopen, freopen64 etc.
248 */
249
250#define FREOPEN(myfreopen) \
251    do \
252    { \
253        int fd0 = -1, fd1 = -1, disp = 0; \
254        LOADSYM(myfreopen); \
255        if(_zz_ready && (fd0 = fileno(stream)) >= 0 && _zz_iswatched(fd0)) \
256        { \
257            _zz_unregister(fd0); \
258            disp = 1; \
259        } \
260        _zz_lock(-1); \
261        ret = ORIG(myfreopen)(path, mode, stream); \
262        _zz_unlock(-1); \
263        if(ret && _zz_mustwatch(path)) \
264        { \
265            fd1 = fileno(ret); \
266            _zz_register(fd1); \
267            disp = 1; \
268        } \
269        if(disp) \
270            debug("%s(\"%s\", \"%s\", [%i]) = [%i]", __func__, \
271                  path, mode, fd0, fd1); \
272    } while(0)
273
274FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
275{
276    FILE *ret; FREOPEN(freopen); return ret;
277}
278
279#if defined HAVE_FREOPEN64
280FILE *NEW(freopen64)(const char *path, const char *mode, FILE *stream)
281{
282    FILE *ret; FREOPEN(freopen64); return ret;
283}
284#endif
285
286#if defined HAVE___FREOPEN64
287FILE *NEW(__freopen64)(const char *path, const char *mode, FILE *stream)
288{
289    FILE *ret; FREOPEN(__freopen64); return ret;
290}
291#endif
292
293/*
294 * fseek, fseeko etc.
295 */
296
297#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
298#   define FSEEK_FUZZ(myftell)
299#else
300#   define FSEEK_FUZZ(myftell) \
301        if(ret == 0) \
302        { \
303            /* FIXME: check what happens when fseek()ing a pipe */ \
304            switch(whence) \
305            { \
306                case SEEK_END: \
307                    offset = myftell(stream); \
308                    /* fall through */ \
309                case SEEK_SET: \
310                    _zz_setpos(fd, offset); \
311                    break; \
312                case SEEK_CUR: \
313                    _zz_addpos(fd, offset); \
314                    break; \
315            } \
316        }
317#endif
318
319#define FSEEK(myfseek, myftell) \
320    do \
321    { \
322        int fd; \
323        LOADSYM(myfseek); \
324        fd = fileno(stream); \
325        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
326            return ORIG(myfseek)(stream, offset, whence); \
327        DEBUG_STREAM("old", stream); \
328        _zz_lock(fd); \
329        ret = ORIG(myfseek)(stream, offset, whence); \
330        _zz_unlock(fd); \
331        debug("%s([%i], %lli, %i) = %i", __func__, \
332              fd, (long long int)offset, whence, ret); \
333        FSEEK_FUZZ(myftell) \
334        DEBUG_STREAM("new", stream); \
335    } while(0)
336
337int NEW(fseek)(FILE *stream, long offset, int whence)
338{
339    int ret; FSEEK(fseek, ftell); return ret;
340}
341
342#if defined HAVE_FSEEKO
343int NEW(fseeko)(FILE *stream, off_t offset, int whence)
344{
345    int ret; FSEEK(fseeko, ftello); return ret;
346}
347#endif
348
349#if defined HAVE_FSEEKO64
350int NEW(fseeko64)(FILE *stream, off64_t offset, int whence)
351{
352    int ret; FSEEK(fseeko64, ftello64); return ret;
353}
354#endif
355
356#if defined HAVE___FSEEKO64
357int NEW(__fseeko64)(FILE *stream, off64_t offset, int whence)
358{
359    int ret; FSEEK(__fseeko64, ftello); return ret;
360}
361#endif
362
363/*
364 * fsetpos64, __fsetpos64
365 */
366
367#define FSETPOS(myfsetpos) \
368    do \
369    { \
370        int fd; \
371        LOADSYM(myfsetpos); \
372        fd = fileno(stream); \
373        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
374            return ORIG(myfsetpos)(stream, pos); \
375        DEBUG_STREAM("old", stream); \
376        _zz_lock(fd); \
377        ret = ORIG(myfsetpos)(stream, pos); \
378        _zz_unlock(fd); \
379        debug("%s([%i], %lli) = %i", __func__, \
380              fd, (long long int)FPOS_CAST(*pos), ret); \
381        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
382        DEBUG_STREAM("new", stream); \
383    } \
384    while(0)
385
386#if defined HAVE_FSETPOS64
387int NEW(fsetpos64)(FILE *stream, const fpos64_t *pos)
388{
389    int ret; FSETPOS(fsetpos64); return ret;
390}
391#endif
392
393#if defined HAVE___FSETPOS64
394int NEW(__fsetpos64)(FILE *stream, const fpos64_t *pos)
395{
396    int ret; FSETPOS(__fsetpos64); return ret;
397}
398#endif
399
400/*
401 * rewind
402 */
403
404void NEW(rewind)(FILE *stream)
405{
406    int fd;
407
408    LOADSYM(rewind);
409    fd = fileno(stream);
410    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
411    {
412        ORIG(rewind)(stream);
413        return;
414    }
415
416    _zz_lock(fd);
417    ORIG(rewind)(stream);
418    _zz_unlock(fd);
419    debug("%s([%i])", __func__, fd);
420
421#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
422#else
423    /* FIXME: check what happens when rewind()ing a pipe */
424    _zz_setpos(fd, 0);
425#endif
426}
427
428/*
429 * fread, fread_unlocked
430 */
431
432/* Compute how many bytes from the stream were already fuzzed by __filbuf,
433 * __srget or __uflow, and store it in already_fuzzed. If these functions
434 * are not available, do nothing. */
435#if defined HAVE_BSD_STDIO
436#   define FREAD_PREFUZZ(fd, oldpos) \
437    do \
438    { \
439        int64_t tmp = _zz_getpos(fd); \
440        _zz_setpos(fd, oldpos); \
441        already_fuzzed = _zz_getfuzzed(fd); \
442        _zz_setpos(fd, tmp); \
443    } \
444    while(0)
445#else
446#   define FREAD_PREFUZZ(fd, oldpos) do {} while(0)
447#endif
448
449/* Fuzz the data returned by fread(). If a __fillbuf mechanism already
450 * fuzzed some of our data, we skip the relevant amount of bytes. If we
451 * have __srefill, we just do nothing because that function is the only
452 * one that actually fuzzes things. */
453#if defined HAVE_DARWIN_STDIO
454#   define FREAD_FUZZ(fd, oldpos) \
455    do \
456    { \
457        debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
458              (long int)size, (long int)nmemb, fd, (long int)ret); \
459    } while(0)
460#else
461#   define FREAD_FUZZ(fd, oldpos) \
462    do \
463    { \
464        int64_t newpos = ftell(stream); \
465        /* XXX: the number of bytes read is not ret * size, because \
466         * a partial read may have advanced the stream pointer. However, \
467         * when reading from a pipe ftell() will return 0, and ret * size \
468         * is then better than nothing. */ \
469        if(newpos <= 0) \
470        { \
471            oldpos = _zz_getpos(fd); \
472            newpos = oldpos + ret * size; \
473        } \
474        if(newpos != oldpos) \
475        { \
476            char *b = ptr; \
477            /* Skip bytes that were already fuzzed by __filbuf or __srget */ \
478            if(newpos > oldpos + already_fuzzed) \
479            { \
480                _zz_setpos(fd, oldpos + already_fuzzed); \
481                _zz_fuzz(fd, ptr, newpos - oldpos - already_fuzzed); \
482                /* FIXME: we need to fuzz the extra bytes that may have been \
483                 * read by the fread call we just made, or subsequent calls \
484                 * to getc_unlocked may miss them. */ \
485                _zz_setpos(fd, newpos); \
486                _zz_fuzz(fd, get_stream_ptr(stream), get_stream_cnt(stream)); \
487                _zz_setfuzzed(fd, get_stream_cnt(stream)); \
488                /* FIXME: *AND* we need to fuzz the buffer before the current \
489                 * position, in case fseek() causes us to rewind. */ \
490            } \
491            _zz_setpos(fd, newpos); \
492            if(newpos >= oldpos + 4) \
493                debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
494                      ptr, (long int)size, (long int)nmemb, fd, \
495                      (long int)ret, b[0], b[1], b[2], b[3]); \
496            else \
497                debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
498                      (long int)size, (long int)nmemb, fd, \
499                      (long int)ret, b[0]); \
500        } \
501        else \
502            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
503                  (long int)size, (long int)nmemb, fd, (long int)ret); \
504    } while(0)
505#endif
506
507#define FREAD(myfread) \
508    do \
509    { \
510        int64_t oldpos; \
511        int fd, already_fuzzed = 0; \
512        LOADSYM(myfread); \
513        fd = fileno(stream); \
514        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
515            return ORIG(myfread)(ptr, size, nmemb, stream); \
516        DEBUG_STREAM("old", stream); \
517        oldpos = ftell(stream); \
518        _zz_lock(fd); \
519        ret = ORIG(myfread)(ptr, size, nmemb, stream); \
520        _zz_unlock(fd); \
521        FREAD_PREFUZZ(fd, oldpos); \
522        FREAD_FUZZ(fd, oldpos); \
523        DEBUG_STREAM("new", stream); \
524    } while(0)
525
526size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
527{
528    size_t ret; FREAD(fread); return ret;
529}
530
531#if defined HAVE_FREAD_UNLOCKED
532#undef fread_unlocked /* can be a macro; we don’t want that */
533size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
534{
535    size_t ret; FREAD(fread_unlocked); return ret;
536}
537#endif
538
539/*
540 * getc, getchar, fgetc etc.
541 */
542
543#if defined HAVE_BSD_STDIO
544#   define FGETC_PREFUZZ already_fuzzed = _zz_getfuzzed(fd);
545#else
546#   define FGETC_PREFUZZ
547#endif
548
549#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
550#   define FGETC_FUZZ
551#else
552#   define FGETC_FUZZ \
553        if(ret != EOF) \
554        { \
555            uint8_t ch = ret; \
556            if(already_fuzzed <= 0) \
557               _zz_fuzz(fd, &ch, 1); \
558            _zz_addpos(fd, 1); \
559            ret = ch; \
560        }
561#endif
562
563#define FGETC(myfgetc, s, arg) \
564    do { \
565        int fd, already_fuzzed = 0; \
566        LOADSYM(myfgetc); \
567        fd = fileno(s); \
568        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
569            return ORIG(myfgetc)(arg); \
570        DEBUG_STREAM("old", s); \
571        _zz_lock(fd); \
572        ret = ORIG(myfgetc)(arg); \
573        _zz_unlock(fd); \
574        FGETC_PREFUZZ \
575        FGETC_FUZZ \
576        if(ret == EOF) \
577            debug("%s([%i]) = EOF", __func__, fd); \
578        else \
579            debug("%s([%i]) = '%c'", __func__, fd, ret); \
580        DEBUG_STREAM("new", s); \
581    } while(0)
582
583#undef getc /* can be a macro; we don’t want that */
584int NEW(getc)(FILE *stream)
585{
586    int ret; FGETC(getc, stream, stream); return ret;
587}
588
589#undef getchar /* can be a macro; we don’t want that */
590int NEW(getchar)(void)
591{
592    int ret; FGETC(getchar, stdin, /* empty */); return ret;
593}
594
595int NEW(fgetc)(FILE *stream)
596{
597    int ret; FGETC(fgetc, stream, stream); return ret;
598}
599
600#if defined HAVE__IO_GETC
601int NEW(_IO_getc)(FILE *stream)
602{
603    int ret; FGETC(_IO_getc, stream, stream); return ret;
604}
605#endif
606
607#if defined HAVE_GETC_UNLOCKED
608#undef getc_unlocked /* can be a macro; we don’t want that */
609int NEW(getc_unlocked)(FILE *stream)
610{
611    int ret; FGETC(getc_unlocked, stream, stream); return ret;
612}
613#endif
614
615#if defined HAVE_GETCHAR_UNLOCKED
616#undef getchar_unlocked /* can be a macro; we don’t want that */
617int NEW(getchar_unlocked)(void)
618{
619    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
620}
621#endif
622
623#if defined HAVE_FGETC_UNLOCKED
624#undef fgetc_unlocked /* can be a macro; we don’t want that */
625int NEW(fgetc_unlocked)(FILE *stream)
626{
627    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
628}
629#endif
630
631/*
632 * fgets, fgets_unlocked
633 */
634
635#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
636#   define FGETS_FUZZ(myfgets, myfgetc) \
637        _zz_lock(fd); \
638        ret = ORIG(myfgets)(s, size, stream); \
639        _zz_unlock(fd);
640#else
641#   define FGETS_FUZZ(myfgets, myfgetc) \
642        if(size <= 0) \
643            ret = NULL; \
644        else if(size == 1) \
645            s[0] = '\0'; \
646        else \
647        { \
648            int i; \
649            for(i = 0; i < size - 1; i++) \
650            { \
651                int ch; \
652                _zz_lock(fd); \
653                ch = ORIG(myfgetc)(stream); \
654                _zz_unlock(fd); \
655                if(ch == EOF) \
656                { \
657                    s[i] = '\0'; \
658                    if(!i) \
659                        ret = NULL; \
660                    break; \
661                } \
662                s[i] = (char)(unsigned char)ch; \
663                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
664                _zz_addpos(fd, 1); \
665                if(s[i] == '\n') \
666                { \
667                    s[i + 1] = '\0'; \
668                    break; \
669                } \
670            } \
671        }
672#endif
673
674#define FGETS(myfgets, myfgetc) \
675    do \
676    { \
677        int fd; \
678        ret = s; \
679        LOADSYM(myfgets); \
680        LOADSYM(myfgetc); \
681        fd = fileno(stream); \
682        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
683            return ORIG(myfgets)(s, size, stream); \
684        DEBUG_STREAM("old", s); \
685        FGETS_FUZZ(myfgets, myfgetc) \
686        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
687        DEBUG_STREAM("new", s); \
688    } while(0)
689
690char *NEW(fgets)(char *s, int size, FILE *stream)
691{
692    char *ret; FGETS(fgets, fgetc); return ret;
693}
694
695#if defined HAVE_FGETS_UNLOCKED
696char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
697{
698    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
699}
700#endif
701
702/*
703 * ungetc
704 */
705
706int NEW(ungetc)(int c, FILE *stream)
707{
708    int ret, fd;
709
710    LOADSYM(ungetc);
711    fd = fileno(stream);
712    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
713        return ORIG(ungetc)(c, stream);
714
715    DEBUG_STREAM("old", stream);
716    _zz_lock(fd);
717    ret = ORIG(ungetc)(c, stream);
718    _zz_unlock(fd);
719
720    if(ret != EOF)
721    {
722        struct fuzz *fuzz = _zz_getfuzz(fd);
723        fuzz->uflag = 1;
724        fuzz->upos = _zz_getpos(fd) - 1;
725        fuzz->uchar = c;
726#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
727#else
728        _zz_addpos(fd, -1);
729#endif
730    }
731
732    if(ret == EOF)
733        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
734    else
735        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
736    DEBUG_STREAM("new", stream);
737    return ret;
738}
739
740/*
741 * fclose
742 */
743
744int NEW(fclose)(FILE *fp)
745{
746    int ret, fd;
747
748    LOADSYM(fclose);
749    fd = fileno(fp);
750    if(!_zz_ready || !_zz_iswatched(fd))
751        return ORIG(fclose)(fp);
752
753    DEBUG_STREAM("old", fp);
754    _zz_lock(fd);
755    ret = ORIG(fclose)(fp);
756    _zz_unlock(fd);
757    debug("%s([%i]) = %i", __func__, fd, ret);
758    _zz_unregister(fd);
759
760    return ret;
761}
762
763/*
764 * getline, getdelim etc.
765 */
766
767#define GETDELIM(mygetdelim, delim, need_delim) \
768    do { \
769        char *line; \
770        ssize_t done, size; \
771        int fd, already_fuzzed = 0, finished = 0; \
772        LOADSYM(mygetdelim); \
773        LOADSYM(getdelim); \
774        LOADSYM(fgetc); \
775        fd = fileno(stream); \
776        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
777        { \
778            ret = ORIG(getdelim)(lineptr, n, delim, stream); \
779            break; \
780        } \
781        DEBUG_STREAM("old", stream); \
782        line = *lineptr; \
783        size = line ? *n : 0; \
784        ret = done = finished = 0; \
785        for(;;) \
786        { \
787            int ch; \
788            if(done >= size) /* highly inefficient but I don't care */ \
789                line = realloc(line, size = done + 1); \
790            if(finished) \
791            { \
792                line[done] = '\0'; \
793                *n = size; \
794                *lineptr = line; \
795                break; \
796            } \
797            _zz_lock(fd); \
798            ch = ORIG(fgetc)(stream); \
799            _zz_unlock(fd); \
800            if(ch == EOF) \
801            { \
802                finished = 1; \
803                ret = done; \
804            } \
805            else \
806            { \
807                unsigned char c = ch; \
808                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
809                line[done++] = c; \
810                _zz_addpos(fd, 1); \
811                if(c == delim) \
812                { \
813                    finished = 1; \
814                    ret = done; \
815                } \
816            } \
817        } \
818        if(need_delim) \
819            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
820                  lineptr, n, delim, fd, (long int)ret); \
821        else \
822            debug("%s(%p, %p, [%i]) = %li", __func__, \
823                  lineptr, n, fd, (long int)ret); \
824        DEBUG_STREAM("new", stream); \
825        break; \
826    } while(0)
827
828#if defined HAVE_GETLINE
829ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
830{
831    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
832}
833#endif
834
835#if defined HAVE_GETDELIM
836ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
837{
838    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
839}
840#endif
841
842#if defined HAVE___GETDELIM
843ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
844{
845    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
846}
847#endif
848
849/*
850 * fgetln
851 */
852
853#if defined HAVE_FGETLN
854char *NEW(fgetln)(FILE *stream, size_t *len)
855{
856    char *ret;
857#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
858#else
859    struct fuzz *fuzz;
860    size_t i, size;
861#endif
862    int fd;
863
864    LOADSYM(fgetln);
865    LOADSYM(fgetc);
866    fd = fileno(stream);
867    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
868        return ORIG(fgetln)(stream, len);
869
870    DEBUG_STREAM("old", stream);
871#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
872    _zz_lock(fd);
873    ret = ORIG(fgetln)(stream, len);
874    _zz_unlock(fd);
875#else
876    fuzz = _zz_getfuzz(fd);
877
878    for(i = size = 0; ; /* i is incremented below */)
879    {
880        int ch;
881
882        _zz_lock(fd);
883        ch = ORIG(fgetc)(stream);
884        _zz_unlock(fd);
885
886        if(ch == EOF)
887            break;
888
889        if(i >= size)
890            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
891
892        fuzz->tmp[i] = (char)(unsigned char)ch;
893        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
894        _zz_addpos(fd, 1);
895
896        if(fuzz->tmp[i++] == '\n')
897            break;
898    }
899
900    *len = i;
901    ret = fuzz->tmp;
902#endif
903
904    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
905    DEBUG_STREAM("new", stream);
906    return ret;
907}
908#endif
909
910/*
911 * __srefill, __filbuf, __srget, __uflow
912 */
913
914#if defined HAVE___UFLOW
915#   define REFILL_RETURNS_INT 0
916#else
917#   define REFILL_RETURNS_INT 1
918#endif
919
920#define REFILL(myrefill, fn_advances) \
921    do \
922    { \
923        int64_t pos; \
924        off_t newpos; \
925        int fd; \
926        LOADSYM(myrefill); \
927        fd = fileno(fp); \
928        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
929            return ORIG(myrefill)(fp); \
930        DEBUG_STREAM("old", fp); \
931        pos = _zz_getpos(fd); \
932        _zz_lock(fd); \
933        ret = ORIG(myrefill)(fp); \
934        newpos = lseek(fd, 0, SEEK_CUR); \
935        _zz_unlock(fd); \
936        if(ret != EOF) \
937        { \
938            int already_fuzzed = 0; \
939            if(fn_advances) \
940            { \
941                uint8_t ch = (uint8_t)(unsigned int)ret; \
942                if(newpos != -1) \
943                    _zz_setpos(fd, newpos - get_stream_cnt(fp) - 1); \
944                already_fuzzed = _zz_getfuzzed(fd); \
945                _zz_fuzz(fd, &ch, 1); \
946                ret = get_stream_ptr(fp)[-1] = ch; \
947                _zz_setfuzzed(fd, get_stream_cnt(fp) + 1); \
948                _zz_addpos(fd, 1); \
949            } \
950            else \
951            { \
952                _zz_setfuzzed(fd, get_stream_cnt(fp)); \
953                if(newpos != -1) \
954                    _zz_setpos(fd, newpos - get_stream_cnt(fp)); \
955            } \
956            if(get_stream_cnt(fp) > already_fuzzed) \
957            { \
958                _zz_addpos(fd, already_fuzzed); \
959                _zz_fuzz(fd, get_stream_ptr(fp), \
960                             get_stream_cnt(fp) - already_fuzzed); \
961            } \
962            _zz_addpos(fd, get_stream_cnt(fp) - already_fuzzed); \
963        } \
964        _zz_setpos(fd, pos); /* FIXME: do we always need to do this? */ \
965        if (REFILL_RETURNS_INT) \
966            debug("%s([%i]) = %i", __func__, fd, ret); \
967        else if (ret == EOF) \
968            debug("%s([%i]) = EOF", __func__, fd, ret); \
969        else \
970            debug("%s([%i]) = '%c'", __func__, fd, ret); \
971        DEBUG_STREAM("new", fp); \
972    } \
973    while(0)
974
975#if defined HAVE___SREFILL
976int NEW(__srefill)(FILE *fp)
977{
978    int ret; REFILL(__srefill, 0); return ret;
979}
980#endif
981
982#if defined HAVE___SRGET && !defined HAVE___SREFILL
983int NEW(__srget)(FILE *fp)
984{
985    int ret; REFILL(__srget, 1); return ret;
986}
987#endif
988
989#if defined HAVE___FILBUF
990int NEW(__filbuf)(FILE *fp)
991{
992    int ret; REFILL(__filbuf, 1); return ret;
993}
994#endif
995
996#if defined HAVE___UFLOW
997int NEW(__uflow)(FILE *fp)
998{
999    int ret; REFILL(__uflow, 1); return ret;
1000}
1001#endif
1002
Note: See TracBrowser for help on using the repository browser.