11use crate :: atoms;
22use crate :: nif_util:: make_tuple2;
3+ use crate :: types:: MAX_DEPTH ;
34use rustler:: sys:: {
45 c_int, c_uint, enif_get_atom, enif_get_atom_length, enif_get_double, enif_get_int64,
5- enif_get_list_cell, enif_get_tuple, enif_inspect_binary , ErlNifBinary , ErlNifCharEncoding ,
6- ErlNifEnv , ERL_NIF_TERM ,
6+ enif_get_list_cell, enif_get_tuple, enif_get_uint64 , enif_inspect_binary , ErlNifBinary ,
7+ ErlNifCharEncoding , ErlNifEnv , ERL_NIF_TERM ,
78} ;
89use rustler:: { Encoder , Env , MapIterator , NewBinary , Term , TermType } ;
910use std:: mem:: MaybeUninit ;
1011
1112#[ derive( Debug ) ]
1213enum EncodeError {
1314 BadArg ,
15+ DepthExceeded ,
1416}
1517
1618/// Read an atom's name into a stack buffer without heap allocation.
@@ -48,14 +50,19 @@ unsafe fn atom_to_stack_buf(
4850fn encode < ' a > ( env : Env < ' a > , term : Term < ' a > ) -> Term < ' a > {
4951 let mut buf: Vec < u8 > = Vec :: with_capacity ( 2048 ) ;
5052 let env_raw = env. as_c_arg ( ) ;
51- match encode_term ( env, env_raw, term, & mut buf) {
53+ match encode_term ( env, env_raw, term, & mut buf, MAX_DEPTH ) {
5254 Ok ( ( ) ) => {
5355 let mut binary = NewBinary :: new ( env, buf. len ( ) ) ;
5456 binary. as_mut_slice ( ) . copy_from_slice ( & buf) ;
5557 let bin_term: Term = binary. into ( ) ;
5658 make_tuple2 ( env, atoms:: ok ( ) . as_c_arg ( ) , bin_term. as_c_arg ( ) )
5759 }
58- Err ( _) => make_tuple2 (
60+ Err ( EncodeError :: DepthExceeded ) => make_tuple2 (
61+ env,
62+ atoms:: error ( ) . as_c_arg ( ) ,
63+ atoms:: nesting_too_deep ( ) . as_c_arg ( ) ,
64+ ) ,
65+ Err ( EncodeError :: BadArg ) => make_tuple2 (
5966 env,
6067 atoms:: error ( ) . as_c_arg ( ) ,
6168 "encode error" . encode ( env) . as_c_arg ( ) ,
@@ -69,14 +76,17 @@ fn encode<'a>(env: Env<'a>, term: Term<'a>) -> Term<'a> {
6976fn encode_iodata < ' a > ( env : Env < ' a > , term : Term < ' a > ) -> Term < ' a > {
7077 let mut buf: Vec < u8 > = Vec :: with_capacity ( 2048 ) ;
7178 let env_raw = env. as_c_arg ( ) ;
72- match encode_term ( env, env_raw, term, & mut buf) {
79+ match encode_term ( env, env_raw, term, & mut buf, MAX_DEPTH ) {
7380 Ok ( ( ) ) => {
7481 let mut binary = NewBinary :: new ( env, buf. len ( ) ) ;
7582 binary. as_mut_slice ( ) . copy_from_slice ( & buf) ;
7683 binary. into ( )
7784 }
78- Err ( _) => unsafe {
79- let reason = "encode error" . encode ( env) . as_c_arg ( ) ;
85+ Err ( e) => unsafe {
86+ let reason = match e {
87+ EncodeError :: DepthExceeded => atoms:: nesting_too_deep ( ) . as_c_arg ( ) ,
88+ EncodeError :: BadArg => "encode error" . encode ( env) . as_c_arg ( ) ,
89+ } ;
8090 Term :: new ( env, rustler:: sys:: enif_raise_exception ( env_raw, reason) )
8191 } ,
8292 }
@@ -88,15 +98,16 @@ fn encode_term(
8898 env_raw : * mut ErlNifEnv ,
8999 term : Term ,
90100 buf : & mut Vec < u8 > ,
101+ depth : u32 ,
91102) -> Result < ( ) , EncodeError > {
92103 match term. get_type ( ) {
93- TermType :: Map => encode_map ( env, env_raw, term, buf) ,
94- TermType :: List => encode_list ( env, env_raw, term, buf) ,
104+ TermType :: Map => encode_map ( env, env_raw, term, buf, depth ) ,
105+ TermType :: List => encode_list ( env, env_raw, term, buf, depth ) ,
95106 TermType :: Binary => encode_binary ( env_raw, term, buf) ,
96107 TermType :: Integer => encode_integer ( env_raw, term, buf) ,
97108 TermType :: Float => encode_float ( env_raw, term, buf) ,
98109 TermType :: Atom => encode_atom ( env_raw, term, buf) ,
99- TermType :: Tuple => encode_tuple ( env, env_raw, term, buf) ,
110+ TermType :: Tuple => encode_tuple ( env, env_raw, term, buf, depth ) ,
100111 _ => Err ( EncodeError :: BadArg ) ,
101112 }
102113}
@@ -106,7 +117,11 @@ fn encode_map(
106117 env_raw : * mut ErlNifEnv ,
107118 term : Term ,
108119 buf : & mut Vec < u8 > ,
120+ depth : u32 ,
109121) -> Result < ( ) , EncodeError > {
122+ if depth == 0 {
123+ return Err ( EncodeError :: DepthExceeded ) ;
124+ }
110125 let iter = MapIterator :: new ( term) . ok_or ( EncodeError :: BadArg ) ?;
111126 buf. push ( b'{' ) ;
112127 let mut first = true ;
@@ -117,7 +132,7 @@ fn encode_map(
117132 first = false ;
118133 encode_map_key ( env_raw, key, buf) ?;
119134 buf. push ( b':' ) ;
120- encode_term ( env, env_raw, value, buf) ?;
135+ encode_term ( env, env_raw, value, buf, depth - 1 ) ?;
121136 }
122137 buf. push ( b'}' ) ;
123138 Ok ( ( ) )
@@ -158,7 +173,11 @@ fn encode_list(
158173 env_raw : * mut ErlNifEnv ,
159174 term : Term ,
160175 buf : & mut Vec < u8 > ,
176+ depth : u32 ,
161177) -> Result < ( ) , EncodeError > {
178+ if depth == 0 {
179+ return Err ( EncodeError :: DepthExceeded ) ;
180+ }
162181 buf. push ( b'[' ) ;
163182 let mut first = true ;
164183 let mut current = term. as_c_arg ( ) ;
@@ -170,7 +189,7 @@ fn encode_list(
170189 }
171190 first = false ;
172191 let item = unsafe { Term :: new ( env, head) } ;
173- encode_term ( env, env_raw, item, buf) ?;
192+ encode_term ( env, env_raw, item, buf, depth - 1 ) ?;
174193 current = tail;
175194 }
176195 buf. push ( b']' ) ;
@@ -204,12 +223,19 @@ fn encode_integer(
204223 buf : & mut Vec < u8 > ,
205224) -> Result < ( ) , EncodeError > {
206225 let mut n: i64 = 0 ;
207- if unsafe { enif_get_int64 ( env_raw, term. as_c_arg ( ) , & mut n) } == 0 {
208- return Err ( EncodeError :: BadArg ) ;
226+ if unsafe { enif_get_int64 ( env_raw, term. as_c_arg ( ) , & mut n) } != 0 {
227+ let mut itoa_buf = itoa:: Buffer :: new ( ) ;
228+ buf. extend_from_slice ( itoa_buf. format ( n) . as_bytes ( ) ) ;
229+ return Ok ( ( ) ) ;
209230 }
210- let mut itoa_buf = itoa:: Buffer :: new ( ) ;
211- buf. extend_from_slice ( itoa_buf. format ( n) . as_bytes ( ) ) ;
212- Ok ( ( ) )
231+ // Fallback for u64 range (i64::MAX + 1 ..= u64::MAX)
232+ let mut u: u64 = 0 ;
233+ if unsafe { enif_get_uint64 ( env_raw, term. as_c_arg ( ) , & mut u) } != 0 {
234+ let mut itoa_buf = itoa:: Buffer :: new ( ) ;
235+ buf. extend_from_slice ( itoa_buf. format ( u) . as_bytes ( ) ) ;
236+ return Ok ( ( ) ) ;
237+ }
238+ Err ( EncodeError :: BadArg )
213239}
214240
215241#[ inline]
@@ -218,6 +244,10 @@ fn encode_float(env_raw: *mut ErlNifEnv, term: Term, buf: &mut Vec<u8>) -> Resul
218244 if unsafe { enif_get_double ( env_raw, term. as_c_arg ( ) , & mut n) } == 0 {
219245 return Err ( EncodeError :: BadArg ) ;
220246 }
247+ // ryu panics on non-finite floats; JSON has no representation for them
248+ if !n. is_finite ( ) {
249+ return Err ( EncodeError :: BadArg ) ;
250+ }
221251 let mut ryu_buf = ryu:: Buffer :: new ( ) ;
222252 buf. extend_from_slice ( ryu_buf. format ( n) . as_bytes ( ) ) ;
223253 Ok ( ( ) )
@@ -264,12 +294,13 @@ fn encode_tuple(
264294 env_raw : * mut ErlNifEnv ,
265295 term : Term ,
266296 buf : & mut Vec < u8 > ,
297+ depth : u32 ,
267298) -> Result < ( ) , EncodeError > {
268299 let elements = unsafe { get_tuple_raw ( env_raw, term) ? } ;
269300 if elements. len ( ) == 1 {
270301 let inner = unsafe { Term :: new ( env, elements[ 0 ] ) } ;
271302 if inner. get_type ( ) == TermType :: List {
272- return encode_proplist ( env, env_raw, inner, buf) ;
303+ return encode_proplist ( env, env_raw, inner, buf, depth ) ;
273304 }
274305 }
275306 Err ( EncodeError :: BadArg )
@@ -280,7 +311,11 @@ fn encode_proplist(
280311 env_raw : * mut ErlNifEnv ,
281312 term : Term ,
282313 buf : & mut Vec < u8 > ,
314+ depth : u32 ,
283315) -> Result < ( ) , EncodeError > {
316+ if depth == 0 {
317+ return Err ( EncodeError :: DepthExceeded ) ;
318+ }
284319 buf. push ( b'{' ) ;
285320 let mut first = true ;
286321 let mut current = term. as_c_arg ( ) ;
@@ -302,7 +337,7 @@ fn encode_proplist(
302337 let val = unsafe { Term :: new ( env, pair[ 1 ] ) } ;
303338 encode_map_key ( env_raw, key, buf) ?;
304339 buf. push ( b':' ) ;
305- encode_term ( env, env_raw, val, buf) ?;
340+ encode_term ( env, env_raw, val, buf, depth - 1 ) ?;
306341 current = tail;
307342 }
308343 buf. push ( b'}' ) ;
0 commit comments