Persist the `val` register across yield The `val` variable is a register value that we need to be able to return at any time from `decode_iter`. If it happened that a yield was triggered while processing trailing whitespace the lack of persistance caused decode to return a term intialized from a random integer value. Obviously the Erlang VM did not enjoy this.
Thanks to @michalpalka for the report. Fixes #66 Project: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/commit/5cd89c1e Tree: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/tree/5cd89c1e Diff: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/diff/5cd89c1e Branch: refs/heads/master Commit: 5cd89c1eda3801bdef790b1e7c0e09259332c0fc Parents: f9095c5 Author: Paul J. Davis <[email protected]> Authored: Sat Aug 23 07:20:37 2014 -0500 Committer: Paul J. Davis <[email protected]> Committed: Sat Aug 23 07:20:37 2014 -0500 ---------------------------------------------------------------------- c_src/decoder.c | 22 ++++++++++++---------- c_src/jiffy.c | 2 +- src/jiffy.erl | 14 +++++++------- test/jiffy_13_whitespace_tests.erl | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/5cd89c1e/c_src/decoder.c ---------------------------------------------------------------------- diff --git a/c_src/decoder.c b/c_src/decoder.c index e7dc48b..ad3e8d3 100644 --- a/c_src/decoder.c +++ b/c_src/decoder.c @@ -675,7 +675,7 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Decoder* d; jiffy_st* st = (jiffy_st*) enif_priv_data(env); - ERL_NIF_TERM tmp_argv[4]; + ERL_NIF_TERM tmp_argv[5]; ERL_NIF_TERM opts; ERL_NIF_TERM val; @@ -690,8 +690,9 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) tmp_argv[0] = argv[0]; tmp_argv[1] = enif_make_resource(env, d); - tmp_argv[2] = enif_make_list(env, 0); + tmp_argv[2] = st->atom_error; tmp_argv[3] = enif_make_list(env, 0); + tmp_argv[4] = enif_make_list(env, 0); enif_release_resource(d); @@ -716,7 +717,7 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } } - return decode_iter(env, 4, tmp_argv); + return decode_iter(env, 5, tmp_argv); } ERL_NIF_TERM @@ -729,25 +730,25 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ERL_NIF_TERM objs; ERL_NIF_TERM curr; - ERL_NIF_TERM val; + ERL_NIF_TERM val = argv[2]; ERL_NIF_TERM ret; size_t start; - if(argc != 4) { + if(argc != 5) { return enif_make_badarg(env); } else if(!enif_inspect_binary(env, argv[0], &bin)) { return enif_make_badarg(env); } else if(!enif_get_resource(env, argv[1], st->res_dec, (void**) &d)) { return enif_make_badarg(env); - } else if(!enif_is_list(env, argv[2])) { - return enif_make_badarg(env); } else if(!enif_is_list(env, argv[3])) { return enif_make_badarg(env); + } else if(!enif_is_list(env, argv[4])) { + return enif_make_badarg(env); } dec_init(d, env, argv[0], &bin); - objs = argv[2]; - curr = argv[3]; + objs = argv[3]; + curr = argv[4]; //fprintf(stderr, "Parsing:\r\n"); start = d->i; @@ -755,10 +756,11 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) //fprintf(stderr, "state: %d\r\n", dec_curr(d)); if(should_yield(d->i - start, d->bytes_per_iter)) { consume_timeslice(env, d->i - start, d->bytes_per_iter); - return enif_make_tuple4( + return enif_make_tuple5( env, st->atom_iter, argv[1], + val, objs, curr ); http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/5cd89c1e/c_src/jiffy.c ---------------------------------------------------------------------- diff --git a/c_src/jiffy.c b/c_src/jiffy.c index 205de91..31aa854 100644 --- a/c_src/jiffy.c +++ b/c_src/jiffy.c @@ -78,7 +78,7 @@ unload(ErlNifEnv* env, void* priv) static ErlNifFunc funcs[] = { {"nif_decode_init", 2, decode_init}, - {"nif_decode_iter", 4, decode_iter}, + {"nif_decode_iter", 5, decode_iter}, {"nif_encode_init", 2, encode_init}, {"nif_encode_iter", 3, encode_iter} }; http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/5cd89c1e/src/jiffy.erl ---------------------------------------------------------------------- diff --git a/src/jiffy.erl b/src/jiffy.erl index 9642b25..23a0c9d 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -18,8 +18,8 @@ decode(Data, Opts) when is_binary(Data), is_list(Opts) -> throw(Error); {partial, EJson} -> finish_decode(EJson); - {iter, Decoder, Objs, Curr} -> - decode_loop(Data, Decoder, Objs, Curr); + {iter, Decoder, Val, Objs, Curr} -> + decode_loop(Data, Decoder, Val, Objs, Curr); EJson -> EJson end; @@ -120,14 +120,14 @@ init() -> erlang:load_nif(filename:join(PrivDir, "jiffy"), 0). -decode_loop(Data, Decoder, Objs, Curr) -> - case nif_decode_iter(Data, Decoder, Objs, Curr) of +decode_loop(Data, Decoder, Val, Objs, Curr) -> + case nif_decode_iter(Data, Decoder, Val, Objs, Curr) of {error, _} = Error -> throw(Error); {partial, EJson} -> finish_decode(EJson); - {iter, NewDecoder, NewObjs, NewCurr} -> - decode_loop(Data, NewDecoder, NewObjs, NewCurr); + {iter, NewDecoder, NewVal, NewObjs, NewCurr} -> + decode_loop(Data, NewDecoder, NewVal, NewObjs, NewCurr); EJson -> EJson end. @@ -156,7 +156,7 @@ not_loaded(Line) -> nif_decode_init(_Data, _Opts) -> ?NOT_LOADED. -nif_decode_iter(_Data, _Decoder, _, _) -> +nif_decode_iter(_Data, _Decoder, _, _, _) -> ?NOT_LOADED. nif_encode_init(_Data, _Options) -> http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/5cd89c1e/test/jiffy_13_whitespace_tests.erl ---------------------------------------------------------------------- diff --git a/test/jiffy_13_whitespace_tests.erl b/test/jiffy_13_whitespace_tests.erl new file mode 100644 index 0000000..9261b6e --- /dev/null +++ b/test/jiffy_13_whitespace_tests.erl @@ -0,0 +1,16 @@ +% This file is part of Jiffy released under the MIT license. +% See the LICENSE file for more information. + +-module(jiffy_13_whitespace_tests). + +-include_lib("eunit/include/eunit.hrl"). + + +trailing_whitespace_test_() -> + Str = [<<"{\"a\":\"b\"}">>, gen_ws(2040)], + Obj = {[{<<"a">>, <<"b">>}]}, + ?_assertEqual(Obj, jiffy:decode(Str)). + + +gen_ws(N) -> + [" " || _ <- lists:seq(1, N)]. \ No newline at end of file
