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

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

Document the srefill strategy in the source code.

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