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

Last change on this file since 2572 was 2572, checked in by Sam Hocevar, 12 years ago
  • lib-stream.c: since srefill is far more powerful than srget, we only reimplement the former on OS X and completely ignore the latter.
  • Property svn:keywords set to Id
File size: 21.4 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 2572 2008-07-20 09:57:52Z 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
[2566]361#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[2331]362#   define FREAD_FUZZ() \
363    do \
364    { \
365        debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
366              (long int)size, (long int)nmemb, fd, (long int)ret); \
367    } while(0)
[1606]368#else
[2331]369#   define FREAD_FUZZ() \
370    do \
371    { \
372        int64_t newpos = ftell(stream); \
373        /* XXX: the number of bytes read is not ret * size, because \
374         * a partial read may have advanced the stream pointer. However, \
375         * when reading from a pipe ftell() will return 0, and ret * size \
376         * is then better than nothing. */ \
377        if(newpos <= 0) \
378        { \
379            pos = _zz_getpos(fd); \
380            newpos = pos + ret * size; \
381        } \
382        if(newpos != pos) \
383        { \
384            char *b = ptr; \
[2568]385            _zz_setpos(fd, pos); \
[2331]386            _zz_fuzz(fd, ptr, newpos - pos); \
387            _zz_setpos(fd, newpos); \
388            if(newpos >= pos + 4) \
389                debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
390                      ptr, (long int)size, (long int)nmemb, fd, \
391                      (long int)ret, b[0], b[1], b[2], b[3]); \
392            else \
393                debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
394                      (long int)size, (long int)nmemb, fd, \
395                      (long int)ret, b[0]); \
396        } \
397        else \
398            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
399                  (long int)size, (long int)nmemb, fd, (long int)ret); \
400    } while(0)
[1606]401#endif
[1473]402
[2331]403#define FREAD(fn) \
404    do \
405    { \
406        int64_t pos; \
407        int fd; \
408        LOADSYM(fn); \
409        fd = fileno(stream); \
410        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
411            return ORIG(fn)(ptr, size, nmemb, stream); \
412        pos = ftell(stream); \
413        _zz_lock(fd); \
414        ret = ORIG(fn)(ptr, size, nmemb, stream); \
415        _zz_unlock(fd); \
416        FREAD_FUZZ(); \
417    } while(0)
[1474]418
[2331]419size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
420{
421    size_t ret; FREAD(fread); return ret;
422}
[1591]423
[2331]424#if defined HAVE_FREAD_UNLOCKED
425#undef fread_unlocked /* can be a macro; we don’t want that */
426size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
427{
428    size_t ret; FREAD(fread_unlocked); return ret;
429}
[1602]430#endif
[1591]431
[2566]432#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1602]433#   define FGETC_FUZZ
434#else
435#   define FGETC_FUZZ \
436        if(ret != EOF) \
437        { \
438            uint8_t ch = ret; \
439            _zz_fuzz(fd, &ch, 1); \
440            _zz_addpos(fd, 1); \
441            ret = ch; \
442        }
443#endif
444
[2334]445#define FGETC(fn, s, arg) \
[1497]446    do { \
447        int fd; \
[1648]448        LOADSYM(fn); \
[2334]449        fd = fileno(s); \
[1791]450        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
[2334]451            return ORIG(fn)(arg); \
[1694]452        _zz_lock(fd); \
[2334]453        ret = ORIG(fn)(arg); \
[1694]454        _zz_unlock(fd); \
[1602]455        FGETC_FUZZ \
[1724]456        if(ret == EOF) \
457            debug("%s([%i]) = EOF", __func__, fd); \
[1723]458        else \
[1722]459            debug("%s([%i]) = '%c'", __func__, fd, ret); \
[1497]460    } while(0)
461
[1595]462#undef getc /* can be a macro; we don’t want that */
[1699]463int NEW(getc)(FILE *stream)
[1497]464{
[2334]465    int ret; FGETC(getc, stream, stream); return ret;
[1497]466}
467
[2334]468#undef getchar /* can be a macro; we don’t want that */
469int NEW(getchar)(void)
470{
471    int ret; FGETC(getchar, stdin, /* empty */); return ret;
472}
473
[1699]474int NEW(fgetc)(FILE *stream)
[1497]475{
[2334]476    int ret; FGETC(fgetc, stream, stream); return ret;
[1497]477}
478
[1695]479#if defined HAVE__IO_GETC
[1699]480int NEW(_IO_getc)(FILE *stream)
[1595]481{
[2334]482    int ret; FGETC(_IO_getc, stream, stream); return ret;
[1595]483}
484#endif
485
[2330]486#if defined HAVE_GETC_UNLOCKED
[2331]487#undef getc_unlocked /* can be a macro; we don’t want that */
[2330]488int NEW(getc_unlocked)(FILE *stream)
489{
[2334]490    int ret; FGETC(getc_unlocked, stream, stream); return ret;
[2330]491}
492#endif
493
[2334]494#if defined HAVE_GETCHAR_UNLOCKED
495#undef getchar_unlocked /* can be a macro; we don’t want that */
496int NEW(getchar_unlocked)(void)
497{
498    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
499}
500#endif
501
[2330]502#if defined HAVE_FGETC_UNLOCKED
[2331]503#undef fgetc_unlocked /* can be a macro; we don’t want that */
[2330]504int NEW(fgetc_unlocked)(FILE *stream)
505{
[2334]506    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
[2330]507}
508#endif
509
[2566]510#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[2332]511#   define FGETS_FUZZ(fn, fn2) \
[2331]512        _zz_lock(fd); \
[2332]513        ret = ORIG(fn)(s, size, stream); \
[2331]514        _zz_unlock(fd);
[1602]515#else
[2332]516#   define FGETS_FUZZ(fn, fn2) \
[2331]517        if(size <= 0) \
518            ret = NULL; \
519        else if(size == 1) \
520            s[0] = '\0'; \
521        else \
522        { \
523            int i; \
524            for(i = 0; i < size - 1; i++) \
525            { \
526                int ch; \
527                _zz_lock(fd); \
[2332]528                ch = ORIG(fn2)(stream); \
[2331]529                _zz_unlock(fd); \
530                if(ch == EOF) \
531                { \
532                    s[i] = '\0'; \
533                    if(!i) \
534                        ret = NULL; \
535                    break; \
536                } \
537                s[i] = (char)(unsigned char)ch; \
538                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
539                _zz_addpos(fd, 1); \
540                if(s[i] == '\n') \
541                { \
542                    s[i + 1] = '\0'; \
543                    break; \
544                } \
545            } \
546        }
547#endif
[1603]548
[2332]549#define FGETS(fn, fn2) \
[2331]550    do \
551    { \
552        int fd; \
553        ret = s; \
554        LOADSYM(fn); \
[2332]555        LOADSYM(fn2); \
[2331]556        fd = fileno(stream); \
557        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
558            return ORIG(fn)(s, size, stream); \
[2332]559        FGETS_FUZZ(fn, fn2) \
[2331]560        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
561    } while(0)
[1497]562
[2331]563char *NEW(fgets)(char *s, int size, FILE *stream)
564{
[2332]565    char *ret; FGETS(fgets, fgetc); return ret;
[2331]566}
[1553]567
[2331]568#if defined HAVE_FGETS_UNLOCKED
569char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
570{
[2332]571    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
[2331]572}
[1602]573#endif
[1497]574
[1699]575int NEW(ungetc)(int c, FILE *stream)
[1497]576{
577    int ret, fd;
578
[1648]579    LOADSYM(ungetc);
[1497]580    fd = fileno(stream);
[1791]581    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
[1699]582        return ORIG(ungetc)(c, stream);
[1497]583
[1694]584    _zz_lock(fd);
[1719]585    ret = ORIG(ungetc)(c, stream);
[1694]586    _zz_unlock(fd);
[1606]587
[1719]588    if(ret != EOF)
589    {
590        struct fuzz *fuzz = _zz_getfuzz(fd);
591        fuzz->uflag = 1;
592        fuzz->upos = _zz_getpos(fd) - 1;
593        fuzz->uchar = c;
[2566]594#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1606]595#else
[1719]596        _zz_addpos(fd, -1);
[1606]597#endif
[1719]598    }
[1606]599
[1724]600    if(ret == EOF)
601        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
[1722]602    else
603        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
604
[1497]605    return ret;
606}
607
[1699]608int NEW(fclose)(FILE *fp)
[1478]609{
610    int ret, fd;
611
[1648]612    LOADSYM(fclose);
[1478]613    fd = fileno(fp);
[1527]614    if(!_zz_ready || !_zz_iswatched(fd))
[1699]615        return ORIG(fclose)(fp);
[1497]616
[1694]617    _zz_lock(fd);
[1699]618    ret = ORIG(fclose)(fp);
[1694]619    _zz_unlock(fd);
[1687]620    debug("%s([%i]) = %i", __func__, fd, ret);
[1524]621    _zz_unregister(fd);
[1478]622
623    return ret;
624}
625
[1497]626#define GETDELIM(fn, delim, need_delim) \
627    do { \
628        char *line; \
629        ssize_t done, size; \
630        int fd, finished = 0; \
[1648]631        LOADSYM(fn); \
[1679]632        LOADSYM(getdelim); \
633        LOADSYM(fgetc); \
[1497]634        fd = fileno(stream); \
[1791]635        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
[1699]636            return ORIG(getdelim)(lineptr, n, delim, stream); \
[1497]637        line = *lineptr; \
638        size = line ? *n : 0; \
639        ret = done = finished = 0; \
640        for(;;) \
641        { \
642            int ch; \
643            if(done >= size) /* highly inefficient but I don't care */ \
644                line = realloc(line, size = done + 1); \
645            if(finished) \
646            { \
647                line[done] = '\0'; \
648                *n = size; \
649                *lineptr = line; \
650                break; \
651            } \
[1694]652            _zz_lock(fd); \
[1699]653            ch = ORIG(fgetc)(stream); \
[1694]654            _zz_unlock(fd); \
[1497]655            if(ch == EOF) \
656            { \
657                finished = 1; \
658                ret = done; \
659            } \
660            else \
661            { \
662                unsigned char c = ch; \
[1523]663                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
[1497]664                line[done++] = c; \
[1524]665                _zz_addpos(fd, 1); \
[1497]666                if(c == delim) \
667                { \
668                    finished = 1; \
669                    ret = done; \
670                } \
671            } \
672        } \
673        if(need_delim) \
[1688]674            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
[1551]675                  lineptr, n, delim, fd, (long int)ret); \
[1497]676        else \
[1687]677            debug("%s(%p, %p, [%i]) = %li", __func__, \
[1551]678                  lineptr, n, fd, (long int)ret); \
[1497]679        return ret; \
680    } while(0)
681
[1695]682#if defined HAVE_GETLINE
[1699]683ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
[1497]684{
685    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
686}
[1543]687#endif
[1497]688
[1695]689#if defined HAVE_GETDELIM
[1699]690ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
[1497]691{
692    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
693}
[1543]694#endif
[1497]695
[1695]696#if defined HAVE___GETDELIM
[1699]697ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
[1497]698{
699    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
700}
[1543]701#endif
[1497]702
[1695]703#if defined HAVE_FGETLN
[1699]704char *NEW(fgetln)(FILE *stream, size_t *len)
[1566]705{
[1602]706    char *ret;
[2566]707#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1604]708#else
[1566]709    struct fuzz *fuzz;
710    size_t i, size;
[1603]711#endif
[1566]712    int fd;
713
[1648]714    LOADSYM(fgetln);
[1679]715    LOADSYM(fgetc);
[1566]716    fd = fileno(stream);
[1791]717    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
[1699]718        return ORIG(fgetln)(stream, len);
[1566]719
[2566]720#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
[1694]721    _zz_lock(fd);
[1699]722    ret = ORIG(fgetln)(stream, len);
[1694]723    _zz_unlock(fd);
[1602]724#else
[1566]725    fuzz = _zz_getfuzz(fd);
726
[1593]727    for(i = size = 0; ; /* i is incremented below */)
[1566]728    {
729        int ch;
730
[1694]731        _zz_lock(fd);
[1699]732        ch = ORIG(fgetc)(stream);
[1694]733        _zz_unlock(fd);
[1566]734
735        if(ch == EOF)
736            break;
737
[1567]738        if(i >= size)
739            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
740
741        fuzz->tmp[i] = (char)(unsigned char)ch;
742        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
[1566]743        _zz_addpos(fd, 1);
[1567]744
[1593]745        if(fuzz->tmp[i++] == '\n')
[1567]746            break;
[1566]747    }
748
[1567]749    *len = i;
[1602]750    ret = fuzz->tmp;
751#endif
[1566]752
[1687]753    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
[1602]754    return ret;
[1566]755}
756#endif
757
[2570]758#define REFILL(fn, fn_advances) \
[2569]759    do \
760    { \
761        off_t newpos; \
762        int fd; \
763        LOADSYM(fn); \
764        fd = fileno(fp); \
765        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
766            return ORIG(fn)(fp); \
767        _zz_lock(fd); \
768        ret = ORIG(fn)(fp); \
769        newpos = lseek(fd, 0, SEEK_CUR); \
770        _zz_unlock(fd); \
771        if(ret != EOF) \
772        { \
[2570]773            if(fn_advances) \
774            { \
775                if(newpos != -1) \
776                    _zz_setpos(fd, newpos - fp->FILE_CNT - 1); \
777                uint8_t ch = (uint8_t)(unsigned int)ret; \
778                _zz_fuzz(fd, &ch, 1); \
779                ret = ch; \
780                _zz_addpos(fd, 1); \
781            } \
782            else \
[2571]783            { \
784                if(newpos != -1) \
785                    _zz_setpos(fd, newpos - fp->FILE_CNT); \
786            } \
[2570]787            _zz_fuzz(fd, fp->FILE_PTR, fp->FILE_CNT); \
788            _zz_addpos(fd, fp->FILE_CNT); \
[2569]789        } \
790        if(!_zz_islocked(fd)) \
791            debug("%s([%i]) = %i", __func__, fd, ret); \
792    } \
793    while(0)
794
[1695]795#if defined HAVE___SREFILL
[1699]796int NEW(__srefill)(FILE *fp)
[1598]797{
[2570]798    int ret; REFILL(__srefill, 0); return ret;
[2569]799}
800#endif
[1598]801
[2572]802#if defined HAVE___SRGET && !defined HAVE___SREFILL
[2569]803int NEW(__srget)(FILE *fp)
804{
[2570]805    int ret; REFILL(__srget, 1); return ret;
[1598]806}
807#endif
808
[2533]809#if defined HAVE___FILBUF
810int NEW(__filbuf)(FILE *fp)
811{
[2570]812    int ret; REFILL(__filbuf, 1); return ret;
[2533]813}
814#endif
815
Note: See TracBrowser for help on using the repository browser.