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

Last change on this file since 2566 was 2566, checked in by Sam Hocevar, 12 years ago
  • lib-stream.c: only use the srefill trick on OS X. HP-UX is too different.
  • Property svn:keywords set to Id
File size: 21.1 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 2566 2008-07-18 09:28:18Z 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/* Library functions that we divert */
59static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
60#if defined HAVE_FOPEN64
61static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
62#endif
63#if defined HAVE___FOPEN64
64static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
65#endif
66static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
67                                  FILE *stream);
68#if defined HAVE_FREOPEN64
69static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
70                                  FILE *stream);
71#endif
72#if defined HAVE___FREOPEN64
73static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
74                                     FILE *stream);
75#endif
76static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
77#if defined HAVE_FSEEKO
78static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
79#endif
80#if defined HAVE_FSEEKO64
81static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
82#endif
83#if defined HAVE___FSEEKO64
84static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
85#endif
86#if defined HAVE_FSETPOS64
87static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
88#endif
89#if defined HAVE___FSETPOS64
90static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
91#endif
92static void    (*ORIG(rewind))   (FILE *stream);
93static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
94                                  FILE *stream);
95#if defined HAVE_FREAD_UNLOCKED
96static size_t  (*ORIG(fread_unlocked))  (void *ptr, size_t size, size_t nmemb,
97                                         FILE *stream);
98#endif
99static int     (*ORIG(getc))     (FILE *stream);
100static int     (*ORIG(getchar))  (void);
101static int     (*ORIG(fgetc))    (FILE *stream);
102#if defined HAVE__IO_GETC
103static int     (*ORIG(_IO_getc)) (FILE *stream);
104#endif
105#if defined HAVE_GETC_UNLOCKED
106static int     (*ORIG(getc_unlocked))    (FILE *stream);
107#endif
108#if defined HAVE_GETCHAR_UNLOCKED
109static int     (*ORIG(getchar_unlocked)) (void);
110#endif
111#if defined HAVE_FGETC_UNLOCKED
112static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
113#endif
114static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
115#if defined HAVE_FGETS_UNLOCKED
116static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
117#endif
118static int     (*ORIG(ungetc))   (int c, FILE *stream);
119static int     (*ORIG(fclose))   (FILE *fp);
120
121/* Additional GNUisms */
122#if defined HAVE_GETLINE
123static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
124#endif
125#if defined HAVE_GETDELIM
126static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
127                                    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
134/* Additional BSDisms */
135#if defined HAVE_FGETLN
136static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
137#endif
138#if defined HAVE___SREFILL
139int            (*ORIG(__srefill)) (FILE *fp);
140#endif
141
142/* Additional HP-UXisms */
143#if defined HAVE___FILBUF
144int            (*ORIG(__filbuf))  (FILE *fp);
145#endif
146
147/* Our function wrappers */
148#if defined REFILL_ONLY_STDIO /* Fuzz fp if we have __srefill() */
149#   define FOPEN_FUZZ() \
150    _zz_fuzz(fd, ret->FILE_PTR, ret->FILE_CNT)
151#else
152#   define FOPEN_FUZZ()
153#endif
154
155#define FOPEN(fn) \
156    do \
157    { \
158        LOADSYM(fn); \
159        if(!_zz_ready) \
160            return ORIG(fn)(path, mode); \
161        _zz_lock(-1); \
162        ret = ORIG(fn)(path, mode); \
163        _zz_unlock(-1); \
164        if(ret && _zz_mustwatch(path)) \
165        { \
166            int fd = fileno(ret); \
167            _zz_register(fd); \
168            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
169            FOPEN_FUZZ(); \
170        } \
171    } while(0)
172
173FILE *NEW(fopen)(const char *path, const char *mode)
174{
175    FILE *ret; FOPEN(fopen); return ret;
176}
177
178#if defined HAVE_FOPEN64
179FILE *NEW(fopen64)(const char *path, const char *mode)
180{
181    FILE *ret; FOPEN(fopen64); return ret;
182}
183#endif
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#define FREOPEN(fn) \
193    do \
194    { \
195        int fd0 = -1, fd1 = -1, disp = 0; \
196        LOADSYM(fn); \
197        if(_zz_ready && (fd0 = fileno(stream)) >= 0 && _zz_iswatched(fd0)) \
198        { \
199            _zz_unregister(fd0); \
200            disp = 1; \
201        } \
202        _zz_lock(-1); \
203        ret = ORIG(fn)(path, mode, stream); \
204        _zz_unlock(-1); \
205        if(ret && _zz_mustwatch(path)) \
206        { \
207            fd1 = fileno(ret); \
208            _zz_register(fd1); \
209            disp = 1; \
210        } \
211        if(disp) \
212            debug("%s(\"%s\", \"%s\", [%i]) = [%i]", __func__, \
213                  path, mode, fd0, fd1); \
214    } while(0)
215
216FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
217{
218    FILE *ret; FREOPEN(freopen); return ret;
219}
220
221#if defined HAVE_FREOPEN64
222FILE *NEW(freopen64)(const char *path, const char *mode, FILE *stream)
223{
224    FILE *ret; FREOPEN(freopen64); return ret;
225}
226#endif
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 REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
236#   define FSEEK_FUZZ(fn2)
237#else
238#   define FSEEK_FUZZ(fn2) \
239        if(ret == 0) \
240        { \
241            /* FIXME: check what happens when fseek()ing a pipe */ \
242            switch(whence) \
243            { \
244                case SEEK_END: \
245                    offset = fn2(stream); \
246                    /* fall through */ \
247                case SEEK_SET: \
248                    _zz_setpos(fd, offset); \
249                    break; \
250                case SEEK_CUR: \
251                    _zz_addpos(fd, offset); \
252                    break; \
253            } \
254        }
255#endif
256
257#define FSEEK(fn, fn2) \
258    do \
259    { \
260        int fd; \
261        LOADSYM(fn); \
262        fd = fileno(stream); \
263        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
264            return ORIG(fn)(stream, offset, whence); \
265        _zz_lock(fd); \
266        ret = ORIG(fn)(stream, offset, whence); \
267        _zz_unlock(fd); \
268        debug("%s([%i], %lli, %i) = %i", __func__, \
269              fd, (long long int)offset, whence, ret); \
270        FSEEK_FUZZ(fn2) \
271    } while(0)
272
273int NEW(fseek)(FILE *stream, long offset, int whence)
274{
275    int ret; FSEEK(fseek, ftell); return ret;
276}
277
278#if defined HAVE_FSEEKO
279int NEW(fseeko)(FILE *stream, off_t offset, int whence)
280{
281    int ret; FSEEK(fseeko, ftello); return ret;
282}
283#endif
284
285#if defined HAVE_FSEEKO64
286int NEW(fseeko64)(FILE *stream, off64_t offset, int whence)
287{
288    int ret; FSEEK(fseeko64, 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#define FSETPOS(fn) \
300    do \
301    { \
302        int fd; \
303        LOADSYM(fn); \
304        fd = fileno(stream); \
305        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
306            return ORIG(fn)(stream, pos); \
307        _zz_lock(fd); \
308        ret = ORIG(fn)(stream, pos); \
309        _zz_unlock(fd); \
310        debug("%s([%i], %lli) = %i", __func__, \
311              fd, (long long int)FPOS_CAST(*pos), ret); \
312        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
313    } \
314    while(0)
315
316#if defined HAVE_FSETPOS64
317int NEW(fsetpos64)(FILE *stream, const fpos64_t *pos)
318{
319    int ret; FSETPOS(fsetpos64); return ret;
320}
321#endif
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
330void NEW(rewind)(FILE *stream)
331{
332    int fd;
333
334    LOADSYM(rewind);
335    fd = fileno(stream);
336    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
337    {
338        ORIG(rewind)(stream);
339        return;
340    }
341
342    _zz_lock(fd);
343    ORIG(rewind)(stream);
344    _zz_unlock(fd);
345    debug("%s([%i])", __func__, fd);
346
347#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
348#else
349    /* FIXME: check what happens when rewind()ing a pipe */
350    _zz_setpos(fd, 0);
351#endif
352}
353
354#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
355#   define FREAD_FUZZ() \
356    do \
357    { \
358        debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
359              (long int)size, (long int)nmemb, fd, (long int)ret); \
360    } while(0)
361#else
362#   define FREAD_FUZZ() \
363    do \
364    { \
365        int64_t newpos = ftell(stream); \
366        /* XXX: the number of bytes read is not ret * size, because \
367         * a partial read may have advanced the stream pointer. However, \
368         * when reading from a pipe ftell() will return 0, and ret * size \
369         * is then better than nothing. */ \
370        if(newpos <= 0) \
371        { \
372            pos = _zz_getpos(fd); \
373            newpos = pos + ret * size; \
374        } \
375        if(newpos != pos) \
376        { \
377            char *b = ptr; \
378            _zz_fuzz(fd, ptr, newpos - pos); \
379            _zz_setpos(fd, newpos); \
380            if(newpos >= pos + 4) \
381                debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
382                      ptr, (long int)size, (long int)nmemb, fd, \
383                      (long int)ret, b[0], b[1], b[2], b[3]); \
384            else \
385                debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
386                      (long int)size, (long int)nmemb, fd, \
387                      (long int)ret, b[0]); \
388        } \
389        else \
390            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
391                  (long int)size, (long int)nmemb, fd, (long int)ret); \
392    } while(0)
393#endif
394
395#define FREAD(fn) \
396    do \
397    { \
398        int64_t pos; \
399        int fd; \
400        LOADSYM(fn); \
401        fd = fileno(stream); \
402        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
403            return ORIG(fn)(ptr, size, nmemb, stream); \
404        pos = ftell(stream); \
405        _zz_lock(fd); \
406        ret = ORIG(fn)(ptr, size, nmemb, stream); \
407        _zz_unlock(fd); \
408        FREAD_FUZZ(); \
409    } while(0)
410
411size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
412{
413    size_t ret; FREAD(fread); return ret;
414}
415
416#if defined HAVE_FREAD_UNLOCKED
417#undef fread_unlocked /* can be a macro; we don’t want that */
418size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
419{
420    size_t ret; FREAD(fread_unlocked); return ret;
421}
422#endif
423
424#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
425#   define FGETC_FUZZ
426#else
427#   define FGETC_FUZZ \
428        if(ret != EOF) \
429        { \
430            uint8_t ch = ret; \
431            _zz_fuzz(fd, &ch, 1); \
432            _zz_addpos(fd, 1); \
433            ret = ch; \
434        }
435#endif
436
437#define FGETC(fn, s, arg) \
438    do { \
439        int fd; \
440        LOADSYM(fn); \
441        fd = fileno(s); \
442        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
443            return ORIG(fn)(arg); \
444        _zz_lock(fd); \
445        ret = ORIG(fn)(arg); \
446        _zz_unlock(fd); \
447        FGETC_FUZZ \
448        if(ret == EOF) \
449            debug("%s([%i]) = EOF", __func__, fd); \
450        else \
451            debug("%s([%i]) = '%c'", __func__, fd, ret); \
452    } while(0)
453
454#undef getc /* can be a macro; we don’t want that */
455int NEW(getc)(FILE *stream)
456{
457    int ret; FGETC(getc, stream, stream); return ret;
458}
459
460#undef getchar /* can be a macro; we don’t want that */
461int NEW(getchar)(void)
462{
463    int ret; FGETC(getchar, stdin, /* empty */); return ret;
464}
465
466int NEW(fgetc)(FILE *stream)
467{
468    int ret; FGETC(fgetc, stream, stream); return ret;
469}
470
471#if defined HAVE__IO_GETC
472int NEW(_IO_getc)(FILE *stream)
473{
474    int ret; FGETC(_IO_getc, stream, stream); return ret;
475}
476#endif
477
478#if defined HAVE_GETC_UNLOCKED
479#undef getc_unlocked /* can be a macro; we don’t want that */
480int NEW(getc_unlocked)(FILE *stream)
481{
482    int ret; FGETC(getc_unlocked, stream, stream); return ret;
483}
484#endif
485
486#if defined HAVE_GETCHAR_UNLOCKED
487#undef getchar_unlocked /* can be a macro; we don’t want that */
488int NEW(getchar_unlocked)(void)
489{
490    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
491}
492#endif
493
494#if defined HAVE_FGETC_UNLOCKED
495#undef fgetc_unlocked /* can be a macro; we don’t want that */
496int NEW(fgetc_unlocked)(FILE *stream)
497{
498    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
499}
500#endif
501
502#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
503#   define FGETS_FUZZ(fn, fn2) \
504        _zz_lock(fd); \
505        ret = ORIG(fn)(s, size, stream); \
506        _zz_unlock(fd);
507#else
508#   define FGETS_FUZZ(fn, fn2) \
509        if(size <= 0) \
510            ret = NULL; \
511        else if(size == 1) \
512            s[0] = '\0'; \
513        else \
514        { \
515            int i; \
516            for(i = 0; i < size - 1; i++) \
517            { \
518                int ch; \
519                _zz_lock(fd); \
520                ch = ORIG(fn2)(stream); \
521                _zz_unlock(fd); \
522                if(ch == EOF) \
523                { \
524                    s[i] = '\0'; \
525                    if(!i) \
526                        ret = NULL; \
527                    break; \
528                } \
529                s[i] = (char)(unsigned char)ch; \
530                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
531                _zz_addpos(fd, 1); \
532                if(s[i] == '\n') \
533                { \
534                    s[i + 1] = '\0'; \
535                    break; \
536                } \
537            } \
538        }
539#endif
540
541#define FGETS(fn, fn2) \
542    do \
543    { \
544        int fd; \
545        ret = s; \
546        LOADSYM(fn); \
547        LOADSYM(fn2); \
548        fd = fileno(stream); \
549        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
550            return ORIG(fn)(s, size, stream); \
551        FGETS_FUZZ(fn, fn2) \
552        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
553    } while(0)
554
555char *NEW(fgets)(char *s, int size, FILE *stream)
556{
557    char *ret; FGETS(fgets, fgetc); return ret;
558}
559
560#if defined HAVE_FGETS_UNLOCKED
561char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
562{
563    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
564}
565#endif
566
567int NEW(ungetc)(int c, FILE *stream)
568{
569    int ret, fd;
570
571    LOADSYM(ungetc);
572    fd = fileno(stream);
573    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
574        return ORIG(ungetc)(c, stream);
575
576    _zz_lock(fd);
577    ret = ORIG(ungetc)(c, stream);
578    _zz_unlock(fd);
579
580    if(ret != EOF)
581    {
582        struct fuzz *fuzz = _zz_getfuzz(fd);
583        fuzz->uflag = 1;
584        fuzz->upos = _zz_getpos(fd) - 1;
585        fuzz->uchar = c;
586#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
587#else
588        _zz_addpos(fd, -1);
589#endif
590    }
591
592    if(ret == EOF)
593        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
594    else
595        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
596
597    return ret;
598}
599
600int NEW(fclose)(FILE *fp)
601{
602    int ret, fd;
603
604    LOADSYM(fclose);
605    fd = fileno(fp);
606    if(!_zz_ready || !_zz_iswatched(fd))
607        return ORIG(fclose)(fp);
608
609    _zz_lock(fd);
610    ret = ORIG(fclose)(fp);
611    _zz_unlock(fd);
612    debug("%s([%i]) = %i", __func__, fd, ret);
613    _zz_unregister(fd);
614
615    return ret;
616}
617
618#define GETDELIM(fn, delim, need_delim) \
619    do { \
620        char *line; \
621        ssize_t done, size; \
622        int fd, finished = 0; \
623        LOADSYM(fn); \
624        LOADSYM(getdelim); \
625        LOADSYM(fgetc); \
626        fd = fileno(stream); \
627        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
628            return ORIG(getdelim)(lineptr, n, delim, stream); \
629        line = *lineptr; \
630        size = line ? *n : 0; \
631        ret = done = finished = 0; \
632        for(;;) \
633        { \
634            int ch; \
635            if(done >= size) /* highly inefficient but I don't care */ \
636                line = realloc(line, size = done + 1); \
637            if(finished) \
638            { \
639                line[done] = '\0'; \
640                *n = size; \
641                *lineptr = line; \
642                break; \
643            } \
644            _zz_lock(fd); \
645            ch = ORIG(fgetc)(stream); \
646            _zz_unlock(fd); \
647            if(ch == EOF) \
648            { \
649                finished = 1; \
650                ret = done; \
651            } \
652            else \
653            { \
654                unsigned char c = ch; \
655                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
656                line[done++] = c; \
657                _zz_addpos(fd, 1); \
658                if(c == delim) \
659                { \
660                    finished = 1; \
661                    ret = done; \
662                } \
663            } \
664        } \
665        if(need_delim) \
666            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
667                  lineptr, n, delim, fd, (long int)ret); \
668        else \
669            debug("%s(%p, %p, [%i]) = %li", __func__, \
670                  lineptr, n, fd, (long int)ret); \
671        return ret; \
672    } while(0)
673
674#if defined HAVE_GETLINE
675ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
676{
677    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
678}
679#endif
680
681#if defined HAVE_GETDELIM
682ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
683{
684    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
685}
686#endif
687
688#if defined HAVE___GETDELIM
689ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
690{
691    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
692}
693#endif
694
695#if defined HAVE_FGETLN
696char *NEW(fgetln)(FILE *stream, size_t *len)
697{
698    char *ret;
699#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
700#else
701    struct fuzz *fuzz;
702    size_t i, size;
703#endif
704    int fd;
705
706    LOADSYM(fgetln);
707    LOADSYM(fgetc);
708    fd = fileno(stream);
709    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
710        return ORIG(fgetln)(stream, len);
711
712#if defined REFILL_ONLY_STDIO /* Don't fuzz or seek if we have __srefill() */
713    _zz_lock(fd);
714    ret = ORIG(fgetln)(stream, len);
715    _zz_unlock(fd);
716#else
717    fuzz = _zz_getfuzz(fd);
718
719    for(i = size = 0; ; /* i is incremented below */)
720    {
721        int ch;
722
723        _zz_lock(fd);
724        ch = ORIG(fgetc)(stream);
725        _zz_unlock(fd);
726
727        if(ch == EOF)
728            break;
729
730        if(i >= size)
731            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
732
733        fuzz->tmp[i] = (char)(unsigned char)ch;
734        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
735        _zz_addpos(fd, 1);
736
737        if(fuzz->tmp[i++] == '\n')
738            break;
739    }
740
741    *len = i;
742    ret = fuzz->tmp;
743#endif
744
745    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
746    return ret;
747}
748#endif
749
750#if defined HAVE___SREFILL
751int NEW(__srefill)(FILE *fp)
752{
753    off_t newpos;
754    int ret, fd;
755
756    LOADSYM(__srefill);
757    fd = fileno(fp);
758    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
759        return ORIG(__srefill)(fp);
760
761    _zz_lock(fd);
762    ret = ORIG(__srefill)(fp);
763    newpos = lseek(fd, 0, SEEK_CUR);
764    _zz_unlock(fd);
765    if(ret != EOF)
766    {
767        /* FIXME: do we have to fuzz ret, too, like in __filbuf? */
768        if(newpos != -1)
769            _zz_setpos(fd, newpos - fp->_r);
770        _zz_fuzz(fd, fp->_p, fp->_r);
771        _zz_addpos(fd, fp->_r);
772    }
773
774    if(!_zz_islocked(fd))
775        debug("%s([%i]) = %i", __func__, fd, ret);
776
777    return ret;
778}
779#endif
780
781#if defined HAVE___FILBUF
782int NEW(__filbuf)(FILE *fp)
783{
784    off_t newpos;
785    int ret, fd;
786
787    LOADSYM(__filbuf);
788    fd = fileno(fp);
789    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
790        return ORIG(__filbuf)(fp);
791
792    _zz_lock(fd);
793    ret = ORIG(__filbuf)(fp);
794    newpos = lseek(fd, 0, SEEK_CUR);
795    _zz_unlock(fd);
796    if(ret != EOF)
797    {
798        if(newpos != -1)
799            _zz_setpos(fd, newpos - fp->FILE_CNT - 1);
800        _zz_fuzz(fd, fp->FILE_PTR - 1, fp->FILE_CNT + 1);
801        ret = (uint8_t)fp->FILE_PTR[-1];
802        _zz_addpos(fd, fp->FILE_CNT + 1);
803    }
804
805    if(!_zz_islocked(fd))
806        debug("%s([%i]) = %i", __func__, fd, ret);
807
808    return ret;
809}
810#endif
811
Note: See TracBrowser for help on using the repository browser.