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

Last change on this file since 2570 was 2570, checked in by Sam Hocevar, 12 years ago
  • lib-stream.c: the BSDs' refill function is slightly different from the HP-UX and Solaris ones; fixing our implementation accordinly.
  • Property svn:keywords set to Id
File size: 21.3 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 2570 2008-07-20 01:22:46Z 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
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
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 REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
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)
368#else
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; \
385            _zz_setpos(fd, pos); \
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)
401#endif
402
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)
418
419size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
420{
421    size_t ret; FREAD(fread); return ret;
422}
423
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}
430#endif
431
432#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
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
445#define FGETC(fn, s, arg) \
446    do { \
447        int fd; \
448        LOADSYM(fn); \
449        fd = fileno(s); \
450        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
451            return ORIG(fn)(arg); \
452        _zz_lock(fd); \
453        ret = ORIG(fn)(arg); \
454        _zz_unlock(fd); \
455        FGETC_FUZZ \
456        if(ret == EOF) \
457            debug("%s([%i]) = EOF", __func__, fd); \
458        else \
459            debug("%s([%i]) = '%c'", __func__, fd, ret); \
460    } while(0)
461
462#undef getc /* can be a macro; we don’t want that */
463int NEW(getc)(FILE *stream)
464{
465    int ret; FGETC(getc, stream, stream); return ret;
466}
467
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
474int NEW(fgetc)(FILE *stream)
475{
476    int ret; FGETC(fgetc, stream, stream); return ret;
477}
478
479#if defined HAVE__IO_GETC
480int NEW(_IO_getc)(FILE *stream)
481{
482    int ret; FGETC(_IO_getc, stream, stream); return ret;
483}
484#endif
485
486#if defined HAVE_GETC_UNLOCKED
487#undef getc_unlocked /* can be a macro; we don’t want that */
488int NEW(getc_unlocked)(FILE *stream)
489{
490    int ret; FGETC(getc_unlocked, stream, stream); return ret;
491}
492#endif
493
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
502#if defined HAVE_FGETC_UNLOCKED
503#undef fgetc_unlocked /* can be a macro; we don’t want that */
504int NEW(fgetc_unlocked)(FILE *stream)
505{
506    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
507}
508#endif
509
510#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
511#   define FGETS_FUZZ(fn, fn2) \
512        _zz_lock(fd); \
513        ret = ORIG(fn)(s, size, stream); \
514        _zz_unlock(fd);
515#else
516#   define FGETS_FUZZ(fn, fn2) \
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); \
528                ch = ORIG(fn2)(stream); \
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
548
549#define FGETS(fn, fn2) \
550    do \
551    { \
552        int fd; \
553        ret = s; \
554        LOADSYM(fn); \
555        LOADSYM(fn2); \
556        fd = fileno(stream); \
557        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
558            return ORIG(fn)(s, size, stream); \
559        FGETS_FUZZ(fn, fn2) \
560        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
561    } while(0)
562
563char *NEW(fgets)(char *s, int size, FILE *stream)
564{
565    char *ret; FGETS(fgets, fgetc); return ret;
566}
567
568#if defined HAVE_FGETS_UNLOCKED
569char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
570{
571    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
572}
573#endif
574
575int NEW(ungetc)(int c, FILE *stream)
576{
577    int ret, fd;
578
579    LOADSYM(ungetc);
580    fd = fileno(stream);
581    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
582        return ORIG(ungetc)(c, stream);
583
584    _zz_lock(fd);
585    ret = ORIG(ungetc)(c, stream);
586    _zz_unlock(fd);
587
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;
594#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
595#else
596        _zz_addpos(fd, -1);
597#endif
598    }
599
600    if(ret == EOF)
601        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
602    else
603        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
604
605    return ret;
606}
607
608int NEW(fclose)(FILE *fp)
609{
610    int ret, fd;
611
612    LOADSYM(fclose);
613    fd = fileno(fp);
614    if(!_zz_ready || !_zz_iswatched(fd))
615        return ORIG(fclose)(fp);
616
617    _zz_lock(fd);
618    ret = ORIG(fclose)(fp);
619    _zz_unlock(fd);
620    debug("%s([%i]) = %i", __func__, fd, ret);
621    _zz_unregister(fd);
622
623    return ret;
624}
625
626#define GETDELIM(fn, delim, need_delim) \
627    do { \
628        char *line; \
629        ssize_t done, size; \
630        int fd, finished = 0; \
631        LOADSYM(fn); \
632        LOADSYM(getdelim); \
633        LOADSYM(fgetc); \
634        fd = fileno(stream); \
635        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
636            return ORIG(getdelim)(lineptr, n, delim, stream); \
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            } \
652            _zz_lock(fd); \
653            ch = ORIG(fgetc)(stream); \
654            _zz_unlock(fd); \
655            if(ch == EOF) \
656            { \
657                finished = 1; \
658                ret = done; \
659            } \
660            else \
661            { \
662                unsigned char c = ch; \
663                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
664                line[done++] = c; \
665                _zz_addpos(fd, 1); \
666                if(c == delim) \
667                { \
668                    finished = 1; \
669                    ret = done; \
670                } \
671            } \
672        } \
673        if(need_delim) \
674            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
675                  lineptr, n, delim, fd, (long int)ret); \
676        else \
677            debug("%s(%p, %p, [%i]) = %li", __func__, \
678                  lineptr, n, fd, (long int)ret); \
679        return ret; \
680    } while(0)
681
682#if defined HAVE_GETLINE
683ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
684{
685    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
686}
687#endif
688
689#if defined HAVE_GETDELIM
690ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
691{
692    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
693}
694#endif
695
696#if defined HAVE___GETDELIM
697ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
698{
699    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
700}
701#endif
702
703#if defined HAVE_FGETLN
704char *NEW(fgetln)(FILE *stream, size_t *len)
705{
706    char *ret;
707#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
708#else
709    struct fuzz *fuzz;
710    size_t i, size;
711#endif
712    int fd;
713
714    LOADSYM(fgetln);
715    LOADSYM(fgetc);
716    fd = fileno(stream);
717    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
718        return ORIG(fgetln)(stream, len);
719
720#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
721    _zz_lock(fd);
722    ret = ORIG(fgetln)(stream, len);
723    _zz_unlock(fd);
724#else
725    fuzz = _zz_getfuzz(fd);
726
727    for(i = size = 0; ; /* i is incremented below */)
728    {
729        int ch;
730
731        _zz_lock(fd);
732        ch = ORIG(fgetc)(stream);
733        _zz_unlock(fd);
734
735        if(ch == EOF)
736            break;
737
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 */
743        _zz_addpos(fd, 1);
744
745        if(fuzz->tmp[i++] == '\n')
746            break;
747    }
748
749    *len = i;
750    ret = fuzz->tmp;
751#endif
752
753    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
754    return ret;
755}
756#endif
757
758#define REFILL(fn, fn_advances) \
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        { \
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 \
783                ret = ((uint8_t *)fp->FILE_PTR)[0]; \
784            _zz_fuzz(fd, fp->FILE_PTR, fp->FILE_CNT); \
785            _zz_addpos(fd, fp->FILE_CNT); \
786        } \
787        if(!_zz_islocked(fd)) \
788            debug("%s([%i]) = %i", __func__, fd, ret); \
789    } \
790    while(0)
791
792#if defined HAVE___SREFILL
793int NEW(__srefill)(FILE *fp)
794{
795    int ret; REFILL(__srefill, 0); return ret;
796}
797#endif
798
799#if defined HAVE___SRGET
800int NEW(__srget)(FILE *fp)
801{
802    int ret; REFILL(__srget, 1); return ret;
803}
804#endif
805
806#if defined HAVE___FILBUF
807int NEW(__filbuf)(FILE *fp)
808{
809    int ret; REFILL(__filbuf, 1); return ret;
810}
811#endif
812
Note: See TracBrowser for help on using the repository browser.