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

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

Reorganise source code to better separate zzuf and libzzuf. Note: the Win32
build is now broken.

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