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

Last change on this file since 4663 was 4663, checked in by Sam Hocevar, 10 years ago

Remove useless code for Win32 diversions.

  • Property svn:keywords set to Id
File size: 32.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  This program is free software. It comes without any warranty, to
7 *  the extent permitted by applicable law. You can redistribute it
8 *  and/or modify it under the terms of the Do What The Fuck You Want
9 *  To Public License, Version 2, as published by Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
11 */
12
13/*
14 *  load-stream.c: loaded stream functions
15 */
16
17#include "config.h"
18
19/* Needed for getline() and getdelim() */
20#define _GNU_SOURCE
21/* Needed for getc_unlocked() on OpenSolaris */
22#define __EXTENSIONS__
23
24/* Define the best ftell() clone */
25#if defined HAVE_FTELLO64
26#   define ZZ_FTELL ftello64
27#elif defined HAVE___FTELLO64
28#   define ZZ_FTELL __ftello64
29#elif defined HAVE_FTELLO
30#   define ZZ_FTELL ftello
31#else
32#   define ZZ_FTELL ftell
33#endif
34
35#if defined HAVE_STDINT_H
36#   include <stdint.h>
37#elif defined HAVE_INTTYPES_H
38#   include <inttypes.h>
39#endif
40#include <stdlib.h>
41
42#include <stdio.h>
43#include <sys/types.h>
44#if defined HAVE_UNISTD_H
45#   include <unistd.h> /* Needed for __srefill’s lseek() call */
46#endif
47
48#include "common.h"
49#include "libzzuf.h"
50#include "lib-load.h"
51#include "debug.h"
52#include "fuzz.h"
53#include "fd.h"
54
55#if defined HAVE___SREFILL
56#undef __srefill
57int NEW(__srefill)(FILE *fp);
58#endif
59
60#if defined HAVE___FILBUF
61#undef __filbuf
62int NEW(__filbuf)(FILE *fp);
63#endif
64
65#if defined HAVE___SRGET && !defined HAVE___SREFILL
66#undef __srget
67int NEW(__srget)(FILE *fp);
68#endif
69
70#if defined HAVE___UFLOW
71#undef __uflow
72int NEW(__uflow)(FILE *fp);
73#endif
74
75/* Library functions that we divert */
76static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
77#if defined HAVE_FOPEN64
78static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
79#endif
80#if defined HAVE___FOPEN64
81static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
82#endif
83static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
84                                  FILE *stream);
85#if defined HAVE_FREOPEN64
86static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
87                                  FILE *stream);
88#endif
89#if defined HAVE___FREOPEN64
90static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
91                                     FILE *stream);
92#endif
93static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
94#if defined HAVE_FSEEKO
95static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
96#endif
97#if defined HAVE_FSEEKO64
98static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
99#endif
100#if defined HAVE___FSEEKO64
101static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
102#endif
103#if defined HAVE_FSETPOS64
104static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
105#endif
106#if defined HAVE___FSETPOS64
107static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
108#endif
109static void    (*ORIG(rewind))   (FILE *stream);
110static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
111                                  FILE *stream);
112#if defined HAVE_FREAD_UNLOCKED
113static size_t  (*ORIG(fread_unlocked))  (void *ptr, size_t size, size_t nmemb,
114                                         FILE *stream);
115#endif
116#if defined HAVE___FREAD_CHK
117static size_t  (*ORIG(__fread_chk))  (void *ptr, size_t ptrlen, size_t size,
118                                      size_t nmemb, FILE *stream);
119#endif
120#if defined HAVE___FREAD_UNLOCKED_CHK
121static size_t  (*ORIG(__fread_unlocked_chk)) (void *ptr, size_t ptrlen, size_t
122                                              size, size_t nmemb, FILE *stream);
123#endif
124static int     (*ORIG(getc))     (FILE *stream);
125static int     (*ORIG(getchar))  (void);
126static int     (*ORIG(fgetc))    (FILE *stream);
127#if defined HAVE__IO_GETC
128static int     (*ORIG(_IO_getc)) (FILE *stream);
129#endif
130#if defined HAVE_GETC_UNLOCKED
131static int     (*ORIG(getc_unlocked))    (FILE *stream);
132#endif
133#if defined HAVE_GETCHAR_UNLOCKED
134static int     (*ORIG(getchar_unlocked)) (void);
135#endif
136#if defined HAVE_FGETC_UNLOCKED
137static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
138#endif
139static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
140#if defined HAVE_FGETS_UNLOCKED
141static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
142#endif
143#if defined HAVE___FGETS_CHK
144static char *  (*ORIG(__fgets_chk)) (char *s, size_t ptrlen,
145                                     int size, FILE *stream);
146#endif
147#if defined HAVE___FGETS_UNLOCKED_CHK
148static char *  (*ORIG(__fgets_unlocked_chk)) (char *s, size_t ptrlen,
149                                              int size, FILE *stream);
150#endif
151static int     (*ORIG(ungetc))   (int c, FILE *stream);
152static int     (*ORIG(fclose))   (FILE *fp);
153
154/* Additional GNUisms */
155#if defined HAVE_GETLINE
156static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
157#endif
158#if defined HAVE_GETDELIM
159static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
160                                    FILE *stream);
161#endif
162#if defined HAVE___GETDELIM
163static ssize_t (*ORIG(__getdelim)) (char **lineptr, size_t *n, int delim,
164                                    FILE *stream);
165#endif
166#if defined HAVE___UFLOW
167static int     (*ORIG(__uflow))    (FILE *fp);
168#endif
169
170/* Additional BSDisms */
171#if defined HAVE_FGETLN
172static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
173#endif
174#if defined HAVE___SREFILL
175int            (*ORIG(__srefill)) (FILE *fp);
176#endif
177#if defined HAVE___SRGET && !defined HAVE___SREFILL
178int            (*ORIG(__srget))   (FILE *fp);
179#endif
180
181/* Additional HP-UXisms */
182#if defined HAVE___FILBUF
183int            (*ORIG(__filbuf))  (FILE *fp);
184#endif
185
186/* Helper functions for refill-like functions */
187static inline uint8_t *get_stream_ptr(FILE *stream)
188{
189#if defined HAVE_GLIBC_FILE
190    return (uint8_t *)stream->_IO_read_ptr;
191#elif defined HAVE_FREEBSD_FILE
192    return (uint8_t *)stream->_p;
193#elif defined HAVE_SOLARIS_FILE
194    return (uint8_t *)stream->_ptr;
195#else
196    (void)stream;
197    return NULL;
198#endif
199}
200
201static inline int get_stream_off(FILE *stream)
202{
203#if defined HAVE_GLIBC_FILE
204    return (int)((uint8_t *)stream->_IO_read_ptr
205                  - (uint8_t *)stream->_IO_read_base);
206#elif defined HAVE_FREEBSD_FILE
207    return (int)((uint8_t *)stream->_p - (uint8_t *)stream->_bf._base);
208#elif defined HAVE_SOLARIS_FILE
209    return (int)((uint8_t *)stream->_ptr - (uint8_t *)stream->_base);
210#else
211    (void)stream;
212    return 0;
213#endif
214}
215
216static inline int get_stream_cnt(FILE *stream)
217{
218#if defined HAVE_GLIBC_FILE
219    return (int)((uint8_t *)stream->_IO_read_end
220                  - (uint8_t *)stream->_IO_read_ptr);
221#elif defined HAVE_FREEBSD_FILE
222    return stream->_r;
223#elif defined HAVE_SOLARIS_FILE
224    return stream->_cnt;
225#else
226    (void)stream;
227    return 0;
228#endif
229}
230
231static char const *get_seek_mode_name(int mode)
232{
233    /* We don’t use switch/case to avoid duplicate labels */
234    if (mode == SEEK_CUR)
235        return "SEEK_CUR";
236    if (mode == SEEK_SET)
237        return "SEEK_SET";
238    if (mode == SEEK_END)
239        return "SEEK_END";
240    return "SEEK_???";
241}
242
243static inline void debug_stream(char const *prefix, FILE *stream)
244{
245    debug2("... %s: stream([%i], %p, %i + %i)", prefix, fileno(stream),
246           get_stream_ptr(stream), get_stream_off(stream),
247           get_stream_cnt(stream));
248}
249
250/*
251 * fopen, fopen64 etc.
252 * freopen, freopen64 etc.
253 *
254 * Strategy: we call the original function, register the new file descriptor
255 * and immediately fuzz whatever's preloaded in the stream structure.
256 */
257
258#define ZZ_FOPEN(myfopen) \
259    do \
260    { \
261        LOADSYM(myfopen); \
262        if(!_zz_ready) \
263            return ORIG(myfopen)(path, mode); \
264        _zz_lock(-1); \
265        ret = ORIG(myfopen)(path, mode); \
266        _zz_unlock(-1); \
267        if(ret && _zz_mustwatch(path)) \
268        { \
269            int fd = fileno(ret); \
270            _zz_register(fd); \
271            _zz_fuzz(fd, get_stream_ptr(ret), get_stream_cnt(ret)); \
272            debug_stream("after", ret); \
273            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
274        } \
275    } while(0)
276
277#define ZZ_FREOPEN(myfreopen) \
278    do \
279    { \
280        int fd0 = -1, fd1 = -1, disp = 0; \
281        LOADSYM(myfreopen); \
282        if(_zz_ready && (fd0 = fileno(stream)) >= 0 && _zz_iswatched(fd0)) \
283        { \
284            _zz_unregister(fd0); \
285            disp = 1; \
286        } \
287        _zz_lock(-1); \
288        ret = ORIG(myfreopen)(path, mode, stream); \
289        _zz_unlock(-1); \
290        if(ret && _zz_mustwatch(path)) \
291        { \
292            fd1 = fileno(ret); \
293            _zz_register(fd1); \
294            _zz_fuzz(fd1, get_stream_ptr(ret), get_stream_cnt(ret)); \
295            disp = 1; \
296        } \
297        if(disp) \
298            debug("%s(\"%s\", \"%s\", [%i]) = [%i]", __func__, \
299                  path, mode, fd0, fd1); \
300    } while(0)
301
302#undef fopen
303FILE *NEW(fopen)(const char *path, const char *mode)
304{
305    FILE *ret; ZZ_FOPEN(fopen); return ret;
306}
307
308#if defined HAVE_FOPEN64
309#undef fopen64
310FILE *NEW(fopen64)(const char *path, const char *mode)
311{
312    FILE *ret; ZZ_FOPEN(fopen64); return ret;
313}
314#endif
315
316#if defined HAVE___FOPEN64
317#undef __fopen64
318FILE *NEW(__fopen64)(const char *path, const char *mode)
319{
320    FILE *ret; ZZ_FOPEN(__fopen64); return ret;
321}
322#endif
323
324#undef freopen
325FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
326{
327    FILE *ret; ZZ_FREOPEN(freopen); return ret;
328}
329
330#if defined HAVE_FREOPEN64
331#undef freopen64
332FILE *NEW(freopen64)(const char *path, const char *mode, FILE *stream)
333{
334    FILE *ret; ZZ_FREOPEN(freopen64); return ret;
335}
336#endif
337
338#if defined HAVE___FREOPEN64
339#undef __freopen64
340FILE *NEW(__freopen64)(const char *path, const char *mode, FILE *stream)
341{
342    FILE *ret; ZZ_FREOPEN(__freopen64); return ret;
343}
344#endif
345
346/*
347 * fseek, fseeko etc.
348 * fsetpos64, __fsetpos64
349 * rewind
350 *
351 * Strategy: we store the previous file position and internal buffer
352 * status, then call the original function. If the new file position
353 * lies outside the previous internal buffer, it means the buffer has
354 * been invalidated, so we fuzz whatever's preloaded in it.
355 */
356
357#define ZZ_FSEEK(myfseek) \
358    do \
359    { \
360        int64_t oldpos, newpos; \
361        int oldoff, oldcnt; \
362        int fd; \
363        LOADSYM(myfseek); \
364        fd = fileno(stream); \
365        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
366             || _zz_islocked(fd)) \
367            return ORIG(myfseek)(stream, offset, whence); \
368        debug_stream("before", stream); \
369        /* FIXME: ftell() will return -1 on a pipe such as stdin */ \
370        oldpos = ZZ_FTELL(stream); \
371        oldoff = get_stream_off(stream); \
372        oldcnt = get_stream_cnt(stream); \
373        _zz_lock(fd); \
374        ret = ORIG(myfseek)(stream, offset, whence); \
375        _zz_unlock(fd); \
376        newpos = ZZ_FTELL(stream); \
377        if (newpos >= oldpos + oldcnt || newpos < oldpos - oldoff) \
378        { \
379            _zz_setpos(fd, newpos - get_stream_off(stream)); \
380            _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
381                         get_stream_cnt(stream) + get_stream_off(stream)); \
382        } \
383        _zz_setpos(fd, newpos); \
384        debug_stream("after", stream); \
385        debug("%s([%i], %lli, %s) = %i", __func__, \
386              fd, (long long int)offset, get_seek_mode_name(whence), ret); \
387    } while(0)
388
389#define ZZ_FSETPOS(myfsetpos) \
390    do \
391    { \
392        int64_t oldpos, newpos; \
393        int oldoff, oldcnt; \
394        int fd; \
395        LOADSYM(myfsetpos); \
396        fd = fileno(stream); \
397        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
398             || _zz_islocked(fd)) \
399            return ORIG(myfsetpos)(stream, pos); \
400        debug_stream("before", stream); \
401        /* FIXME: ftell() will return -1 on a pipe such as stdin */ \
402        oldpos = ZZ_FTELL(stream); \
403        oldoff = get_stream_off(stream); \
404        oldcnt = get_stream_cnt(stream); \
405        _zz_lock(fd); \
406        ret = ORIG(myfsetpos)(stream, pos); \
407        _zz_unlock(fd); \
408        newpos = ZZ_FTELL(stream); \
409        if (newpos >= oldpos + oldcnt || newpos < oldpos - oldoff) \
410        { \
411            _zz_setpos(fd, newpos - get_stream_off(stream)); \
412            _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
413                         get_stream_cnt(stream) + get_stream_off(stream)); \
414        } \
415        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
416        debug_stream("after", stream); \
417        debug("%s([%i], %lli) = %i", __func__, \
418              fd, (long long int)FPOS_CAST(*pos), ret); \
419    } \
420    while(0)
421
422#define ZZ_REWIND(myrewind) \
423    do \
424    { \
425        int64_t oldpos, newpos; \
426        int oldoff, oldcnt; \
427        int fd; \
428        LOADSYM(rewind); \
429        fd = fileno(stream); \
430        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
431             || _zz_islocked(fd)) \
432            return ORIG(rewind)(stream); \
433        debug_stream("before", stream); \
434        /* FIXME: ftell() will return -1 on a pipe such as stdin */ \
435        oldpos = ZZ_FTELL(stream); \
436        oldoff = get_stream_off(stream); \
437        oldcnt = get_stream_cnt(stream); \
438        _zz_lock(fd); \
439        ORIG(rewind)(stream); \
440        _zz_unlock(fd); \
441        newpos = ZZ_FTELL(stream); \
442        if (newpos >= oldpos + oldcnt || newpos < oldpos - oldoff) \
443        { \
444            _zz_setpos(fd, newpos - get_stream_off(stream)); \
445            _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
446                         get_stream_cnt(stream) + get_stream_off(stream)); \
447        } \
448        _zz_setpos(fd, newpos); \
449        debug_stream("after", stream); \
450        debug("%s([%i])", __func__, fd); \
451    } while(0)
452
453#undef fseek
454int NEW(fseek)(FILE *stream, long offset, int whence)
455{
456    int ret; ZZ_FSEEK(fseek); return ret;
457}
458
459#if defined HAVE_FSEEKO
460#undef fseeko
461int NEW(fseeko)(FILE *stream, off_t offset, int whence)
462{
463    int ret; ZZ_FSEEK(fseeko); return ret;
464}
465#endif
466
467#if defined HAVE_FSEEKO64
468#undef fseeko64
469int NEW(fseeko64)(FILE *stream, off64_t offset, int whence)
470{
471    int ret; ZZ_FSEEK(fseeko64); return ret;
472}
473#endif
474
475#if defined HAVE___FSEEKO64
476#undef __fseeko64
477int NEW(__fseeko64)(FILE *stream, off64_t offset, int whence)
478{
479    int ret; ZZ_FSEEK(__fseeko64); return ret;
480}
481#endif
482
483#if defined HAVE_FSETPOS64
484#undef fsetpos64
485int NEW(fsetpos64)(FILE *stream, const fpos64_t *pos)
486{
487    int ret; ZZ_FSETPOS(fsetpos64); return ret;
488}
489#endif
490
491#if defined HAVE___FSETPOS64
492#undef __fsetpos64
493int NEW(__fsetpos64)(FILE *stream, const fpos64_t *pos)
494{
495    int ret; ZZ_FSETPOS(__fsetpos64); return ret;
496}
497#endif
498
499#undef rewind
500void NEW(rewind)(FILE *stream)
501{
502    ZZ_REWIND(rewind);
503}
504
505/*
506 * fread, fread_unlocked
507 *
508 * Strategy: we store the previous file position and internal buffer
509 * status, then call the original function. If the new file position
510 * lies outside the previous internal buffer, it means the buffer has
511 * been invalidated, so we fuzz whatever's preloaded in it.
512 */
513
514#define ZZ_FREAD(myfread, myargs) /* NEW */ \
515    do \
516    { \
517        int64_t oldpos, newpos; \
518        uint8_t *b = ptr;\
519        int oldoff, oldcnt; \
520        int fd; \
521        LOADSYM(myfread); \
522        fd = fileno(stream); \
523        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
524             || _zz_islocked(fd)) \
525            return ORIG(myfread) myargs; \
526        debug_stream("before", stream); \
527        /* FIXME: ftell() will return -1 on a pipe such as stdin */ \
528        oldpos = ZZ_FTELL(stream); \
529        oldoff = get_stream_off(stream); \
530        oldcnt = get_stream_cnt(stream); \
531        _zz_lock(fd); \
532        ret = ORIG(myfread) myargs; \
533        _zz_unlock(fd); \
534        newpos = ZZ_FTELL(stream); \
535        if (newpos >= oldpos + oldcnt) \
536        { \
537            /* Fuzz returned data that wasn't in the old internal buffer */ \
538            _zz_setpos(fd, oldpos + oldcnt); \
539            _zz_fuzz(fd, b + oldcnt, newpos - oldpos - oldcnt); \
540            /* Fuzz the internal stream buffer */ \
541            _zz_setpos(fd, newpos - get_stream_off(stream)); \
542            _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
543                         get_stream_cnt(stream) + get_stream_off(stream)); \
544        } \
545        _zz_setpos(fd, newpos); \
546        debug_stream("after", stream); \
547        if (newpos >= oldpos + 4) \
548            debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
549                  ptr, (long int)size, (long int)nmemb, fd, \
550                  (long int)ret, b[0], b[1], b[2], b[3]); \
551        else if (newpos > oldpos) \
552            debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
553                  (long int)size, (long int)nmemb, fd, \
554                  (long int)ret, b[0]); \
555        else \
556            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
557                  (long int)size, (long int)nmemb, fd, (long int)ret); \
558    } while(0)
559
560#undef fread
561size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
562{
563    size_t ret; ZZ_FREAD(fread, (ptr, size, nmemb, stream)); return ret;
564}
565
566#if defined HAVE_FREAD_UNLOCKED
567#undef fread_unlocked
568size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
569{
570    size_t ret;
571    ZZ_FREAD(fread_unlocked, (ptr, size, nmemb, stream));
572    return ret;
573}
574#endif
575
576#if defined HAVE___FREAD_CHK
577#undef __fread_chk
578size_t NEW(__fread_chk)(void *ptr, size_t ptrlen, size_t size, size_t nmemb,
579                        FILE *stream)
580{
581    size_t ret;
582    ZZ_FREAD(__fread_chk, (ptr, ptrlen, size, nmemb, stream));
583    return ret;
584}
585#endif
586
587#if defined HAVE___FREAD_UNLOCKED_CHK
588#undef __fread_unlocked_chk
589size_t NEW(__fread_unlocked_chk)(void *ptr, size_t ptrlen, size_t size,
590                                 size_t nmemb, FILE *stream)
591{
592    size_t ret;
593    ZZ_FREAD(__fread_unlocked_chk, (ptr, ptrlen, size, nmemb, stream));
594    return ret;
595}
596#endif
597
598/*
599 * getc, getchar, fgetc etc.
600 *
601 * Strategy: we store the previous file position and internal buffer
602 * status, then call the original function. If the new file position
603 * lies outside the previous internal buffer, it means the buffer has
604 * been invalidated, so we fuzz whatever's preloaded in it.
605 */
606
607#define ZZ_FGETC(myfgetc, s, arg) \
608    do { \
609        int64_t oldpos, newpos; \
610        int oldoff, oldcnt; \
611        int fd; \
612        LOADSYM(myfgetc); \
613        fd = fileno(s); \
614        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
615             || _zz_islocked(fd)) \
616            return ORIG(myfgetc)(arg); \
617        debug_stream("before", s); \
618        oldpos = ZZ_FTELL(s); \
619        oldoff = get_stream_off(s); \
620        oldcnt = get_stream_cnt(s); \
621        _zz_lock(fd); \
622        ret = ORIG(myfgetc)(arg); \
623        _zz_unlock(fd); \
624        newpos = ZZ_FTELL(s); \
625        if (oldcnt == 0 && ret != EOF) \
626        { \
627            /* Fuzz returned data that wasn't in the old internal buffer */ \
628            uint8_t ch = ret; \
629            _zz_setpos(fd, oldpos); \
630            _zz_fuzz(fd, &ch, 1); \
631            ret = ch; \
632        } \
633        if (newpos >= oldpos + oldcnt) \
634        { \
635            /* Fuzz the internal stream buffer */ \
636            _zz_setpos(fd, newpos - get_stream_off(s)); \
637            _zz_fuzz(fd, get_stream_ptr(s) - get_stream_off(s), \
638                         get_stream_cnt(s) + get_stream_off(s)); \
639        } \
640        _zz_setpos(fd, newpos); \
641        debug_stream("after", s); \
642        if(ret == EOF) \
643            debug("%s([%i]) = EOF", __func__, fd); \
644        else \
645            debug("%s([%i]) = '%c'", __func__, fd, ret); \
646    } while(0)
647
648#undef getc
649int NEW(getc)(FILE *stream)
650{
651    int ret; ZZ_FGETC(getc, stream, stream); return ret;
652}
653
654#undef getchar
655int NEW(getchar)(void)
656{
657    int ret; ZZ_FGETC(getchar, stdin, /* empty */); return ret;
658}
659
660#undef fgetc
661int NEW(fgetc)(FILE *stream)
662{
663    int ret; ZZ_FGETC(fgetc, stream, stream); return ret;
664}
665
666#if defined HAVE__IO_GETC
667#undef _IO_fgetc
668int NEW(_IO_getc)(FILE *stream)
669{
670    int ret; ZZ_FGETC(_IO_getc, stream, stream); return ret;
671}
672#endif
673
674#if defined HAVE_GETC_UNLOCKED
675#undef getc_unlocked
676int NEW(getc_unlocked)(FILE *stream)
677{
678    int ret; ZZ_FGETC(getc_unlocked, stream, stream); return ret;
679}
680#endif
681
682#if defined HAVE_GETCHAR_UNLOCKED
683#undef getchar_unlocked
684int NEW(getchar_unlocked)(void)
685{
686    int ret; ZZ_FGETC(getchar_unlocked, stdin, /* empty */); return ret;
687}
688#endif
689
690#if defined HAVE_FGETC_UNLOCKED
691#undef fgetc_unlocked
692int NEW(fgetc_unlocked)(FILE *stream)
693{
694    int ret; ZZ_FGETC(fgetc_unlocked, stream, stream); return ret;
695}
696#endif
697
698/*
699 * fgets, fgets_unlocked
700 */
701
702#define ZZ_FGETS(myfgets, myfgetc, myargs) \
703    do \
704    { \
705        int64_t oldpos, newpos; \
706        int oldoff, oldcnt; \
707        int fd; \
708        ret = s; \
709        LOADSYM(myfgets); \
710        LOADSYM(myfgetc); \
711        fd = fileno(stream); \
712        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
713             || _zz_islocked(fd)) \
714            return ORIG(myfgets) myargs; \
715        debug_stream("before", stream); \
716        oldpos = ZZ_FTELL(stream); \
717        oldoff = get_stream_off(stream); \
718        oldcnt = get_stream_cnt(stream); \
719        newpos = oldpos; \
720        if(size <= 0) \
721            ret = NULL; \
722        else if(size == 1) \
723            s[0] = '\0'; \
724        else \
725        { \
726            int i; \
727            for(i = 0; i < size - 1; i++) \
728            { \
729                int chr; \
730                _zz_lock(fd); \
731                chr = ORIG(myfgetc)(stream); \
732                _zz_unlock(fd); \
733                newpos = oldpos + 1; \
734                if (oldcnt == 0 && chr != EOF) \
735                { \
736                    /* Fuzz returned data that wasn't in the old buffer */ \
737                    uint8_t ch = chr; \
738                    _zz_setpos(fd, oldpos); \
739                    _zz_fuzz(fd, &ch, 1); \
740                    chr = ch; \
741                } \
742                if (newpos >= oldpos + oldcnt) \
743                { \
744                    /* Fuzz the internal stream buffer, if necessary */ \
745                    _zz_setpos(fd, newpos - get_stream_off(stream)); \
746                    _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
747                                 get_stream_cnt(stream) + get_stream_off(stream)); \
748                } \
749                oldpos = newpos; \
750                oldoff = get_stream_off(stream); \
751                oldcnt = get_stream_cnt(stream); \
752                if(chr == EOF) \
753                { \
754                    s[i] = '\0'; \
755                    if(!i) \
756                        ret = NULL; \
757                    break; \
758                } \
759                s[i] = (char)(unsigned char)chr; \
760                if(s[i] == '\n') \
761                { \
762                    s[i + 1] = '\0'; \
763                    break; \
764                } \
765            } \
766        } \
767        _zz_setpos(fd, newpos); \
768        debug_stream("after", stream); \
769        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
770    } while(0)
771
772#undef fgets
773char *NEW(fgets)(char *s, int size, FILE *stream)
774{
775    char *ret; ZZ_FGETS(fgets, fgetc, (s, size, stream)); return ret;
776}
777
778#if defined HAVE_FGETS_UNLOCKED
779#undef fgets_unlocked
780char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
781{
782    char *ret;
783    ZZ_FGETS(fgets_unlocked, fgetc_unlocked, (s, size, stream));
784    return ret;
785}
786#endif
787
788#if defined HAVE___FGETS_CHK
789#undef __fgets_chk
790char *NEW(__fgets_chk)(char *s, size_t ptrlen, int size, FILE *stream)
791{
792    char *ret;
793    ZZ_FGETS(__fgets_chk, fgetc, (s, ptrlen, size, stream));
794    return ret;
795}
796#endif
797
798#if defined HAVE___FGETS_UNLOCKED_CHK
799#undef __fgets_unlocked_chk
800char *NEW(__fgets_unlocked_chk)(char *s, size_t ptrlen, int size, FILE *stream)
801{
802    char *ret;
803    ZZ_FGETS(__fgets_unlocked_chk, fgetc_unlocked, (s, ptrlen, size, stream));
804    return ret;
805}
806#endif
807
808/*
809 * ungetc
810 */
811
812#undef ungetc
813int NEW(ungetc)(int c, FILE *stream)
814{
815    int oldpos, ret, fd;
816
817    LOADSYM(ungetc);
818    fd = fileno(stream);
819    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)
820         || _zz_islocked(fd))
821        return ORIG(ungetc)(c, stream);
822
823    debug_stream("before", stream);
824    oldpos = ZZ_FTELL(stream);
825    _zz_lock(fd);
826    ret = ORIG(ungetc)(c, stream);
827    _zz_unlock(fd);
828    _zz_setpos(fd, oldpos - 1);
829
830    debug_stream("after", stream);
831    if(ret == EOF)
832        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
833    else
834        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
835    return ret;
836}
837
838/*
839 * fclose
840 */
841
842#undef fclose
843int NEW(fclose)(FILE *fp)
844{
845    int ret, fd;
846
847    LOADSYM(fclose);
848    fd = fileno(fp);
849    if(!_zz_ready || !_zz_iswatched(fd))
850        return ORIG(fclose)(fp);
851
852    debug_stream("before", fp);
853    _zz_lock(fd);
854    ret = ORIG(fclose)(fp);
855    _zz_unlock(fd);
856    debug("%s([%i]) = %i", __func__, fd, ret);
857    _zz_unregister(fd);
858
859    return ret;
860}
861
862/*
863 * getline, getdelim etc.
864 */
865
866#define ZZ_GETDELIM(mygetdelim, delim, need_delim) \
867    do { \
868        int64_t oldpos, newpos; \
869        char *line; \
870        ssize_t done, size; \
871        int oldoff, oldcnt; \
872        int fd, finished = 0; \
873        LOADSYM(mygetdelim); \
874        LOADSYM(getdelim); \
875        LOADSYM(fgetc); \
876        fd = fileno(stream); \
877        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
878             || _zz_islocked(fd)) \
879            return ORIG(getdelim)(lineptr, n, delim, stream); \
880        debug_stream("before", stream); \
881        oldpos = ZZ_FTELL(stream); \
882        oldoff = get_stream_off(stream); \
883        oldcnt = get_stream_cnt(stream); \
884        newpos = oldpos; \
885        line = *lineptr; \
886        size = line ? *n : 0; \
887        ret = done = finished = 0; \
888        for(;;) \
889        { \
890            int chr; \
891            if(done >= size) /* highly inefficient but I don't care */ \
892                line = realloc(line, size = done + 1); \
893            if(finished) \
894            { \
895                line[done] = '\0'; \
896                *n = size; \
897                *lineptr = line; \
898                break; \
899            } \
900            _zz_lock(fd); \
901            chr = ORIG(fgetc)(stream); \
902            _zz_unlock(fd); \
903            newpos = oldpos + 1; \
904            if (oldcnt == 0 && chr != EOF) \
905            { \
906                /* Fuzz returned data that wasn't in the old buffer */ \
907                uint8_t ch = chr; \
908                _zz_setpos(fd, oldpos); \
909                _zz_fuzz(fd, &ch, 1); \
910                chr = ch; \
911            } \
912            if (newpos >= oldpos + oldcnt) \
913            { \
914                /* Fuzz the internal stream buffer, if necessary */ \
915                _zz_setpos(fd, newpos - get_stream_off(stream)); \
916                _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream), \
917                             get_stream_cnt(stream) + get_stream_off(stream)); \
918            } \
919            oldpos = newpos; \
920            oldoff = get_stream_off(stream); \
921            oldcnt = get_stream_cnt(stream); \
922            if(chr == EOF) \
923            { \
924                finished = 1; \
925                ret = done ? done : -1; \
926            } \
927            else \
928            { \
929                unsigned char c = chr; \
930                line[done++] = c; \
931                if(c == delim) \
932                { \
933                    finished = 1; \
934                    ret = done; \
935                } \
936            } \
937        } \
938        _zz_setpos(fd, newpos); \
939        debug_stream("after", stream); \
940        if(need_delim) \
941            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
942                  lineptr, n, delim, fd, (long int)ret); \
943        else \
944            debug("%s(%p, %p, [%i]) = %li", __func__, \
945                  lineptr, n, fd, (long int)ret); \
946        break; \
947    } while(0)
948
949#if defined HAVE_GETLINE
950#undef getline
951ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
952{
953    ssize_t ret; ZZ_GETDELIM(getline, '\n', 0); return ret;
954}
955#endif
956
957#if defined HAVE_GETDELIM
958#undef getdelim
959ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
960{
961    ssize_t ret; ZZ_GETDELIM(getdelim, delim, 1); return ret;
962}
963#endif
964
965#if defined HAVE___GETDELIM
966#undef __getdelim
967ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
968{
969    ssize_t ret; ZZ_GETDELIM(__getdelim, delim, 1); return ret;
970}
971#endif
972
973/*
974 * fgetln
975 */
976
977#if defined HAVE_FGETLN
978#undef fgetln
979char *NEW(fgetln)(FILE *stream, size_t *len)
980{
981    int64_t oldpos, newpos;
982    char *ret;
983    struct fuzz *fuzz;
984    size_t i, size;
985    int oldoff, oldcnt, fd;
986
987    LOADSYM(fgetln);
988    LOADSYM(fgetc);
989    fd = fileno(stream);
990    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)
991         || _zz_islocked(fd))
992        return ORIG(fgetln)(stream, len);
993
994    debug_stream("before", stream);
995    oldpos = ZZ_FTELL(stream);
996    oldoff = get_stream_off(stream);
997    oldcnt = get_stream_cnt(stream);
998    newpos = oldpos;
999
1000    fuzz = _zz_getfuzz(fd);
1001
1002    for(i = size = 0; ; /* i is incremented below */)
1003    {
1004        int chr;
1005
1006        _zz_lock(fd);
1007        chr = ORIG(fgetc)(stream);
1008        _zz_unlock(fd);
1009
1010        newpos = oldpos + 1;
1011        if (oldcnt == 0 && chr != EOF)
1012        {
1013            /* Fuzz returned data that wasn't in the old buffer */
1014            uint8_t ch = chr;
1015            _zz_setpos(fd, oldpos);
1016            _zz_fuzz(fd, &ch, 1);
1017            chr = ch;
1018        }
1019        if (newpos >= oldpos + oldcnt)
1020        {
1021            /* Fuzz the internal stream buffer, if necessary */
1022            _zz_setpos(fd, newpos - get_stream_off(stream));
1023            _zz_fuzz(fd, get_stream_ptr(stream) - get_stream_off(stream),
1024                         get_stream_cnt(stream) + get_stream_off(stream));
1025        }
1026        oldpos = newpos;
1027        oldoff = get_stream_off(stream);
1028        oldcnt = get_stream_cnt(stream);
1029
1030        if(chr == EOF)
1031            break;
1032
1033        if(i >= size)
1034            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
1035
1036        fuzz->tmp[i] = (char)(unsigned char)chr;
1037
1038        if(fuzz->tmp[i++] == '\n')
1039            break;
1040    }
1041
1042    *len = i;
1043    ret = fuzz->tmp;
1044
1045    debug_stream("after", stream);
1046    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
1047    return ret;
1048}
1049#endif
1050
1051/*
1052 * __srefill, __filbuf, __srget, __uflow
1053 */
1054
1055#if defined HAVE___UFLOW
1056#   define REFILL_RETURNS_INT 0
1057#else
1058#   define REFILL_RETURNS_INT 1
1059#endif
1060
1061#define ZZ_REFILL(myrefill, fn_advances) \
1062    do \
1063    { \
1064        int64_t pos; \
1065        off_t newpos; \
1066        int fd; \
1067        LOADSYM(myrefill); \
1068        fd = fileno(fp); \
1069        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd) \
1070             || _zz_islocked(fd)) \
1071            return ORIG(myrefill)(fp); \
1072        debug_stream("before", fp); \
1073        pos = _zz_getpos(fd); \
1074        _zz_lock(fd); \
1075        ret = ORIG(myrefill)(fp); \
1076        newpos = lseek(fd, 0, SEEK_CUR); \
1077        _zz_unlock(fd); \
1078        if(ret != EOF) \
1079        { \
1080            int already_fuzzed = 0; \
1081            if(fn_advances) \
1082            { \
1083                uint8_t ch = (uint8_t)(unsigned int)ret; \
1084                if(newpos != -1) \
1085                    _zz_setpos(fd, newpos - get_stream_cnt(fp) - 1); \
1086                already_fuzzed = _zz_getfuzzed(fd); \
1087                _zz_fuzz(fd, &ch, 1); \
1088                ret = get_stream_ptr(fp)[-1] = ch; \
1089                _zz_setfuzzed(fd, get_stream_cnt(fp) + 1); \
1090                _zz_addpos(fd, 1); \
1091            } \
1092            else \
1093            { \
1094                _zz_setfuzzed(fd, get_stream_cnt(fp)); \
1095                if(newpos != -1) \
1096                    _zz_setpos(fd, newpos - get_stream_cnt(fp)); \
1097            } \
1098            if(get_stream_cnt(fp) > already_fuzzed) \
1099            { \
1100                _zz_addpos(fd, already_fuzzed); \
1101                _zz_fuzz(fd, get_stream_ptr(fp), \
1102                             get_stream_cnt(fp) - already_fuzzed); \
1103            } \
1104            _zz_addpos(fd, get_stream_cnt(fp) - already_fuzzed); \
1105        } \
1106        _zz_setpos(fd, pos); /* FIXME: do we always need to do this? */ \
1107        debug_stream("after", fp); \
1108        if (REFILL_RETURNS_INT) \
1109            debug("%s([%i]) = %i", __func__, fd, ret); \
1110        else if (ret == EOF) \
1111            debug("%s([%i]) = EOF", __func__, fd); \
1112        else \
1113            debug("%s([%i]) = '%c'", __func__, fd, ret); \
1114    } \
1115    while(0)
1116
1117#if defined HAVE___SREFILL
1118#undef __srefill
1119int NEW(__srefill)(FILE *fp)
1120{
1121    int ret; ZZ_REFILL(__srefill, 0); return ret;
1122}
1123#endif
1124
1125#if defined HAVE___SRGET && !defined HAVE___SREFILL
1126#undef __srget
1127int NEW(__srget)(FILE *fp)
1128{
1129    int ret; ZZ_REFILL(__srget, 1); return ret;
1130}
1131#endif
1132
1133#if defined HAVE___FILBUF
1134#undef __filbuf
1135int NEW(__filbuf)(FILE *fp)
1136{
1137    int ret; ZZ_REFILL(__filbuf, 1); return ret;
1138}
1139#endif
1140
1141#if defined HAVE___UFLOW
1142#undef __uflow
1143int NEW(__uflow)(FILE *fp)
1144{
1145    int ret; ZZ_REFILL(__uflow, 1); return ret;
1146}
1147#endif
Note: See TracBrowser for help on using the repository browser.