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
Line 
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/*
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 REFILL_ONLY_STDIO
29#endif
30
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
38#include <stdio.h>
39#include <sys/types.h>
40#if defined HAVE_UNISTD_H
41#   include <unistd.h> /* Needed for __srefill’s lseek() call */
42#endif
43
44#include "libzzuf.h"
45#include "lib-load.h"
46#include "debug.h"
47#include "fuzz.h"
48#include "fd.h"
49
50#if defined HAVE___SREFILL
51int NEW(__srefill)(FILE *fp);
52#endif
53
54#if defined HAVE___FILBUF
55int NEW(__filbuf)(FILE *fp);
56#endif
57
58#if defined HAVE___SRGET && !defined HAVE___SREFILL
59int NEW(__srget)(FILE *fp);
60#endif
61
62/* Library functions that we divert */
63static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
64#if defined HAVE_FOPEN64
65static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
66#endif
67#if defined HAVE___FOPEN64
68static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
69#endif
70static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
71                                  FILE *stream);
72#if defined HAVE_FREOPEN64
73static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
74                                  FILE *stream);
75#endif
76#if defined HAVE___FREOPEN64
77static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
78                                     FILE *stream);
79#endif
80static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
81#if defined HAVE_FSEEKO
82static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
83#endif
84#if defined HAVE_FSEEKO64
85static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
86#endif
87#if defined HAVE___FSEEKO64
88static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
89#endif
90#if defined HAVE_FSETPOS64
91static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
92#endif
93#if defined HAVE___FSETPOS64
94static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
95#endif
96static void    (*ORIG(rewind))   (FILE *stream);
97static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
98                                  FILE *stream);
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
103static int     (*ORIG(getc))     (FILE *stream);
104static int     (*ORIG(getchar))  (void);
105static int     (*ORIG(fgetc))    (FILE *stream);
106#if defined HAVE__IO_GETC
107static int     (*ORIG(_IO_getc)) (FILE *stream);
108#endif
109#if defined HAVE_GETC_UNLOCKED
110static int     (*ORIG(getc_unlocked))    (FILE *stream);
111#endif
112#if defined HAVE_GETCHAR_UNLOCKED
113static int     (*ORIG(getchar_unlocked)) (void);
114#endif
115#if defined HAVE_FGETC_UNLOCKED
116static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
117#endif
118static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
119#if defined HAVE_FGETS_UNLOCKED
120static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
121#endif
122static int     (*ORIG(ungetc))   (int c, FILE *stream);
123static int     (*ORIG(fclose))   (FILE *fp);
124
125/* Additional GNUisms */
126#if defined HAVE_GETLINE
127static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
128#endif
129#if defined HAVE_GETDELIM
130static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
131                                    FILE *stream);
132#endif
133#if defined HAVE___GETDELIM
134static ssize_t (*ORIG(__getdelim)) (char **lineptr, size_t *n, int delim,
135                                    FILE *stream);
136#endif
137
138/* Additional BSDisms */
139#if defined HAVE_FGETLN
140static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
141#endif
142#if defined HAVE___SREFILL
143int            (*ORIG(__srefill)) (FILE *fp);
144#endif
145#if defined HAVE___SRGET && !defined HAVE___SREFILL
146int            (*ORIG(__srget))   (FILE *fp);
147#endif
148
149/* Additional HP-UXisms */
150#if defined HAVE___FILBUF
151int            (*ORIG(__filbuf))  (FILE *fp);
152#endif
153
154/* Our function wrappers */
155#if defined REFILL_ONLY_STDIO /* Fuzz fp if we have __srefill() */
156#   define FOPEN_FUZZ() \
157    _zz_fuzz(fd, ret->FILE_PTR, ret->FILE_CNT)
158#else
159#   define FOPEN_FUZZ()
160#endif
161
162#define FOPEN(fn) \
163    do \
164    { \
165        LOADSYM(fn); \
166        if(!_zz_ready) \
167            return ORIG(fn)(path, mode); \
168        _zz_lock(-1); \
169        ret = ORIG(fn)(path, mode); \
170        _zz_unlock(-1); \
171        if(ret && _zz_mustwatch(path)) \
172        { \
173            int fd = fileno(ret); \
174            _zz_register(fd); \
175            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
176            FOPEN_FUZZ(); \
177        } \
178    } while(0)
179
180FILE *NEW(fopen)(const char *path, const char *mode)
181{
182    FILE *ret; FOPEN(fopen); return ret;
183}
184
185#if defined HAVE_FOPEN64
186FILE *NEW(fopen64)(const char *path, const char *mode)
187{
188    FILE *ret; FOPEN(fopen64); return ret;
189}
190#endif
191
192#if defined HAVE___FOPEN64
193FILE *NEW(__fopen64)(const char *path, const char *mode)
194{
195    FILE *ret; FOPEN(__fopen64); return ret;
196}
197#endif
198
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)
222
223FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
224{
225    FILE *ret; FREOPEN(freopen); return ret;
226}
227
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
235#if defined HAVE___FREOPEN64
236FILE *NEW(__freopen64)(const char *path, const char *mode, FILE *stream)
237{
238    FILE *ret; FREOPEN(__freopen64); return ret;
239}
240#endif
241
242#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
243#   define FSEEK_FUZZ(fn2)
244#else
245#   define FSEEK_FUZZ(fn2) \
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            } \
261        }
262#endif
263
264#define FSEEK(fn, fn2) \
265    do \
266    { \
267        int fd; \
268        LOADSYM(fn); \
269        fd = fileno(stream); \
270        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
271            return ORIG(fn)(stream, offset, whence); \
272        _zz_lock(fd); \
273        ret = ORIG(fn)(stream, offset, whence); \
274        _zz_unlock(fd); \
275        debug("%s([%i], %lli, %i) = %i", __func__, \
276              fd, (long long int)offset, whence, ret); \
277        FSEEK_FUZZ(fn2) \
278    } while(0)
279
280int NEW(fseek)(FILE *stream, long offset, int whence)
281{
282    int ret; FSEEK(fseek, ftell); return ret;
283}
284
285#if defined HAVE_FSEEKO
286int NEW(fseeko)(FILE *stream, off_t offset, int whence)
287{
288    int ret; FSEEK(fseeko, ftello); return ret;
289}
290#endif
291
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
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
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__, \
318              fd, (long long int)FPOS_CAST(*pos), ret); \
319        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
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
330#if defined HAVE___FSETPOS64
331int NEW(__fsetpos64)(FILE *stream, const fpos64_t *pos)
332{
333    int ret; FSETPOS(__fsetpos64); return ret;
334}
335#endif
336
337void NEW(rewind)(FILE *stream)
338{
339    int fd;
340
341    LOADSYM(rewind);
342    fd = fileno(stream);
343    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
344    {
345        ORIG(rewind)(stream);
346        return;
347    }
348
349    _zz_lock(fd);
350    ORIG(rewind)(stream);
351    _zz_unlock(fd);
352    debug("%s([%i])", __func__, fd);
353
354#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
355#else
356    /* FIXME: check what happens when rewind()ing a pipe */
357    _zz_setpos(fd, 0);
358#endif
359}
360
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
375#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
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)
382#else
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; \
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            } \
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)
419#endif
420
421#define FREAD(fn) \
422    do \
423    { \
424        int64_t pos; \
425        int fd, already_fuzzed = 0; \
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); \
434        FREAD_PREFUZZ(); \
435        FREAD_FUZZ(); \
436    } while(0)
437
438size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
439{
440    size_t ret; FREAD(fread); return ret;
441}
442
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}
449#endif
450
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
457#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
458#   define FGETC_FUZZ
459#else
460#   define FGETC_FUZZ \
461        if(ret != EOF) \
462        { \
463            uint8_t ch = ret; \
464            if(already_fuzzed <= 0) \
465               _zz_fuzz(fd, &ch, 1); \
466            _zz_addpos(fd, 1); \
467            ret = ch; \
468        }
469#endif
470
471#define FGETC(fn, s, arg) \
472    do { \
473        int fd, already_fuzzed = 0; \
474        LOADSYM(fn); \
475        fd = fileno(s); \
476        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
477            return ORIG(fn)(arg); \
478        _zz_lock(fd); \
479        ret = ORIG(fn)(arg); \
480        _zz_unlock(fd); \
481        FGETC_PREFUZZ \
482        FGETC_FUZZ \
483        if(ret == EOF) \
484            debug("%s([%i]) = EOF", __func__, fd); \
485        else \
486            debug("%s([%i]) = '%c'", __func__, fd, ret); \
487    } while(0)
488
489#undef getc /* can be a macro; we don’t want that */
490int NEW(getc)(FILE *stream)
491{
492    int ret; FGETC(getc, stream, stream); return ret;
493}
494
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
501int NEW(fgetc)(FILE *stream)
502{
503    int ret; FGETC(fgetc, stream, stream); return ret;
504}
505
506#if defined HAVE__IO_GETC
507int NEW(_IO_getc)(FILE *stream)
508{
509    int ret; FGETC(_IO_getc, stream, stream); return ret;
510}
511#endif
512
513#if defined HAVE_GETC_UNLOCKED
514#undef getc_unlocked /* can be a macro; we don’t want that */
515int NEW(getc_unlocked)(FILE *stream)
516{
517    int ret; FGETC(getc_unlocked, stream, stream); return ret;
518}
519#endif
520
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
529#if defined HAVE_FGETC_UNLOCKED
530#undef fgetc_unlocked /* can be a macro; we don’t want that */
531int NEW(fgetc_unlocked)(FILE *stream)
532{
533    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
534}
535#endif
536
537#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
538#   define FGETS_FUZZ(fn, fn2) \
539        _zz_lock(fd); \
540        ret = ORIG(fn)(s, size, stream); \
541        _zz_unlock(fd);
542#else
543#   define FGETS_FUZZ(fn, fn2) \
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); \
555                ch = ORIG(fn2)(stream); \
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
575
576#define FGETS(fn, fn2) \
577    do \
578    { \
579        int fd; \
580        ret = s; \
581        LOADSYM(fn); \
582        LOADSYM(fn2); \
583        fd = fileno(stream); \
584        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
585            return ORIG(fn)(s, size, stream); \
586        FGETS_FUZZ(fn, fn2) \
587        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
588    } while(0)
589
590char *NEW(fgets)(char *s, int size, FILE *stream)
591{
592    char *ret; FGETS(fgets, fgetc); return ret;
593}
594
595#if defined HAVE_FGETS_UNLOCKED
596char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
597{
598    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
599}
600#endif
601
602int NEW(ungetc)(int c, FILE *stream)
603{
604    int ret, fd;
605
606    LOADSYM(ungetc);
607    fd = fileno(stream);
608    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
609        return ORIG(ungetc)(c, stream);
610
611    _zz_lock(fd);
612    ret = ORIG(ungetc)(c, stream);
613    _zz_unlock(fd);
614
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;
621#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
622#else
623        _zz_addpos(fd, -1);
624#endif
625    }
626
627    if(ret == EOF)
628        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
629    else
630        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
631
632    return ret;
633}
634
635int NEW(fclose)(FILE *fp)
636{
637    int ret, fd;
638
639    LOADSYM(fclose);
640    fd = fileno(fp);
641    if(!_zz_ready || !_zz_iswatched(fd))
642        return ORIG(fclose)(fp);
643
644    _zz_lock(fd);
645    ret = ORIG(fclose)(fp);
646    _zz_unlock(fd);
647    debug("%s([%i]) = %i", __func__, fd, ret);
648    _zz_unregister(fd);
649
650    return ret;
651}
652
653#define GETDELIM(fn, delim, need_delim) \
654    do { \
655        char *line; \
656        ssize_t done, size; \
657        int fd, finished = 0; \
658        LOADSYM(fn); \
659        LOADSYM(getdelim); \
660        LOADSYM(fgetc); \
661        fd = fileno(stream); \
662        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
663            return ORIG(getdelim)(lineptr, n, delim, stream); \
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            } \
679            _zz_lock(fd); \
680            ch = ORIG(fgetc)(stream); \
681            _zz_unlock(fd); \
682            if(ch == EOF) \
683            { \
684                finished = 1; \
685                ret = done; \
686            } \
687            else \
688            { \
689                unsigned char c = ch; \
690                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
691                line[done++] = c; \
692                _zz_addpos(fd, 1); \
693                if(c == delim) \
694                { \
695                    finished = 1; \
696                    ret = done; \
697                } \
698            } \
699        } \
700        if(need_delim) \
701            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
702                  lineptr, n, delim, fd, (long int)ret); \
703        else \
704            debug("%s(%p, %p, [%i]) = %li", __func__, \
705                  lineptr, n, fd, (long int)ret); \
706        return ret; \
707    } while(0)
708
709#if defined HAVE_GETLINE
710ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
711{
712    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
713}
714#endif
715
716#if defined HAVE_GETDELIM
717ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
718{
719    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
720}
721#endif
722
723#if defined HAVE___GETDELIM
724ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
725{
726    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
727}
728#endif
729
730#if defined HAVE_FGETLN
731char *NEW(fgetln)(FILE *stream, size_t *len)
732{
733    char *ret;
734#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
735#else
736    struct fuzz *fuzz;
737    size_t i, size;
738#endif
739    int fd;
740
741    LOADSYM(fgetln);
742    LOADSYM(fgetc);
743    fd = fileno(stream);
744    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
745        return ORIG(fgetln)(stream, len);
746
747#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
748    _zz_lock(fd);
749    ret = ORIG(fgetln)(stream, len);
750    _zz_unlock(fd);
751#else
752    fuzz = _zz_getfuzz(fd);
753
754    for(i = size = 0; ; /* i is incremented below */)
755    {
756        int ch;
757
758        _zz_lock(fd);
759        ch = ORIG(fgetc)(stream);
760        _zz_unlock(fd);
761
762        if(ch == EOF)
763            break;
764
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 */
770        _zz_addpos(fd, 1);
771
772        if(fuzz->tmp[i++] == '\n')
773            break;
774    }
775
776    *len = i;
777    ret = fuzz->tmp;
778#endif
779
780    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
781    return ret;
782}
783#endif
784
785#define REFILL(fn, fn_advances) \
786    do \
787    { \
788        int64_t pos; \
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); \
795        pos = _zz_getpos(fd); \
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        { \
802            int already_fuzzed = 0; \
803            if(fn_advances) \
804            { \
805                uint8_t ch = (uint8_t)(unsigned int)ret; \
806                if(newpos != -1) \
807                    _zz_setpos(fd, newpos - fp->FILE_CNT - 1); \
808                already_fuzzed = _zz_getfuzzed(fd); \
809                _zz_fuzz(fd, &ch, 1); \
810                ret = fp->FILE_PTR[-1] = ch; \
811                _zz_setfuzzed(fd, fp->FILE_CNT + 1); \
812                _zz_addpos(fd, 1); \
813            } \
814            else \
815            { \
816                _zz_setfuzzed(fd, fp->FILE_CNT); \
817                if(newpos != -1) \
818                    _zz_setpos(fd, newpos - fp->FILE_CNT); \
819            } \
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); \
826        } \
827        _zz_setpos(fd, pos); /* FIXME: do we always need to do this? */ \
828        debug("%s([%i]) = %i", __func__, fd, ret); \
829    } \
830    while(0)
831
832#if defined HAVE___SREFILL
833int NEW(__srefill)(FILE *fp)
834{
835    int ret; REFILL(__srefill, 0); return ret;
836}
837#endif
838
839#if defined HAVE___SRGET && !defined HAVE___SREFILL
840int NEW(__srget)(FILE *fp)
841{
842    int ret; REFILL(__srget, 1); return ret;
843}
844#endif
845
846#if defined HAVE___FILBUF
847int NEW(__filbuf)(FILE *fp)
848{
849    int ret; REFILL(__filbuf, 1); return ret;
850}
851#endif
852
Note: See TracBrowser for help on using the repository browser.