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

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