Skip to content

Commit 7921d7e

Browse files
authored
Merge pull request #65 from esl/fix-null
Throw exception on null characters Any further data passed via exml_stream:parse/2 to the parser won't be processed as well because rapidxml works on null-terminated strings and treats the whole input as empty. The similar issue happens when null character is in the middle of input (other exception is thrown but it has eof flag as well). I implemented the fix that checks (in advance) whether the buffer contains null character. If so, it throws the error immediately. This way we can make sure that input received from Erlang will be valid in term of processing.
2 parents b74dfc2 + 794f085 commit 7921d7e

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

c_src/exml.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <algorithm>
1313
#include <chrono>
14+
#include <cstring>
1415
#include <iostream>
1516
#include <string>
1617
#include <thread>
@@ -551,6 +552,13 @@ static ERL_NIF_TERM parse_next(ErlNifEnv *env, int argc,
551552
enif_make_string(env, result.error_message.c_str(), ERL_NIF_LATIN1));
552553
}
553554

555+
// Raise an exception when null character is found.
556+
std::size_t rest_size = &Parser::buffer.back() - result.rest;
557+
if (std::strlen(reinterpret_cast<const char*>(result.rest)) != rest_size)
558+
return enif_make_tuple2(
559+
env, atom_error,
560+
enif_make_string(env, "null character found in buffer", ERL_NIF_LATIN1));
561+
554562
return enif_make_tuple3(
555563
env, atom_ok, element,
556564
enif_make_uint64(env, result.rest - Parser::buffer.data()));

test/exml_stream_tests.erl

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,18 +191,24 @@ stream_max_child_size_test() ->
191191

192192
infinite_stream_partial_chunk_test() ->
193193
{ok, Parser0} = exml_stream:new_parser([{infinite_stream, true}, {autoreset, true}]),
194-
{ok, Parser1, Open} = exml_stream:parse(Parser0, <<"<open xmlns='urn:ietf:params:xml:ns:xmpp-framing' to='i.am.banana.com' version='1.0'/>">>),
194+
{ok, Parser1, Open} = exml_stream:parse(Parser0, <<"<open xmlns='urn:ietf:params:xml:ns:xmpp-framing' to='i.am.banana.com' version='1.0'/>">>),
195195
?assertEqual(
196196
[#xmlel{name = <<"open">>,
197-
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>},
198-
{<<"to">>, <<"i.am.banana.com">>},
199-
{<<"version">>, <<"1.0">>}]}],
197+
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>},
198+
{<<"to">>, <<"i.am.banana.com">>},
199+
{<<"version">>, <<"1.0">>}]}],
200200
Open),
201201
{ok, Parser2, A} = exml_stream:parse(Parser1, <<"<a></a>">>),
202-
?assertEqual([#xmlel{name = <<"a">>, attrs = []}], A),
203-
{ok, Parser3, Empty0} = exml_stream:parse(Parser2, <<" ">>),
204-
?assertEqual([], Empty0),
205-
{ok, Parser4, Empty1} = exml_stream:parse(Parser3, <<"<b></b">>),
206-
?assertEqual([], Empty1),
207-
{ok, _Parser5, B} = exml_stream:parse(Parser4, <<">">>),
208-
?assertEqual([#xmlel{name = <<"b">>, attrs = []}], B).
202+
?assertEqual([#xmlel{name = <<"a">>, attrs = []}], A),
203+
{ok, Parser3, Empty0} = exml_stream:parse(Parser2, <<" ">>),
204+
?assertEqual([], Empty0),
205+
{ok, Parser4, Empty1} = exml_stream:parse(Parser3, <<"<b></b">>),
206+
?assertEqual([], Empty1),
207+
{ok, _Parser5, B} = exml_stream:parse(Parser4, <<">">>),
208+
?assertEqual([#xmlel{name = <<"b">>, attrs = []}], B).
209+
210+
null_character_test() ->
211+
{ok, P1} = exml_stream:new_parser(),
212+
?assertMatch({error, _}, exml_stream:parse(P1, <<"\0<stream>">>)),
213+
{ok, P2} = exml_stream:new_parser(),
214+
?assertMatch({error, _}, exml_stream:parse(P2, <<"<stream>\0">>)).

0 commit comments

Comments
 (0)