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

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

Fix DEBUG_STREAM compilation on Win32.

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