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

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