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

Last change on this file since 2584 was 2584, checked in by Sam Hocevar, 12 years ago
  • Hack around to get HP-UX tools to work. It still fails the most nasty zzcat test, though. But a more massive redesign is probably necessary.
  • Property svn:keywords set to Id
File size: 22.7 KB
RevLine 
[1466]1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: lib-stream.c 2584 2008-07-23 23:40:13Z 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/*
[1494]16 *  load-stream.c: loaded stream functions
[1466]17 */
18
19#include "config.h"
[1478]20
[2542]21/* Needed for getline() and getdelim() */
22#define _GNU_SOURCE
[2557]23/* Needed for getc_unlocked() on OpenSolaris */
24#define __EXTENSIONS__
[1466]25
[2566]26/* Define if stdio operations use *only* the refill mechanism */
27#if defined HAVE___SREFILL
28#   define REFILL_ONLY_STDIO
[2542]29#endif
30
[1466]31#if defined HAVE_STDINT_H
32#   include <stdint.h>
33#elif defined HAVE_INTTYPES_H
34#   include <inttypes.h>
35#endif
36#include <stdlib.h>
37
[1494]38#include <stdio.h>
[1594]39#include <sys/types.h>
[2566]40#if defined HAVE_UNISTD_H
[1611]41#   include <unistd.h> /* Needed for __srefill’s lseek() call */
42#endif
[1494]43
[1470]44#include "libzzuf.h"
[1683]45#include "lib-load.h"
[1470]46#include "debug.h"
47#include "fuzz.h"
[1613]48#include "fd.h"
[1470]49
[1695]50#if defined HAVE___SREFILL
[1699]51int NEW(__srefill)(FILE *fp);
[1602]52#endif
53
[2533]54#if defined HAVE___FILBUF
55int NEW(__filbuf)(FILE *fp);
56#endif
57
[2572]58#if defined HAVE___SRGET && !defined HAVE___SREFILL
[2569]59int NEW(__srget)(FILE *fp);
60#endif
61
[1470]62/* Library functions that we divert */
[1699]63static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
[1695]64#if defined HAVE_FOPEN64
[1699]65static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
[1543]66#endif
[2528]67#if defined HAVE___FOPEN64
68static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
69#endif
[1699]70static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
71                                  FILE *stream);
[2552]72#if defined HAVE_FREOPEN64
73static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
74                                  FILE *stream);
75#endif
[2528]76#if defined HAVE___FREOPEN64
77static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
78                                     FILE *stream);
79#endif
[1699]80static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
[1695]81#if defined HAVE_FSEEKO
[1699]82static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
[1594]83#endif
[2552]84#if defined HAVE_FSEEKO64
85static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
86#endif
[2528]87#if defined HAVE___FSEEKO64
88static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
89#endif
[2552]90#if defined HAVE_FSETPOS64
91static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
92#endif
[2533]93#if defined HAVE___FSETPOS64
94static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
95#endif
[1699]96static void    (*ORIG(rewind))   (FILE *stream);
97static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
98                                  FILE *stream);
[2331]99#if defined HAVE_FREAD_UNLOCKED
100static size_t  (*ORIG(fread_unlocked))  (void *ptr, size_t size, size_t nmemb,
101                                         FILE *stream);
102#endif
[1699]103static int     (*ORIG(getc))     (FILE *stream);
[2334]104static int     (*ORIG(getchar))  (void);
[1699]105static int     (*ORIG(fgetc))    (FILE *stream);
[1695]106#if defined HAVE__IO_GETC
[1699]107static int     (*ORIG(_IO_getc)) (FILE *stream);
[1600]108#endif
[2330]109#if defined HAVE_GETC_UNLOCKED
[2334]110static int     (*ORIG(getc_unlocked))    (FILE *stream);
[2330]111#endif
[2334]112#if defined HAVE_GETCHAR_UNLOCKED
113static int     (*ORIG(getchar_unlocked)) (void);
114#endif
[2330]115#if defined HAVE_FGETC_UNLOCKED
[2334]116static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
[2330]117#endif
[1699]118static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
[2331]119#if defined HAVE_FGETS_UNLOCKED
[2334]120static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
[2331]121#endif
[1699]122static int     (*ORIG(ungetc))   (int c, FILE *stream);
123static int     (*ORIG(fclose))   (FILE *fp);
[1478]124
[1497]125/* Additional GNUisms */
[1695]126#if defined HAVE_GETLINE
[1699]127static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
[1543]128#endif
[1695]129#if defined HAVE_GETDELIM
[1699]130static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
131                                    FILE *stream);
[1543]132#endif
[1695]133#if defined HAVE___GETDELIM
[1699]134static ssize_t (*ORIG(__getdelim)) (char **lineptr, size_t *n, int delim,
135                                    FILE *stream);
[1543]136#endif
[1497]137
[1566]138/* Additional BSDisms */
[1695]139#if defined HAVE_FGETLN
[1699]140static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
[1566]141#endif
[1695]142#if defined HAVE___SREFILL
[1699]143int            (*ORIG(__srefill)) (FILE *fp);
[1598]144#endif
[2572]145#if defined HAVE___SRGET && !defined HAVE___SREFILL
[2569]146int            (*ORIG(__srget))   (FILE *fp);
147#endif
[1566]148
[2533]149/* Additional HP-UXisms */
150#if defined HAVE___FILBUF
151int            (*ORIG(__filbuf))  (FILE *fp);
152#endif
153
[1466]154/* Our function wrappers */
[2566]155#if defined REFILL_ONLY_STDIO /* Fuzz fp if we have __srefill() */
[2533]156#   define FOPEN_FUZZ() \
[2554]157    _zz_fuzz(fd, ret->FILE_PTR, ret->FILE_CNT)
[2533]158#else
159#   define FOPEN_FUZZ()
160#endif
161
[1482]162#define FOPEN(fn) \
[1471]163    do \
164    { \
[1648]165        LOADSYM(fn); \
[1523]166        if(!_zz_ready) \
[1497]167            return ORIG(fn)(path, mode); \
[1694]168        _zz_lock(-1); \
[1471]169        ret = ORIG(fn)(path, mode); \
[1694]170        _zz_unlock(-1); \
[1527]171        if(ret && _zz_mustwatch(path)) \
[1471]172        { \
[1527]173            int fd = fileno(ret); \
174            _zz_register(fd); \
[1687]175            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
[2533]176            FOPEN_FUZZ(); \
[1471]177        } \
178    } while(0)
179
[1699]180FILE *NEW(fopen)(const char *path, const char *mode)
[1466]181{
[1482]182    FILE *ret; FOPEN(fopen); return ret;
[1471]183}
[1470]184
[1695]185#if defined HAVE_FOPEN64
[1699]186FILE *NEW(fopen64)(const char *path, const char *mode)
[1471]187{
[1482]188    FILE *ret; FOPEN(fopen64); return ret;
[1466]189}
[1543]190#endif
[1466]191
[2528]192#if defined HAVE___FOPEN64
193FILE *NEW(__fopen64)(const char *path, const char *mode)
[1619]194{
[2528]195    FILE *ret; FOPEN(__fopen64); return ret;
196}
197#endif
[1619]198
[2528]199#define FREOPEN(fn) \
200    do \
201    { \
202        int fd0 = -1, fd1 = -1, disp = 0; \
203        LOADSYM(fn); \
204        if(_zz_ready && (fd0 = fileno(stream)) >= 0 && _zz_iswatched(fd0)) \
205        { \
206            _zz_unregister(fd0); \
207            disp = 1; \
208        } \
209        _zz_lock(-1); \
210        ret = ORIG(fn)(path, mode, stream); \
211        _zz_unlock(-1); \
212        if(ret && _zz_mustwatch(path)) \
213        { \
214            fd1 = fileno(ret); \
215            _zz_register(fd1); \
216            disp = 1; \
217        } \
218        if(disp) \
219            debug("%s(\"%s\", \"%s\", [%i]) = [%i]", __func__, \
220                  path, mode, fd0, fd1); \
221    } while(0)
[1619]222
[2528]223FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
224{
225    FILE *ret; FREOPEN(freopen); return ret;
226}
[1619]227
[2552]228#if defined HAVE_FREOPEN64
229FILE *NEW(freopen64)(const char *path, const char *mode, FILE *stream)
230{
231    FILE *ret; FREOPEN(freopen64); return ret;
232}
233#endif
234
[2528]235#if defined HAVE___FREOPEN64
236FILE *NEW(__freopen64)(const char *path, const char *mode, FILE *stream)
237{
238    FILE *ret; FREOPEN(__freopen64); return ret;
[1619]239}
[2528]240#endif
[1619]241
[2566]242#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1606]243#   define FSEEK_FUZZ(fn2)
244#else
245#   define FSEEK_FUZZ(fn2) \
[1594]246        if(ret == 0) \
247        { \
248            /* FIXME: check what happens when fseek()ing a pipe */ \
249            switch(whence) \
250            { \
251                case SEEK_END: \
252                    offset = fn2(stream); \
253                    /* fall through */ \
254                case SEEK_SET: \
255                    _zz_setpos(fd, offset); \
256                    break; \
257                case SEEK_CUR: \
258                    _zz_addpos(fd, offset); \
259                    break; \
260            } \
[1606]261        }
262#endif
263
264#define FSEEK(fn, fn2) \
265    do \
266    { \
267        int fd; \
[1648]268        LOADSYM(fn); \
[1606]269        fd = fileno(stream); \
[1791]270        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
[1606]271            return ORIG(fn)(stream, offset, whence); \
[1694]272        _zz_lock(fd); \
[1606]273        ret = ORIG(fn)(stream, offset, whence); \
[1694]274        _zz_unlock(fd); \
[1687]275        debug("%s([%i], %lli, %i) = %i", __func__, \
[1606]276              fd, (long long int)offset, whence, ret); \
277        FSEEK_FUZZ(fn2) \
[1594]278    } while(0)
279
[1699]280int NEW(fseek)(FILE *stream, long offset, int whence)
[1476]281{
[1594]282    int ret; FSEEK(fseek, ftell); return ret;
283}
[1476]284
[1695]285#if defined HAVE_FSEEKO
[1699]286int NEW(fseeko)(FILE *stream, off_t offset, int whence)
[1594]287{
288    int ret; FSEEK(fseeko, ftello); return ret;
[1476]289}
[1594]290#endif
[1476]291
[2552]292#if defined HAVE_FSEEKO64
293int NEW(fseeko64)(FILE *stream, off64_t offset, int whence)
294{
295    int ret; FSEEK(fseeko64, ftello); return ret;
296}
297#endif
298
[2528]299#if defined HAVE___FSEEKO64
300int NEW(__fseeko64)(FILE *stream, off64_t offset, int whence)
301{
302    int ret; FSEEK(__fseeko64, ftello); return ret;
303}
304#endif
305
[2552]306#define FSETPOS(fn) \
307    do \
308    { \
309        int fd; \
310        LOADSYM(fn); \
311        fd = fileno(stream); \
312        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
313            return ORIG(fn)(stream, pos); \
314        _zz_lock(fd); \
315        ret = ORIG(fn)(stream, pos); \
316        _zz_unlock(fd); \
317        debug("%s([%i], %lli) = %i", __func__, \
[2559]318              fd, (long long int)FPOS_CAST(*pos), ret); \
319        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
[2552]320    } \
321    while(0)
322
323#if defined HAVE_FSETPOS64
324int NEW(fsetpos64)(FILE *stream, const fpos64_t *pos)
325{
326    int ret; FSETPOS(fsetpos64); return ret;
327}
328#endif
329
[2533]330#if defined HAVE___FSETPOS64
331int NEW(__fsetpos64)(FILE *stream, const fpos64_t *pos)
332{
[2552]333    int ret; FSETPOS(__fsetpos64); return ret;
[2533]334}
335#endif
336
[1699]337void NEW(rewind)(FILE *stream)
[1581]338{
339    int fd;
340
[1648]341    LOADSYM(rewind);
[1581]342    fd = fileno(stream);
[1791]343    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
[1581]344    {
[1699]345        ORIG(rewind)(stream);
[1581]346        return;
347    }
348
[1694]349    _zz_lock(fd);
[1699]350    ORIG(rewind)(stream);
[1694]351    _zz_unlock(fd);
[1687]352    debug("%s([%i])", __func__, fd);
[1581]353
[2566]354#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1606]355#else
[1581]356    /* FIXME: check what happens when rewind()ing a pipe */
357    _zz_setpos(fd, 0);
[1606]358#endif
[1581]359}
360
[2584]361#if defined HAVE___FILBUF || defined HAVE___SRGET
362#   define FREAD_PREFUZZ() \
363    do \
364    { \
365        int64_t tmp = _zz_getpos(fd); \
366        _zz_setpos(fd, pos); \
367        already_fuzzed = _zz_getfuzzed(fd); \
368        _zz_setpos(fd, tmp); \
369    } \
370    while(0)
371#else
372#   define FREAD_PREFUZZ() do {} while(0)
373#endif
374
[2566]375#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[2331]376#   define FREAD_FUZZ() \
377    do \
378    { \
379        debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
380              (long int)size, (long int)nmemb, fd, (long int)ret); \
381    } while(0)
[1606]382#else
[2331]383#   define FREAD_FUZZ() \
384    do \
385    { \
386        int64_t newpos = ftell(stream); \
387        /* XXX: the number of bytes read is not ret * size, because \
388         * a partial read may have advanced the stream pointer. However, \
389         * when reading from a pipe ftell() will return 0, and ret * size \
390         * is then better than nothing. */ \
391        if(newpos <= 0) \
392        { \
393            pos = _zz_getpos(fd); \
394            newpos = pos + ret * size; \
395        } \
396        if(newpos != pos) \
397        { \
398            char *b = ptr; \
[2584]399            /* Skip bytes that were already fuzzed by __filbuf or __srget */ \
400            if(newpos > pos + already_fuzzed) \
401            { \
402                _zz_setpos(fd, pos + already_fuzzed); \
403                _zz_fuzz(fd, ptr, newpos - pos - already_fuzzed); \
404            } \
[2331]405            _zz_setpos(fd, newpos); \
406            if(newpos >= pos + 4) \
407                debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
408                      ptr, (long int)size, (long int)nmemb, fd, \
409                      (long int)ret, b[0], b[1], b[2], b[3]); \
410            else \
411                debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
412                      (long int)size, (long int)nmemb, fd, \
413                      (long int)ret, b[0]); \
414        } \
415        else \
416            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
417                  (long int)size, (long int)nmemb, fd, (long int)ret); \
418    } while(0)
[1606]419#endif
[1473]420
[2331]421#define FREAD(fn) \
422    do \
423    { \
424        int64_t pos; \
[2584]425        int fd, already_fuzzed = 0; \
[2331]426        LOADSYM(fn); \
427        fd = fileno(stream); \
428        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
429            return ORIG(fn)(ptr, size, nmemb, stream); \
430        pos = ftell(stream); \
431        _zz_lock(fd); \
432        ret = ORIG(fn)(ptr, size, nmemb, stream); \
433        _zz_unlock(fd); \
[2584]434        FREAD_PREFUZZ(); \
[2331]435        FREAD_FUZZ(); \
436    } while(0)
[1474]437
[2331]438size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
439{
440    size_t ret; FREAD(fread); return ret;
441}
[1591]442
[2331]443#if defined HAVE_FREAD_UNLOCKED
444#undef fread_unlocked /* can be a macro; we don’t want that */
445size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
446{
447    size_t ret; FREAD(fread_unlocked); return ret;
448}
[1602]449#endif
[1591]450
[2584]451#if defined HAVE___FILBUF || defined HAVE___SRGET
452#   define FGETC_PREFUZZ already_fuzzed = _zz_getfuzzed(fd);
453#else
454#   define FGETC_PREFUZZ
455#endif
456
[2566]457#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1602]458#   define FGETC_FUZZ
459#else
460#   define FGETC_FUZZ \
461        if(ret != EOF) \
462        { \
463            uint8_t ch = ret; \
[2584]464            if(already_fuzzed <= 0) \
465               _zz_fuzz(fd, &ch, 1); \
[1602]466            _zz_addpos(fd, 1); \
467            ret = ch; \
468        }
469#endif
470
[2334]471#define FGETC(fn, s, arg) \
[1497]472    do { \
[2584]473        int fd, already_fuzzed = 0; \
[1648]474        LOADSYM(fn); \
[2334]475        fd = fileno(s); \
[1791]476        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
[2334]477            return ORIG(fn)(arg); \
[1694]478        _zz_lock(fd); \
[2334]479        ret = ORIG(fn)(arg); \
[1694]480        _zz_unlock(fd); \
[2584]481        FGETC_PREFUZZ \
[1602]482        FGETC_FUZZ \
[1724]483        if(ret == EOF) \
484            debug("%s([%i]) = EOF", __func__, fd); \
[1723]485        else \
[1722]486            debug("%s([%i]) = '%c'", __func__, fd, ret); \
[1497]487    } while(0)
488
[1595]489#undef getc /* can be a macro; we don’t want that */
[1699]490int NEW(getc)(FILE *stream)
[1497]491{
[2334]492    int ret; FGETC(getc, stream, stream); return ret;
[1497]493}
494
[2334]495#undef getchar /* can be a macro; we don’t want that */
496int NEW(getchar)(void)
497{
498    int ret; FGETC(getchar, stdin, /* empty */); return ret;
499}
500
[1699]501int NEW(fgetc)(FILE *stream)
[1497]502{
[2334]503    int ret; FGETC(fgetc, stream, stream); return ret;
[1497]504}
505
[1695]506#if defined HAVE__IO_GETC
[1699]507int NEW(_IO_getc)(FILE *stream)
[1595]508{
[2334]509    int ret; FGETC(_IO_getc, stream, stream); return ret;
[1595]510}
511#endif
512
[2330]513#if defined HAVE_GETC_UNLOCKED
[2331]514#undef getc_unlocked /* can be a macro; we don’t want that */
[2330]515int NEW(getc_unlocked)(FILE *stream)
516{
[2334]517    int ret; FGETC(getc_unlocked, stream, stream); return ret;
[2330]518}
519#endif
520
[2334]521#if defined HAVE_GETCHAR_UNLOCKED
522#undef getchar_unlocked /* can be a macro; we don’t want that */
523int NEW(getchar_unlocked)(void)
524{
525    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
526}
527#endif
528
[2330]529#if defined HAVE_FGETC_UNLOCKED
[2331]530#undef fgetc_unlocked /* can be a macro; we don’t want that */
[2330]531int NEW(fgetc_unlocked)(FILE *stream)
532{
[2334]533    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
[2330]534}
535#endif
536
[2566]537#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[2332]538#   define FGETS_FUZZ(fn, fn2) \
[2331]539        _zz_lock(fd); \
[2332]540        ret = ORIG(fn)(s, size, stream); \
[2331]541        _zz_unlock(fd);
[1602]542#else
[2332]543#   define FGETS_FUZZ(fn, fn2) \
[2331]544        if(size <= 0) \
545            ret = NULL; \
546        else if(size == 1) \
547            s[0] = '\0'; \
548        else \
549        { \
550            int i; \
551            for(i = 0; i < size - 1; i++) \
552            { \
553                int ch; \
554                _zz_lock(fd); \
[2332]555                ch = ORIG(fn2)(stream); \
[2331]556                _zz_unlock(fd); \
557                if(ch == EOF) \
558                { \
559                    s[i] = '\0'; \
560                    if(!i) \
561                        ret = NULL; \
562                    break; \
563                } \
564                s[i] = (char)(unsigned char)ch; \
565                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
566                _zz_addpos(fd, 1); \
567                if(s[i] == '\n') \
568                { \
569                    s[i + 1] = '\0'; \
570                    break; \
571                } \
572            } \
573        }
574#endif
[1603]575
[2332]576#define FGETS(fn, fn2) \
[2331]577    do \
578    { \
579        int fd; \
580        ret = s; \
581        LOADSYM(fn); \
[2332]582        LOADSYM(fn2); \
[2331]583        fd = fileno(stream); \
584        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
585            return ORIG(fn)(s, size, stream); \
[2332]586        FGETS_FUZZ(fn, fn2) \
[2331]587        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
588    } while(0)
[1497]589
[2331]590char *NEW(fgets)(char *s, int size, FILE *stream)
591{
[2332]592    char *ret; FGETS(fgets, fgetc); return ret;
[2331]593}
[1553]594
[2331]595#if defined HAVE_FGETS_UNLOCKED
596char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
597{
[2332]598    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
[2331]599}
[1602]600#endif
[1497]601
[1699]602int NEW(ungetc)(int c, FILE *stream)
[1497]603{
604    int ret, fd;
605
[1648]606    LOADSYM(ungetc);
[1497]607    fd = fileno(stream);
[1791]608    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
[1699]609        return ORIG(ungetc)(c, stream);
[1497]610
[1694]611    _zz_lock(fd);
[1719]612    ret = ORIG(ungetc)(c, stream);
[1694]613    _zz_unlock(fd);
[1606]614
[1719]615    if(ret != EOF)
616    {
617        struct fuzz *fuzz = _zz_getfuzz(fd);
618        fuzz->uflag = 1;
619        fuzz->upos = _zz_getpos(fd) - 1;
620        fuzz->uchar = c;
[2566]621#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1606]622#else
[1719]623        _zz_addpos(fd, -1);
[1606]624#endif
[1719]625    }
[1606]626
[1724]627    if(ret == EOF)
628        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
[1722]629    else
630        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
631
[1497]632    return ret;
633}
634
[1699]635int NEW(fclose)(FILE *fp)
[1478]636{
637    int ret, fd;
638
[1648]639    LOADSYM(fclose);
[1478]640    fd = fileno(fp);
[1527]641    if(!_zz_ready || !_zz_iswatched(fd))
[1699]642        return ORIG(fclose)(fp);
[1497]643
[1694]644    _zz_lock(fd);
[1699]645    ret = ORIG(fclose)(fp);
[1694]646    _zz_unlock(fd);
[1687]647    debug("%s([%i]) = %i", __func__, fd, ret);
[1524]648    _zz_unregister(fd);
[1478]649
650    return ret;
651}
652
[1497]653#define GETDELIM(fn, delim, need_delim) \
654    do { \
655        char *line; \
656        ssize_t done, size; \
657        int fd, finished = 0; \
[1648]658        LOADSYM(fn); \
[1679]659        LOADSYM(getdelim); \
660        LOADSYM(fgetc); \
[1497]661        fd = fileno(stream); \
[1791]662        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
[1699]663            return ORIG(getdelim)(lineptr, n, delim, stream); \
[1497]664        line = *lineptr; \
665        size = line ? *n : 0; \
666        ret = done = finished = 0; \
667        for(;;) \
668        { \
669            int ch; \
670            if(done >= size) /* highly inefficient but I don't care */ \
671                line = realloc(line, size = done + 1); \
672            if(finished) \
673            { \
674                line[done] = '\0'; \
675                *n = size; \
676                *lineptr = line; \
677                break; \
678            } \
[1694]679            _zz_lock(fd); \
[1699]680            ch = ORIG(fgetc)(stream); \
[1694]681            _zz_unlock(fd); \
[1497]682            if(ch == EOF) \
683            { \
684                finished = 1; \
685                ret = done; \
686            } \
687            else \
688            { \
689                unsigned char c = ch; \
[1523]690                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
[1497]691                line[done++] = c; \
[1524]692                _zz_addpos(fd, 1); \
[1497]693                if(c == delim) \
694                { \
695                    finished = 1; \
696                    ret = done; \
697                } \
698            } \
699        } \
700        if(need_delim) \
[1688]701            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
[1551]702                  lineptr, n, delim, fd, (long int)ret); \
[1497]703        else \
[1687]704            debug("%s(%p, %p, [%i]) = %li", __func__, \
[1551]705                  lineptr, n, fd, (long int)ret); \
[1497]706        return ret; \
707    } while(0)
708
[1695]709#if defined HAVE_GETLINE
[1699]710ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
[1497]711{
712    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
713}
[1543]714#endif
[1497]715
[1695]716#if defined HAVE_GETDELIM
[1699]717ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
[1497]718{
719    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
720}
[1543]721#endif
[1497]722
[1695]723#if defined HAVE___GETDELIM
[1699]724ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
[1497]725{
726    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
727}
[1543]728#endif
[1497]729
[1695]730#if defined HAVE_FGETLN
[1699]731char *NEW(fgetln)(FILE *stream, size_t *len)
[1566]732{
[1602]733    char *ret;
[2566]734#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1604]735#else
[1566]736    struct fuzz *fuzz;
737    size_t i, size;
[1603]738#endif
[1566]739    int fd;
740
[1648]741    LOADSYM(fgetln);
[1679]742    LOADSYM(fgetc);
[1566]743    fd = fileno(stream);
[1791]744    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
[1699]745        return ORIG(fgetln)(stream, len);
[1566]746
[2566]747#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1694]748    _zz_lock(fd);
[1699]749    ret = ORIG(fgetln)(stream, len);
[1694]750    _zz_unlock(fd);
[1602]751#else
[1566]752    fuzz = _zz_getfuzz(fd);
753
[1593]754    for(i = size = 0; ; /* i is incremented below */)
[1566]755    {
756        int ch;
757
[1694]758        _zz_lock(fd);
[1699]759        ch = ORIG(fgetc)(stream);
[1694]760        _zz_unlock(fd);
[1566]761
762        if(ch == EOF)
763            break;
764
[1567]765        if(i >= size)
766            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
767
768        fuzz->tmp[i] = (char)(unsigned char)ch;
769        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
[1566]770        _zz_addpos(fd, 1);
[1567]771
[1593]772        if(fuzz->tmp[i++] == '\n')
[1567]773            break;
[1566]774    }
775
[1567]776    *len = i;
[1602]777    ret = fuzz->tmp;
778#endif
[1566]779
[1687]780    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
[1602]781    return ret;
[1566]782}
783#endif
784
[2570]785#define REFILL(fn, fn_advances) \
[2569]786    do \
787    { \
[2584]788        int64_t pos; \
[2569]789        off_t newpos; \
790        int fd; \
791        LOADSYM(fn); \
792        fd = fileno(fp); \
793        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
794            return ORIG(fn)(fp); \
[2584]795        pos = _zz_getpos(fd); \
[2569]796        _zz_lock(fd); \
797        ret = ORIG(fn)(fp); \
798        newpos = lseek(fd, 0, SEEK_CUR); \
799        _zz_unlock(fd); \
800        if(ret != EOF) \
801        { \
[2584]802            int already_fuzzed = 0; \
[2570]803            if(fn_advances) \
804            { \
[2584]805                uint8_t ch = (uint8_t)(unsigned int)ret; \
[2570]806                if(newpos != -1) \
807                    _zz_setpos(fd, newpos - fp->FILE_CNT - 1); \
[2584]808                already_fuzzed = _zz_getfuzzed(fd); \
[2570]809                _zz_fuzz(fd, &ch, 1); \
[2584]810                ret = fp->FILE_PTR[-1] = ch; \
811                _zz_setfuzzed(fd, fp->FILE_CNT + 1); \
[2570]812                _zz_addpos(fd, 1); \
813            } \
814            else \
[2571]815            { \
[2584]816                _zz_setfuzzed(fd, fp->FILE_CNT); \
[2571]817                if(newpos != -1) \
818                    _zz_setpos(fd, newpos - fp->FILE_CNT); \
819            } \
[2584]820            if(fp->FILE_CNT > already_fuzzed) \
821            { \
822                _zz_addpos(fd, already_fuzzed); \
823                _zz_fuzz(fd, fp->FILE_PTR, fp->FILE_CNT - already_fuzzed); \
824            } \
825            _zz_addpos(fd, fp->FILE_CNT - already_fuzzed); \
[2569]826        } \
[2584]827        _zz_setpos(fd, pos); /* FIXME: do we always need to do this? */ \
828        debug("%s([%i]) = %i", __func__, fd, ret); \
[2569]829    } \
830    while(0)
831
[1695]832#if defined HAVE___SREFILL
[1699]833int NEW(__srefill)(FILE *fp)
[1598]834{
[2570]835    int ret; REFILL(__srefill, 0); return ret;
[2569]836}
837#endif
[1598]838
[2572]839#if defined HAVE___SRGET && !defined HAVE___SREFILL
[2569]840int NEW(__srget)(FILE *fp)
841{
[2570]842    int ret; REFILL(__srget, 1); return ret;
[1598]843}
844#endif
845
[2533]846#if defined HAVE___FILBUF
847int NEW(__filbuf)(FILE *fp)
848{
[2570]849    int ret; REFILL(__filbuf, 1); return ret;
[2533]850}
851#endif
852
Note: See TracBrowser for help on using the repository browser.