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

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

Reset offset position before most stdio call.

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