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

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

Minor Win32 compilation fix.

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