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

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

Revert any potential overriding macro before declaring a new function.

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