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

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

Use fseeko64() everywhere when possible, instead of potential 32-bit versions.

  • Property svn:keywords set to Id
File size: 26.7 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 4041 2009-11-26 01:13:58Z 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_lock(fd); \
530        ret = ORIG(myfread)(ptr, size, nmemb, stream); \
531        _zz_unlock(fd); \
532        FREAD_PREFUZZ(fd, oldpos); \
533        FREAD_FUZZ(fd, oldpos); \
534        DEBUG_STREAM("new", stream); \
535    } while(0)
536
537size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
538{
539    size_t ret; FREAD(fread); return ret;
540}
541
542#if defined HAVE_FREAD_UNLOCKED
543#undef fread_unlocked /* can be a macro; we don’t want that */
544size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
545{
546    size_t ret; FREAD(fread_unlocked); return ret;
547}
548#endif
549
550/*
551 * getc, getchar, fgetc etc.
552 */
553
554#if defined HAVE_BSD_STDIO
555#   define FGETC_PREFUZZ already_fuzzed = _zz_getfuzzed(fd);
556#else
557#   define FGETC_PREFUZZ
558#endif
559
560#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
561#   define FGETC_FUZZ
562#else
563#   define FGETC_FUZZ \
564        if(ret != EOF) \
565        { \
566            uint8_t ch = ret; \
567            if(already_fuzzed <= 0) \
568               _zz_fuzz(fd, &ch, 1); \
569            _zz_addpos(fd, 1); \
570            ret = ch; \
571        }
572#endif
573
574#define FGETC(myfgetc, s, arg) \
575    do { \
576        int fd, already_fuzzed = 0; \
577        LOADSYM(myfgetc); \
578        fd = fileno(s); \
579        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
580            return ORIG(myfgetc)(arg); \
581        DEBUG_STREAM("old", s); \
582        _zz_lock(fd); \
583        ret = ORIG(myfgetc)(arg); \
584        _zz_unlock(fd); \
585        FGETC_PREFUZZ \
586        FGETC_FUZZ \
587        if(ret == EOF) \
588            debug("%s([%i]) = EOF", __func__, fd); \
589        else \
590            debug("%s([%i]) = '%c'", __func__, fd, ret); \
591        DEBUG_STREAM("new", s); \
592    } while(0)
593
594#undef getc /* can be a macro; we don’t want that */
595int NEW(getc)(FILE *stream)
596{
597    int ret; FGETC(getc, stream, stream); return ret;
598}
599
600#undef getchar /* can be a macro; we don’t want that */
601int NEW(getchar)(void)
602{
603    int ret; FGETC(getchar, stdin, /* empty */); return ret;
604}
605
606int NEW(fgetc)(FILE *stream)
607{
608    int ret; FGETC(fgetc, stream, stream); return ret;
609}
610
611#if defined HAVE__IO_GETC
612int NEW(_IO_getc)(FILE *stream)
613{
614    int ret; FGETC(_IO_getc, stream, stream); return ret;
615}
616#endif
617
618#if defined HAVE_GETC_UNLOCKED
619#undef getc_unlocked /* can be a macro; we don’t want that */
620int NEW(getc_unlocked)(FILE *stream)
621{
622    int ret; FGETC(getc_unlocked, stream, stream); return ret;
623}
624#endif
625
626#if defined HAVE_GETCHAR_UNLOCKED
627#undef getchar_unlocked /* can be a macro; we don’t want that */
628int NEW(getchar_unlocked)(void)
629{
630    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
631}
632#endif
633
634#if defined HAVE_FGETC_UNLOCKED
635#undef fgetc_unlocked /* can be a macro; we don’t want that */
636int NEW(fgetc_unlocked)(FILE *stream)
637{
638    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
639}
640#endif
641
642/*
643 * fgets, fgets_unlocked
644 */
645
646#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
647#   define FGETS_FUZZ(myfgets, myfgetc) \
648        _zz_lock(fd); \
649        ret = ORIG(myfgets)(s, size, stream); \
650        _zz_unlock(fd);
651#else
652#   define FGETS_FUZZ(myfgets, myfgetc) \
653        if(size <= 0) \
654            ret = NULL; \
655        else if(size == 1) \
656            s[0] = '\0'; \
657        else \
658        { \
659            int i; \
660            for(i = 0; i < size - 1; i++) \
661            { \
662                int ch; \
663                _zz_lock(fd); \
664                ch = ORIG(myfgetc)(stream); \
665                _zz_unlock(fd); \
666                if(ch == EOF) \
667                { \
668                    s[i] = '\0'; \
669                    if(!i) \
670                        ret = NULL; \
671                    break; \
672                } \
673                s[i] = (char)(unsigned char)ch; \
674                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
675                _zz_addpos(fd, 1); \
676                if(s[i] == '\n') \
677                { \
678                    s[i + 1] = '\0'; \
679                    break; \
680                } \
681            } \
682        }
683#endif
684
685#define FGETS(myfgets, myfgetc) \
686    do \
687    { \
688        int fd; \
689        ret = s; \
690        LOADSYM(myfgets); \
691        LOADSYM(myfgetc); \
692        fd = fileno(stream); \
693        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
694            return ORIG(myfgets)(s, size, stream); \
695        DEBUG_STREAM("old", s); \
696        FGETS_FUZZ(myfgets, myfgetc) \
697        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
698        DEBUG_STREAM("new", s); \
699    } while(0)
700
701char *NEW(fgets)(char *s, int size, FILE *stream)
702{
703    char *ret; FGETS(fgets, fgetc); return ret;
704}
705
706#if defined HAVE_FGETS_UNLOCKED
707char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
708{
709    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
710}
711#endif
712
713/*
714 * ungetc
715 */
716
717int NEW(ungetc)(int c, FILE *stream)
718{
719    int ret, fd;
720
721    LOADSYM(ungetc);
722    fd = fileno(stream);
723    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
724        return ORIG(ungetc)(c, stream);
725
726    DEBUG_STREAM("old", stream);
727    _zz_lock(fd);
728    ret = ORIG(ungetc)(c, stream);
729    _zz_unlock(fd);
730
731    if(ret != EOF)
732    {
733        struct fuzz *fuzz = _zz_getfuzz(fd);
734        fuzz->uflag = 1;
735        fuzz->upos = _zz_getpos(fd) - 1;
736        fuzz->uchar = c;
737#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
738#else
739        _zz_addpos(fd, -1);
740#endif
741    }
742
743    if(ret == EOF)
744        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
745    else
746        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
747    DEBUG_STREAM("new", stream);
748    return ret;
749}
750
751/*
752 * fclose
753 */
754
755int NEW(fclose)(FILE *fp)
756{
757    int ret, fd;
758
759    LOADSYM(fclose);
760    fd = fileno(fp);
761    if(!_zz_ready || !_zz_iswatched(fd))
762        return ORIG(fclose)(fp);
763
764    DEBUG_STREAM("old", fp);
765    _zz_lock(fd);
766    ret = ORIG(fclose)(fp);
767    _zz_unlock(fd);
768    debug("%s([%i]) = %i", __func__, fd, ret);
769    _zz_unregister(fd);
770
771    return ret;
772}
773
774/*
775 * getline, getdelim etc.
776 */
777
778#define GETDELIM(mygetdelim, delim, need_delim) \
779    do { \
780        char *line; \
781        ssize_t done, size; \
782        int fd, already_fuzzed = 0, finished = 0; \
783        LOADSYM(mygetdelim); \
784        LOADSYM(getdelim); \
785        LOADSYM(fgetc); \
786        fd = fileno(stream); \
787        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
788        { \
789            ret = ORIG(getdelim)(lineptr, n, delim, stream); \
790            break; \
791        } \
792        DEBUG_STREAM("old", stream); \
793        line = *lineptr; \
794        size = line ? *n : 0; \
795        ret = done = finished = 0; \
796        for(;;) \
797        { \
798            int ch; \
799            if(done >= size) /* highly inefficient but I don't care */ \
800                line = realloc(line, size = done + 1); \
801            if(finished) \
802            { \
803                line[done] = '\0'; \
804                *n = size; \
805                *lineptr = line; \
806                break; \
807            } \
808            _zz_lock(fd); \
809            ch = ORIG(fgetc)(stream); \
810            _zz_unlock(fd); \
811            if(ch == EOF) \
812            { \
813                finished = 1; \
814                ret = done; \
815            } \
816            else \
817            { \
818                unsigned char c = ch; \
819                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
820                line[done++] = c; \
821                _zz_addpos(fd, 1); \
822                if(c == delim) \
823                { \
824                    finished = 1; \
825                    ret = done; \
826                } \
827            } \
828        } \
829        if(need_delim) \
830            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
831                  lineptr, n, delim, fd, (long int)ret); \
832        else \
833            debug("%s(%p, %p, [%i]) = %li", __func__, \
834                  lineptr, n, fd, (long int)ret); \
835        DEBUG_STREAM("new", stream); \
836        break; \
837    } while(0)
838
839#if defined HAVE_GETLINE
840ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
841{
842    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
843}
844#endif
845
846#if defined HAVE_GETDELIM
847ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
848{
849    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
850}
851#endif
852
853#if defined HAVE___GETDELIM
854ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
855{
856    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
857}
858#endif
859
860/*
861 * fgetln
862 */
863
864#if defined HAVE_FGETLN
865char *NEW(fgetln)(FILE *stream, size_t *len)
866{
867    char *ret;
868#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
869#else
870    struct fuzz *fuzz;
871    size_t i, size;
872#endif
873    int fd;
874
875    LOADSYM(fgetln);
876    LOADSYM(fgetc);
877    fd = fileno(stream);
878    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
879        return ORIG(fgetln)(stream, len);
880
881    DEBUG_STREAM("old", stream);
882#if defined HAVE_DARWIN_STDIO /* Don't fuzz or seek if we have __srefill() */
883    _zz_lock(fd);
884    ret = ORIG(fgetln)(stream, len);
885    _zz_unlock(fd);
886#else
887    fuzz = _zz_getfuzz(fd);
888
889    for(i = size = 0; ; /* i is incremented below */)
890    {
891        int ch;
892
893        _zz_lock(fd);
894        ch = ORIG(fgetc)(stream);
895        _zz_unlock(fd);
896
897        if(ch == EOF)
898            break;
899
900        if(i >= size)
901            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
902
903        fuzz->tmp[i] = (char)(unsigned char)ch;
904        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
905        _zz_addpos(fd, 1);
906
907        if(fuzz->tmp[i++] == '\n')
908            break;
909    }
910
911    *len = i;
912    ret = fuzz->tmp;
913#endif
914
915    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
916    DEBUG_STREAM("new", stream);
917    return ret;
918}
919#endif
920
921/*
922 * __srefill, __filbuf, __srget, __uflow
923 */
924
925#if defined HAVE___UFLOW
926#   define REFILL_RETURNS_INT 0
927#else
928#   define REFILL_RETURNS_INT 1
929#endif
930
931#define REFILL(myrefill, fn_advances) \
932    do \
933    { \
934        int64_t pos; \
935        off_t newpos; \
936        int fd; \
937        LOADSYM(myrefill); \
938        fd = fileno(fp); \
939        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
940            return ORIG(myrefill)(fp); \
941        DEBUG_STREAM("old", fp); \
942        pos = _zz_getpos(fd); \
943        _zz_lock(fd); \
944        ret = ORIG(myrefill)(fp); \
945        newpos = lseek(fd, 0, SEEK_CUR); \
946        _zz_unlock(fd); \
947        if(ret != EOF) \
948        { \
949            int already_fuzzed = 0; \
950            if(fn_advances) \
951            { \
952                uint8_t ch = (uint8_t)(unsigned int)ret; \
953                if(newpos != -1) \
954                    _zz_setpos(fd, newpos - get_stream_cnt(fp) - 1); \
955                already_fuzzed = _zz_getfuzzed(fd); \
956                _zz_fuzz(fd, &ch, 1); \
957                ret = get_stream_ptr(fp)[-1] = ch; \
958                _zz_setfuzzed(fd, get_stream_cnt(fp) + 1); \
959                _zz_addpos(fd, 1); \
960            } \
961            else \
962            { \
963                _zz_setfuzzed(fd, get_stream_cnt(fp)); \
964                if(newpos != -1) \
965                    _zz_setpos(fd, newpos - get_stream_cnt(fp)); \
966            } \
967            if(get_stream_cnt(fp) > already_fuzzed) \
968            { \
969                _zz_addpos(fd, already_fuzzed); \
970                _zz_fuzz(fd, get_stream_ptr(fp), \
971                             get_stream_cnt(fp) - already_fuzzed); \
972            } \
973            _zz_addpos(fd, get_stream_cnt(fp) - already_fuzzed); \
974        } \
975        _zz_setpos(fd, pos); /* FIXME: do we always need to do this? */ \
976        if (REFILL_RETURNS_INT) \
977            debug("%s([%i]) = %i", __func__, fd, ret); \
978        else if (ret == EOF) \
979            debug("%s([%i]) = EOF", __func__, fd, ret); \
980        else \
981            debug("%s([%i]) = '%c'", __func__, fd, ret); \
982        DEBUG_STREAM("new", fp); \
983    } \
984    while(0)
985
986#if defined HAVE___SREFILL
987int NEW(__srefill)(FILE *fp)
988{
989    int ret; REFILL(__srefill, 0); return ret;
990}
991#endif
992
993#if defined HAVE___SRGET && !defined HAVE___SREFILL
994int NEW(__srget)(FILE *fp)
995{
996    int ret; REFILL(__srget, 1); return ret;
997}
998#endif
999
1000#if defined HAVE___FILBUF
1001int NEW(__filbuf)(FILE *fp)
1002{
1003    int ret; REFILL(__filbuf, 1); return ret;
1004}
1005#endif
1006
1007#if defined HAVE___UFLOW
1008int NEW(__uflow)(FILE *fp)
1009{
1010    int ret; REFILL(__uflow, 1); return ret;
1011}
1012#endif
1013
Note: See TracBrowser for help on using the repository browser.