diff options
| author | Lloyd Hilaiel <lloyd@hilaiel.com> | 2009-04-01 18:05:07 +0300 |
|---|---|---|
| committer | Lloyd Hilaiel <lloyd@hilaiel.com> | 2009-04-01 18:05:07 +0300 |
| commit | b78dd790825e3347422ef8ac56d2ad557a473e8f (patch) | |
| tree | e1caa8c32bad3281b704d334b1a4d94c561af2ce | |
| parent | af305526e77828621de645c4dd4c93f2d76b821b (diff) | |
| download | yajl-b78dd790825e3347422ef8ac56d2ad557a473e8f.tar.gz | |
* BREAKING API CHANGE: allow client to specify memory allocation routines
* bump yajl version to 1.0.0
* update TODO list, removing completed tasks
* update yajl_test to override allocation routines and count allocations/frees, providing an automated standalone way to validate we're not leaky
* update all copyright dates
* update all .gold files with new test output
* update ChangeLog in preparation for 1.0.0 release
67 files changed, 404 insertions, 72 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 08a043e..f0570f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -32,9 +32,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(YetAnotherJSONParser) -SET (YAJL_MAJOR 0) -SET (YAJL_MINOR 4) -SET (YAJL_MICRO 1) +SET (YAJL_MAJOR 1) +SET (YAJL_MINOR 0) +SET (YAJL_MICRO 0) SET (YAJL_DIST_NAME "yajl-${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}") @@ -1,4 +1,4 @@ -Copyright 2007, Lloyd Hilaiel. +Copyright 2007-2009, Lloyd Hilaiel. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -1,6 +1,17 @@ 1.0.0 * lth add 'make install' rules, thaks to Andrei Soroker for the contribution. + * lth client may override allocation routines at generator or parser + allocation time + * tjw add yajl_parse_complete routine to allow client to explicitly + specify end-of-input, solving the "lonely number" case, where + json text consists only of an element with no explicit syntactic + end. + * tjw many new test cases + * tjw cleanup of code for symmetry and ease of reading + * lth integration of patches from Robert Varga which cleanup + compilation warnings on 64 bit linux + 0.4.0 * lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to Eric Bergstrome @@ -1,13 +1,9 @@ * add a test for 0x1F bug * numeric overflow in integers and double * line and char offsets in the lexer and in error messages -* numbers at eof bug. client must have a way of indicating 'end of input' - (other than passing in a ' ' whitespace byte), - problem illustrated with lonely number test case. * testing: a. the permuter b. some performance comparison against json_checker. * investigate pull instead of push parsing * Handle memory allocation failures gracefully -* allow client to override malloc/calloc/free impl. * cygwin/msys support on win32 @@ -1,5 +1,5 @@ #!/usr/bin/env ruby -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/reformatter/CMakeLists.txt b/reformatter/CMakeLists.txt index 5ac7035..5e6a281 100644 --- a/reformatter/CMakeLists.txt +++ b/reformatter/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/reformatter/json_reformat.c b/reformatter/json_reformat.c index b1c2ee7..d117179 100644 --- a/reformatter/json_reformat.c +++ b/reformatter/json_reformat.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -156,10 +156,10 @@ main(int argc, char ** argv) usage(argv[0]); } - g = yajl_gen_alloc(&conf); + g = yajl_gen_alloc(&conf, NULL); /* ok. open file. let's read and parse */ - hand = yajl_alloc(&callbacks, &cfg, (void *) g); + hand = yajl_alloc(&callbacks, &cfg, (void *) g, NULL); while (!done) { rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); @@ -185,7 +185,7 @@ main(int argc, char ** argv) { unsigned char * str = yajl_get_error(hand, 1, fileData, rd); fprintf(stderr, (const char *) str); - yajl_free_error(str); + yajl_free_error(hand, str); } else { const unsigned char * buf; unsigned int len; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db24757..59027cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -28,8 +28,9 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c yajl_encode.c yajl_gen.c) -SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h) +SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c + yajl_encode.c yajl_gen.c yajl_alloc.c) +SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h yajl_alloc.h) SET (PUB_HDRS api/yajl_parse.h api/yajl_gen.h api/yajl_common.h) # useful when fixing lexer bugs. diff --git a/src/api/yajl_common.h b/src/api/yajl_common.h index a97b3c0..004c6c6 100644 --- a/src/api/yajl_common.h +++ b/src/api/yajl_common.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +33,10 @@ #ifndef __YAJL_COMMON_H__ #define __YAJL_COMMON_H__ +#ifdef __cplusplus +extern "C" { +#endif + #define YAJL_MAX_DEPTH 128 /* msft dll export gunk. To build a DLL on windows, you @@ -48,4 +52,34 @@ # define YAJL_API #endif +/** pointer to a malloc function, supporting client overriding memory + * allocation routines */ +typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz); + +/** pointer to a free function, supporting client overriding memory + * allocation routines */ +typedef void (*yajl_free_func)(void *ctx, void * ptr); + +/** pointer to a realloc function which can resize an allocation. */ +typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz); + +/** A structure which can be passed to yajl_*_alloc routines to allow the + * client to specify memory allocation functions to be used. */ +typedef struct +{ + /** pointer to a function that can allocate uninitialized memory */ + yajl_malloc_func malloc; + /** pointer to a function that can resize memory allocations */ + yajl_realloc_func realloc; + /** pointer to a function that can free memory allocated using + * reallocFunction or mallocFunction */ + yajl_free_func free; + /** a context pointer that will be passed to above allocation routines */ + void * ctx; +} yajl_alloc_funcs; + +#ifdef __cplusplus +}; +#endif + #endif diff --git a/src/api/yajl_gen.h b/src/api/yajl_gen.h index 334373b..c26dc6a 100644 --- a/src/api/yajl_gen.h +++ b/src/api/yajl_gen.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -73,8 +73,18 @@ extern "C" { const char * indentString; } yajl_gen_config; - /** allocate a generator handle */ - yajl_gen YAJL_API yajl_gen_alloc(const yajl_gen_config * config); + /** allocate a generator handle + * \param config a pointer to a structure containing parameters which + * configure the behavior of the json generator + * \param allocFuncs an optional pointer to a structure which allows + * the client to overide the memory allocation + * used by yajl. May be NULL, in which case + * malloc/free/realloc will be used. + * + * \returns an allocated handle on success, NULL on failure (bad params) + */ + yajl_gen YAJL_API yajl_gen_alloc(const yajl_gen_config * config, + const yajl_alloc_funcs * allocFuncs); /** free a generator handle */ void YAJL_API yajl_gen_free(yajl_gen handle); diff --git a/src/api/yajl_parse.h b/src/api/yajl_parse.h index 6f6dba3..56504f3 100644 --- a/src/api/yajl_parse.h +++ b/src/api/yajl_parse.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -129,6 +129,7 @@ extern "C" { */ yajl_handle YAJL_API yajl_alloc(const yajl_callbacks * callbacks, const yajl_parser_config * config, + const yajl_alloc_funcs * allocFuncs, void * ctx); /** free a parser handle */ @@ -169,7 +170,7 @@ extern "C" { unsigned int jsonTextLength); /** free an error returned from yajl_get_error */ - void YAJL_API yajl_free_error(unsigned char * str); + void YAJL_API yajl_free_error(yajl_handle hand, unsigned char * str); #ifdef __cplusplus }; @@ -1,7 +1,7 @@ /*! \mainpage Yet Another JSON Library (YAJL) \author Lloyd Hilaiel - \date 2007-2008 + \date 2007-2009 Yet Another JSON Library (YAJL) is a small event-driven (SAX-style) JSON parser written in ANSI C, and a small validating JSON @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +33,7 @@ #include "api/yajl_parse.h" #include "yajl_lex.h" #include "yajl_parser.h" +#include "yajl_alloc.h" #include <stdlib.h> #include <string.h> @@ -62,11 +63,29 @@ yajl_status_to_string(yajl_status stat) yajl_handle yajl_alloc(const yajl_callbacks * callbacks, const yajl_parser_config * config, + const yajl_alloc_funcs * afs, void * ctx) { unsigned int allowComments = 0; unsigned int validateUTF8 = 0; - yajl_handle hand = (yajl_handle) malloc(sizeof(struct yajl_handle_t)); + yajl_handle hand = NULL; + yajl_alloc_funcs afsBuffer; + + /* first order of business is to set up memory allocation routines */ + if (afs != NULL) { + if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) + { + return NULL; + } + } else { + yajl_set_default_alloc_funcs(&afsBuffer); + afs = &afsBuffer; + } + + hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); + + /* copy in pointers to allocation routines */ + memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); if (config != NULL) { allowComments = config->allowComments; @@ -75,10 +94,10 @@ yajl_alloc(const yajl_callbacks * callbacks, hand->callbacks = callbacks; hand->ctx = ctx; - hand->lexer = yajl_lex_alloc(allowComments, validateUTF8); + hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); hand->errorOffset = 0; - hand->decodeBuf = yajl_buf_alloc(); - hand->stateBuf = yajl_buf_alloc(); + hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); + hand->stateBuf = yajl_buf_alloc(&(hand->alloc)); yajl_state_push(hand, yajl_state_start); @@ -91,7 +110,7 @@ yajl_free(yajl_handle handle) yajl_buf_free(handle->stateBuf); yajl_buf_free(handle->decodeBuf); yajl_lex_free(handle->lexer); - free(handle); + YA_FREE(&(handle->alloc), handle); } yajl_status @@ -124,10 +143,10 @@ yajl_get_error(yajl_handle hand, int verbose, } void -yajl_free_error(unsigned char * str) +yajl_free_error(yajl_handle hand, unsigned char * str) { - /* XXX: use memory allocation functions if set */ - free(str); + /* use memory allocation functions if set */ + YA_FREE(&(hand->alloc), str); } /* XXX: add utility routines to parse from file */ diff --git a/src/yajl_alloc.c b/src/yajl_alloc.c new file mode 100644 index 0000000..0b4bf37 --- /dev/null +++ b/src/yajl_alloc.c @@ -0,0 +1,65 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_alloc.h + * default memory allocation routines for yajl which use malloc/realloc and + * free + */ + +#include "yajl_alloc.h" +#include <stdlib.h> + +static void * yajl_internal_malloc(void *ctx, unsigned int sz) +{ + return malloc(sz); +} + +static void * yajl_internal_realloc(void *ctx, void * previous, + unsigned int sz) +{ + return realloc(previous, sz); +} + +static void yajl_internal_free(void *ctx, void * ptr) +{ + free(ptr); +} + +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) +{ + yaf->malloc = yajl_internal_malloc; + yaf->free = yajl_internal_free; + yaf->realloc = yajl_internal_realloc; + yaf->ctx = NULL; +} + diff --git a/src/yajl_alloc.h b/src/yajl_alloc.h new file mode 100644 index 0000000..bf19308 --- /dev/null +++ b/src/yajl_alloc.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_alloc.h + * default memory allocation routines for yajl which use malloc/realloc and + * free + */ + +#ifndef __YAJL_ALLOC_H__ +#define __YAJL_ALLOC_H__ + +#include "api/yajl_common.h" + +#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) +#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) +#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) + +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); + +#endif diff --git a/src/yajl_buf.c b/src/yajl_buf.c index 55051c8..97f1ced 100644 --- a/src/yajl_buf.c +++ b/src/yajl_buf.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -42,6 +42,7 @@ struct yajl_buf_t { unsigned int len; unsigned int used; unsigned char * data; + yajl_alloc_funcs * alloc; }; static @@ -54,7 +55,7 @@ void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) /* first call */ if (buf->data == NULL) { buf->len = YAJL_BUF_INIT_SIZE; - buf->data = (unsigned char *) malloc(buf->len); + buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); buf->data[0] = 0; } @@ -63,21 +64,24 @@ void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) while (want >= (need - buf->used)) need <<= 1; if (need != buf->len) { - buf->data = (unsigned char *) realloc(buf->data, need); + buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); buf->len = need; } } -yajl_buf yajl_buf_alloc(void) +yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) { - return (yajl_buf) calloc(1, sizeof(struct yajl_buf_t)); + yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); + memset((void *) b, 0, sizeof(struct yajl_buf_t)); + b->alloc = alloc; + return b; } void yajl_buf_free(yajl_buf buf) { assert(buf != NULL); - if (buf->data) free(buf->data); - free(buf); + if (buf->data) YA_FREE(buf->alloc, buf->data); + YA_FREE(buf->alloc, buf); } void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len) diff --git a/src/yajl_buf.h b/src/yajl_buf.h index e2c08b5..62b5554 100644 --- a/src/yajl_buf.h +++ b/src/yajl_buf.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +33,9 @@ #ifndef __YAJL_BUF_H__ #define __YAJL_BUF_H__ +#include "api/yajl_common.h" +#include "yajl_alloc.h" + /** * yajl_buf is a buffer with exponential growth. the buffer ensures that * you are always null padded. @@ -40,7 +43,7 @@ typedef struct yajl_buf_t * yajl_buf; /* allocate a new buffer */ -yajl_buf yajl_buf_alloc(void); +yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); /* free the buffer */ void yajl_buf_free(yajl_buf buf); diff --git a/src/yajl_encode.c b/src/yajl_encode.c index 0449225..184277b 100644 --- a/src/yajl_encode.c +++ b/src/yajl_encode.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff --git a/src/yajl_encode.h b/src/yajl_encode.h index f3ab5bd..8bd01af 100644 --- a/src/yajl_encode.h +++ b/src/yajl_encode.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff --git a/src/yajl_gen.c b/src/yajl_gen.c index 67740ec..34cfbec 100644 --- a/src/yajl_gen.c +++ b/src/yajl_gen.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -56,18 +56,39 @@ struct yajl_gen_t const char * indentString; yajl_gen_state state[YAJL_MAX_DEPTH]; yajl_buf buf; + /* memory allocation routines */ + yajl_alloc_funcs alloc; }; yajl_gen -yajl_gen_alloc(const yajl_gen_config * config) +yajl_gen_alloc(const yajl_gen_config * config, + const yajl_alloc_funcs * afs) { - yajl_gen g = (yajl_gen) malloc(sizeof(struct yajl_gen_t)); + yajl_gen g = NULL; + yajl_alloc_funcs afsBuffer; + + /* first order of business is to set up memory allocation routines */ + if (afs != NULL) { + if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) + { + return NULL; + } + } else { + yajl_set_default_alloc_funcs(&afsBuffer); + afs = &afsBuffer; + } + + g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); memset((void *) g, 0, sizeof(struct yajl_gen_t)); + /* copy in pointers to allocation routines */ + memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); + if (config) { g->pretty = config->beautify; g->indentString = config->indentString ? config->indentString : " "; } - g->buf = yajl_buf_alloc(); + g->buf = yajl_buf_alloc(&(g->alloc)); + return g; } @@ -75,7 +96,7 @@ void yajl_gen_free(yajl_gen g) { yajl_buf_free(g->buf); - free(g); + YA_FREE(&(g->alloc), g); } #define INSERT_SEP \ diff --git a/src/yajl_lex.c b/src/yajl_lex.c index 5392422..b56f32b 100644 --- a/src/yajl_lex.c +++ b/src/yajl_lex.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -105,6 +105,8 @@ struct yajl_lexer_t { /* shall we validate utf8 inside strings? */ unsigned int validateUTF8; + + yajl_alloc_funcs * alloc; }; static unsigned char @@ -127,12 +129,15 @@ unreadChar(yajl_lexer lxr, unsigned int *off) } yajl_lexer -yajl_lex_alloc(unsigned int allowComments, unsigned int validateUTF8) +yajl_lex_alloc(yajl_alloc_funcs * alloc, + unsigned int allowComments, unsigned int validateUTF8) { - yajl_lexer lxr = (yajl_lexer) calloc(1, sizeof(struct yajl_lexer_t)); - lxr->buf = yajl_buf_alloc(); + yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t)); + memset((void *) lxr, 0, sizeof(struct yajl_lexer_t)); + lxr->buf = yajl_buf_alloc(alloc); lxr->allowComments = allowComments; lxr->validateUTF8 = validateUTF8; + lxr->alloc = alloc; return lxr; } @@ -140,7 +145,7 @@ void yajl_lex_free(yajl_lexer lxr) { yajl_buf_free(lxr->buf); - free(lxr); + YA_FREE(lxr->alloc, lxr); return; } diff --git a/src/yajl_lex.h b/src/yajl_lex.h index e84131a..966365c 100644 --- a/src/yajl_lex.h +++ b/src/yajl_lex.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +33,8 @@ #ifndef __YAJL_LEX_H__ #define __YAJL_LEX_H__ +#include "api/yajl_common.h" + typedef enum { yajl_tok_bool, yajl_tok_colon, @@ -61,7 +63,8 @@ typedef enum { typedef struct yajl_lexer_t * yajl_lexer; -yajl_lexer yajl_lex_alloc(unsigned int allowComments, +yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, + unsigned int allowComments, unsigned int validateUTF8); void yajl_lex_free(yajl_lexer lexer); diff --git a/src/yajl_parser.c b/src/yajl_parser.c index e6bc437..398873c 100644 --- a/src/yajl_parser.c +++ b/src/yajl_parser.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -71,7 +71,7 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, memneeded += strlen(": "); memneeded += strlen(errorText); } - str = (unsigned char *) malloc(memneeded + 2); + str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); str[0] = 0; strcat((char *) str, errorType); strcat((char *) str, " error"); @@ -108,14 +108,15 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, text[i++] = '\n'; text[i] = 0; { - char * newStr = (char *) malloc(strlen((char *) str) + - strlen((char *) text) + - strlen(arrow) + 1); + char * newStr = (char *) + YA_MALLOC(&(hand->alloc), (strlen((char *) str) + + strlen((char *) text) + + strlen(arrow) + 1)); newStr[0] = 0; strcat((char *) newStr, (char *) str); strcat((char *) newStr, text); strcat((char *) newStr, arrow); - free(str); + YA_FREE(&(hand->alloc), str); str = (unsigned char *) newStr; } } diff --git a/src/yajl_parser.h b/src/yajl_parser.h index ba6c49d..0e1227d 100644 --- a/src/yajl_parser.h +++ b/src/yajl_parser.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -61,6 +61,8 @@ struct yajl_handle_t { yajl_buf decodeBuf; /* a stack of states. access with yajl_state_XXX routines */ yajl_buf stateBuf; + /* memory allocation routines */ + yajl_alloc_funcs alloc; }; yajl_status diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c6d65e9..85d673d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/test/cases/array.json.gold b/test/cases/array.json.gold index 95ec334..477559d 100644 --- a/test/cases/array.json.gold +++ b/test/cases/array.json.gold @@ -19,3 +19,4 @@ array close ']' string: '
\' array close ']' +memory leaks: 0 diff --git a/test/cases/array_close.json.gold b/test/cases/array_close.json.gold index 4eedbc9..972fd39 100644 --- a/test/cases/array_close.json.gold +++ b/test/cases/array_close.json.gold @@ -1 +1,2 @@ parse error: unallowed token at this point in JSON text +memory leaks: 0 diff --git a/test/cases/array_open.json.gold b/test/cases/array_open.json.gold index 86c13ec..478b6b9 100644 --- a/test/cases/array_open.json.gold +++ b/test/cases/array_open.json.gold @@ -1 +1,2 @@ array open '[' +memory leaks: 0 diff --git a/test/cases/bogus_char.json.gold b/test/cases/bogus_char.json.gold index ccbeed5..0c68a49 100644 --- a/test/cases/bogus_char.json.gold +++ b/test/cases/bogus_char.json.gold @@ -7,3 +7,4 @@ string: 'be' string: 'a happy bit of json' string: 'but someone, misspelled "true"' lexical error: invalid string in json text. +memory leaks: 0 diff --git a/test/cases/codepoints_from_unicode_org.json.gold b/test/cases/codepoints_from_unicode_org.json.gold index 12b358a..f359a1b 100644 --- a/test/cases/codepoints_from_unicode_org.json.gold +++ b/test/cases/codepoints_from_unicode_org.json.gold @@ -1 +1,2 @@ string: 'Mа二𐌂' +memory leaks: 0 diff --git a/test/cases/dc_simple_with_comments.json.gold b/test/cases/dc_simple_with_comments.json.gold index 92be7a5..d222e9b 100644 --- a/test/cases/dc_simple_with_comments.json.gold +++ b/test/cases/dc_simple_with_comments.json.gold @@ -2,3 +2,4 @@ map open '{' key: 'this' string: 'is' lexical error: probable comment found in input text, comments are not enabled. +memory leaks: 0 diff --git a/test/cases/deep_arrays.json.gold b/test/cases/deep_arrays.json.gold index e549637..4d5cd99 100644 --- a/test/cases/deep_arrays.json.gold +++ b/test/cases/deep_arrays.json.gold @@ -2046,3 +2046,4 @@ array close ']' array close ']' array close ']' array close ']' +memory leaks: 0 diff --git a/test/cases/difficult_json_c_test_case.json.gold b/test/cases/difficult_json_c_test_case.json.gold index eaaf41a..c3adc11 100644 --- a/test/cases/difficult_json_c_test_case.json.gold +++ b/test/cases/difficult_json_c_test_case.json.gold @@ -33,3 +33,4 @@ array close ']' map close '}' map close '}' map close '}' +memory leaks: 0 diff --git a/test/cases/difficult_json_c_test_case_with_comments.json.gold b/test/cases/difficult_json_c_test_case_with_comments.json.gold index eaaf41a..c3adc11 100644 --- a/test/cases/difficult_json_c_test_case_with_comments.json.gold +++ b/test/cases/difficult_json_c_test_case_with_comments.json.gold @@ -33,3 +33,4 @@ array close ']' map close '}' map close '}' map close '}' +memory leaks: 0 diff --git a/test/cases/doubles.json.gold b/test/cases/doubles.json.gold index 0426b37..c0ea726 100644 --- a/test/cases/doubles.json.gold +++ b/test/cases/doubles.json.gold @@ -4,3 +4,4 @@ double: 10 double: 3.14157 double: 1000 array close ']' +memory leaks: 0 diff --git a/test/cases/empty_array.json.gold b/test/cases/empty_array.json.gold index 45924af..f069c8f 100644 --- a/test/cases/empty_array.json.gold +++ b/test/cases/empty_array.json.gold @@ -1,2 +1,3 @@ array open '[' array close ']' +memory leaks: 0 diff --git a/test/cases/empty_string.json.gold b/test/cases/empty_string.json.gold index c3a3cd3..c197bba 100644 --- a/test/cases/empty_string.json.gold +++ b/test/cases/empty_string.json.gold @@ -1 +1,2 @@ string: '' +memory leaks: 0 diff --git a/test/cases/escaped_bulgarian.json.gold b/test/cases/escaped_bulgarian.json.gold index 9f2aa00..a0c9ae9 100644 --- a/test/cases/escaped_bulgarian.json.gold +++ b/test/cases/escaped_bulgarian.json.gold @@ -4,3 +4,4 @@ string: 'Му' string: 'Еба' string: 'Майката' array close ']' +memory leaks: 0 diff --git a/test/cases/escaped_foobar.json.gold b/test/cases/escaped_foobar.json.gold index 774e867..5753c64 100644 --- a/test/cases/escaped_foobar.json.gold +++ b/test/cases/escaped_foobar.json.gold @@ -1 +1,2 @@ string: 'foobar' +memory leaks: 0 diff --git a/test/cases/false.json.gold b/test/cases/false.json.gold index c91690a..e55fa1f 100644 --- a/test/cases/false.json.gold +++ b/test/cases/false.json.gold @@ -1 +1,2 @@ bool: false +memory leaks: 0 diff --git a/test/cases/false_then_garbage.json.gold b/test/cases/false_then_garbage.json.gold index c91690a..e55fa1f 100644 --- a/test/cases/false_then_garbage.json.gold +++ b/test/cases/false_then_garbage.json.gold @@ -1 +1,2 @@ bool: false +memory leaks: 0 diff --git a/test/cases/integers.json.gold b/test/cases/integers.json.gold index 7341a2d..bb55c39 100644 --- a/test/cases/integers.json.gold +++ b/test/cases/integers.json.gold @@ -11,3 +11,4 @@ integer: -123456789 integer: 2147483647 integer: -2147483647 parse error: integer overflow +memory leaks: 0 diff --git a/test/cases/invalid_utf8.json.gold b/test/cases/invalid_utf8.json.gold index 0cabb13..c0dec77 100644 --- a/test/cases/invalid_utf8.json.gold +++ b/test/cases/invalid_utf8.json.gold @@ -1,2 +1,3 @@ array open '[' lexical error: invalid bytes in UTF8 string. +memory leaks: 0 diff --git a/test/cases/isolated_surrogate_marker.json.gold b/test/cases/isolated_surrogate_marker.json.gold index 1ad9e8b..cca172e 100644 --- a/test/cases/isolated_surrogate_marker.json.gold +++ b/test/cases/isolated_surrogate_marker.json.gold @@ -1 +1,2 @@ string: '?' +memory leaks: 0 diff --git a/test/cases/leading_zero_in_number.json.gold b/test/cases/leading_zero_in_number.json.gold index 828aec8..1a1580d 100644 --- a/test/cases/leading_zero_in_number.json.gold +++ b/test/cases/leading_zero_in_number.json.gold @@ -2,3 +2,4 @@ map open '{' key: 'bad thing' integer: 0 parse error: after key and value, inside map, I expect ',' or '}' +memory leaks: 0 diff --git a/test/cases/lonely_minus_sign.json.gold b/test/cases/lonely_minus_sign.json.gold index 4b23c61..d15ede9 100644 --- a/test/cases/lonely_minus_sign.json.gold +++ b/test/cases/lonely_minus_sign.json.gold @@ -6,3 +6,4 @@ string: 'blue' string: 'baby where are you?' string: 'oh boo hoo!' lexical error: malformed number, a digit is required after the minus sign. +memory leaks: 0 diff --git a/test/cases/lonely_number.json.gold b/test/cases/lonely_number.json.gold index cdc08ba..181fdfa 100644 --- a/test/cases/lonely_number.json.gold +++ b/test/cases/lonely_number.json.gold @@ -1 +1,2 @@ integer: 123456789 +memory leaks: 0 diff --git a/test/cases/map_close.json.gold b/test/cases/map_close.json.gold index 4eedbc9..972fd39 100644 --- a/test/cases/map_close.json.gold +++ b/test/cases/map_close.json.gold @@ -1 +1,2 @@ parse error: unallowed token at this point in JSON text +memory leaks: 0 diff --git a/test/cases/map_open.json.gold b/test/cases/map_open.json.gold index a823ebe..ab1f33d 100644 --- a/test/cases/map_open.json.gold +++ b/test/cases/map_open.json.gold @@ -1 +1,2 @@ map open '{' +memory leaks: 0 diff --git a/test/cases/missing_integer_after_decimal_point.json.gold b/test/cases/missing_integer_after_decimal_point.json.gold index 1d85c91..c2e7e2e 100644 --- a/test/cases/missing_integer_after_decimal_point.json.gold +++ b/test/cases/missing_integer_after_decimal_point.json.gold @@ -1 +1,2 @@ lexical error: malformed number, a digit is required after the decimal point. +memory leaks: 0 diff --git a/test/cases/missing_integer_after_exponent.json.gold b/test/cases/missing_integer_after_exponent.json.gold index b9f184f..5089681 100644 --- a/test/cases/missing_integer_after_exponent.json.gold +++ b/test/cases/missing_integer_after_exponent.json.gold @@ -1 +1,2 @@ lexical error: malformed number, a digit is required after the exponent. +memory leaks: 0 diff --git a/test/cases/non_utf8_char_in_string.json.gold b/test/cases/non_utf8_char_in_string.json.gold index b3780ae..5e3c580 100644 --- a/test/cases/non_utf8_char_in_string.json.gold +++ b/test/cases/non_utf8_char_in_string.json.gold @@ -5,3 +5,4 @@ key: 'CoreletType' string: 'standalone' key: 'documentation' lexical error: invalid bytes in UTF8 string. +memory leaks: 0 diff --git a/test/cases/null.json.gold b/test/cases/null.json.gold index 19765bd..94ad0fa 100644 --- a/test/cases/null.json.gold +++ b/test/cases/null.json.gold @@ -1 +1,2 @@ null +memory leaks: 0 diff --git a/test/cases/null_then_garbage.json.gold b/test/cases/null_then_garbage.json.gold index 19765bd..94ad0fa 100644 --- a/test/cases/null_then_garbage.json.gold +++ b/test/cases/null_then_garbage.json.gold @@ -1 +1,2 @@ null +memory leaks: 0 diff --git a/test/cases/nulls_and_bools.json.gold b/test/cases/nulls_and_bools.json.gold index 8dc173c..51f990b 100644 --- a/test/cases/nulls_and_bools.json.gold +++ b/test/cases/nulls_and_bools.json.gold @@ -6,3 +6,4 @@ bool: false key: 'null' null map close '}' +memory leaks: 0 diff --git a/test/cases/simple.json.gold b/test/cases/simple.json.gold index 59b7d6a..80fcad2 100644 --- a/test/cases/simple.json.gold +++ b/test/cases/simple.json.gold @@ -6,3 +6,4 @@ string: 'simple' key: 'json' string: 'right?' map close '}' +memory leaks: 0 diff --git a/test/cases/simple_with_comments.json.gold b/test/cases/simple_with_comments.json.gold index 59b7d6a..80fcad2 100644 --- a/test/cases/simple_with_comments.json.gold +++ b/test/cases/simple_with_comments.json.gold @@ -6,3 +6,4 @@ string: 'simple' key: 'json' string: 'right?' map close '}' +memory leaks: 0 diff --git a/test/cases/string_invalid_escape.json.gold b/test/cases/string_invalid_escape.json.gold index bdc473e..439df43 100644 --- a/test/cases/string_invalid_escape.json.gold +++ b/test/cases/string_invalid_escape.json.gold @@ -1,2 +1,3 @@ array open '[' lexical error: inside a string, '\' occurs before a character which it may not. +memory leaks: 0 diff --git a/test/cases/string_invalid_hex_char.json.gold b/test/cases/string_invalid_hex_char.json.gold index d8b535e..8498792 100644 --- a/test/cases/string_invalid_hex_char.json.gold +++ b/test/cases/string_invalid_hex_char.json.gold @@ -1 +1,2 @@ lexical error: invalid (non-hex) character occurs after '\u' inside string. +memory leaks: 0 diff --git a/test/cases/string_with_escapes.json.gold b/test/cases/string_with_escapes.json.gold index ac878a2..086a9dc 100644 --- a/test/cases/string_with_escapes.json.gold +++ b/test/cases/string_with_escapes.json.gold @@ -4,3 +4,4 @@ string: ' string: '"and this string has an escape at the beginning' string: 'and this string has no escapes' array close ']' +memory leaks: 0 diff --git a/test/cases/string_with_invalid_newline.json.gold b/test/cases/string_with_invalid_newline.json.gold index 80c1b8a..c38bdef 100644 --- a/test/cases/string_with_invalid_newline.json.gold +++ b/test/cases/string_with_invalid_newline.json.gold @@ -1 +1,2 @@ lexical error: invalid character inside string. +memory leaks: 0 diff --git a/test/cases/true.json.gold b/test/cases/true.json.gold index 3283d03..0858bf7 100644 --- a/test/cases/true.json.gold +++ b/test/cases/true.json.gold @@ -1 +1,2 @@ bool: true +memory leaks: 0 diff --git a/test/cases/true_then_garbage.json.gold b/test/cases/true_then_garbage.json.gold index 3283d03..0858bf7 100644 --- a/test/cases/true_then_garbage.json.gold +++ b/test/cases/true_then_garbage.json.gold @@ -1 +1,2 @@ bool: true +memory leaks: 0 diff --git a/test/cases/unescaped_bulgarian.json.gold b/test/cases/unescaped_bulgarian.json.gold index ac34442..8db076e 100644 --- a/test/cases/unescaped_bulgarian.json.gold +++ b/test/cases/unescaped_bulgarian.json.gold @@ -1,3 +1,4 @@ array open '[' string: 'Да Му Еба Майката' array close ']' +memory leaks: 0 diff --git a/test/yajl_test.c b/test/yajl_test.c index 3c2fcf1..77281a5 100644 --- a/test/yajl_test.c +++ b/test/yajl_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -37,6 +37,48 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> + +/* memory debugging routines */ +typedef struct +{ + unsigned int numFrees; + unsigned int numMallocs; + /* XXX: we really need a hash table here with per-allocation + * information */ +} yajlTestMemoryContext; + +/* cast void * into context */ +#define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr)) + +static void yajlTestFree(void * ctx, void * ptr) +{ + assert(ptr != NULL); + TEST_CTX(ctx)->numFrees++; + free(ptr); +} + +static void * yajlTestMalloc(void * ctx, unsigned int sz) +{ + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + return malloc(sz); +} + +static void * yajlTestRealloc(void * ctx, void * ptr, unsigned int sz) +{ + if (ptr == NULL) { + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + } else if (sz == 0) { + TEST_CTX(ctx)->numFrees++; + } + + return realloc(ctx, sz); +} + + +/* begin parsing callback routines */ #define BUF_SIZE 2048 static int test_yajl_null(void *ctx) @@ -144,6 +186,21 @@ main(int argc, char ** argv) yajl_parser_config cfg = { 0, 1 }; int i, j, done; + /* memory allocation debugging: allocate a structure which collects + * statistics */ + yajlTestMemoryContext memCtx = { 0,0 }; + + /* memory allocation debugging: allocate a structure which holds + * allocation routines */ + yajl_alloc_funcs allocFuncs = { + yajlTestMalloc, + yajlTestRealloc, + yajlTestFree, + (void *) NULL + }; + + allocFuncs.ctx = (void *) &memCtx; + /* check arguments. We expect exactly one! */ for (i=1;i<argc;i++) { if (!strcmp("-c", argv[i])) { @@ -183,7 +240,7 @@ main(int argc, char ** argv) fileName = argv[argc-1]; /* ok. open file. let's read and parse */ - hand = yajl_alloc(&callbacks, &cfg, NULL); + hand = yajl_alloc(&callbacks, &cfg, &allocFuncs, NULL); done = 0; while (!done) { @@ -210,7 +267,7 @@ main(int argc, char ** argv) unsigned char * str = yajl_get_error(hand, 0, fileData, rd); fflush(stdout); fprintf(stderr, (char *) str); - yajl_free_error(str); + yajl_free_error(hand, str); break; } } @@ -218,5 +275,15 @@ main(int argc, char ** argv) yajl_free(hand); free(fileData); + /* finally, print out some memory statistics */ + +/* (lth) only print leaks here, as allocations and frees may vary depending + * on read buffer size, causing false failures. + * + * printf("allocations:\t%u\n", memCtx.numMallocs); + * printf("frees:\t\t%u\n", memCtx.numFrees); +*/ + printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees); + return 0; } diff --git a/verify/CMakeLists.txt b/verify/CMakeLists.txt index 17efd83..68aaff9 100644 --- a/verify/CMakeLists.txt +++ b/verify/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2007, Lloyd Hilaiel. +# Copyright 2007-2009, Lloyd Hilaiel. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/verify/json_verify.c b/verify/json_verify.c index f76fbe9..11d0285 100644 --- a/verify/json_verify.c +++ b/verify/json_verify.c @@ -1,5 +1,5 @@ /* - * Copyright 2007, Lloyd Hilaiel. + * Copyright 2007-2009, Lloyd Hilaiel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -80,7 +80,7 @@ main(int argc, char ** argv) } /* allocate a parser */ - hand = yajl_alloc(NULL, &cfg, NULL); + hand = yajl_alloc(NULL, &cfg, NULL, NULL); while (!done) { rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); @@ -112,7 +112,7 @@ main(int argc, char ** argv) if (!quiet) { unsigned char * str = yajl_get_error(hand, 1, fileData, rd); fprintf(stderr, (const char *) str); - yajl_free_error(str); + yajl_free_error(hand, str); } retval = 1; break; |
