@@ -2,18 +2,18 @@ use std::{
22 collections:: { btree_map, BTreeMap } ,
33 mem:: size_of,
44 ops:: { Deref , DerefMut } ,
5- str:: from_utf8 ,
5+ str,
66} ;
77
8- use serde:: { Deserialize , Serialize } ;
9-
108use crate :: {
119 decode:: Decode ,
1210 encode:: { Encode , IsNull } ,
1311 error:: BoxDynError ,
1412 types:: Type ,
1513 PgArgumentBuffer , PgTypeInfo , PgValueRef , Postgres ,
1614} ;
15+ use serde:: { Deserialize , Serialize } ;
16+ use sqlx_core:: bytes:: Buf ;
1717
1818/// Key-value support (`hstore`) for Postgres.
1919///
@@ -143,41 +143,64 @@ impl<'r> Decode<'r, Postgres> for PgHstore {
143143 let mut buf = <& [ u8 ] as Decode < Postgres > >:: decode ( value) ?;
144144 let len = read_length ( & mut buf) ?;
145145
146- if len < 0 {
147- Err ( format ! ( "hstore, invalid entry count: {len}" ) ) ?;
148- }
146+ let len =
147+ usize:: try_from ( len) . map_err ( |_| format ! ( "PgHstore: length out of range: {len}" ) ) ?;
149148
150149 let mut result = Self :: default ( ) ;
151150
152- while !buf. is_empty ( ) {
153- let key_len = read_length ( & mut buf) ?;
154- let key = read_value ( & mut buf, key_len) ?. ok_or ( "hstore, key not found" ) ?;
151+ for i in 0 ..len {
152+ let key = read_string ( & mut buf)
153+ . map_err ( |e| format ! ( "PgHstore: error reading {i}th key: {e}" ) ) ?
154+ . ok_or_else ( || format ! ( "PgHstore: expected {i}th key, got nothing" ) ) ?;
155155
156- let value_len = read_length ( & mut buf) ? ;
157- let value = read_value ( & mut buf , value_len ) ?;
156+ let value = read_string ( & mut buf)
157+ . map_err ( |e| format ! ( "PgHstore: error reading value for key {key:?}: {e}" ) ) ?;
158158
159159 result. insert ( key, value) ;
160160 }
161161
162+ if !buf. is_empty ( ) {
163+ tracing:: warn!( "{} unread bytes at the end of HSTORE value" , buf. len( ) ) ;
164+ }
165+
162166 Ok ( result)
163167 }
164168}
165169
166170impl Encode < ' _ , Postgres > for PgHstore {
167171 fn encode_by_ref ( & self , buf : & mut PgArgumentBuffer ) -> Result < IsNull , BoxDynError > {
168- buf. extend_from_slice ( & i32:: to_be_bytes ( self . 0 . len ( ) as i32 ) ) ;
169-
170- for ( key, val) in & self . 0 {
172+ buf. extend_from_slice ( & i32:: to_be_bytes (
173+ self . 0
174+ . len ( )
175+ . try_into ( )
176+ . map_err ( |_| format ! ( "PgHstore length out of range: {}" , self . 0 . len( ) ) ) ?,
177+ ) ) ;
178+
179+ for ( i, ( key, val) ) in self . 0 . iter ( ) . enumerate ( ) {
171180 let key_bytes = key. as_bytes ( ) ;
172181
173- buf. extend_from_slice ( & i32:: to_be_bytes ( key_bytes. len ( ) as i32 ) ) ;
182+ let key_len = i32:: try_from ( key_bytes. len ( ) ) . map_err ( |_| {
183+ // Doesn't make sense to print the key itself: it's more than 2 GiB long!
184+ format ! (
185+ "PgHstore: length of {i}th key out of range: {} bytes" ,
186+ key_bytes. len( )
187+ )
188+ } ) ?;
189+
190+ buf. extend_from_slice ( & i32:: to_be_bytes ( key_len) ) ;
174191 buf. extend_from_slice ( key_bytes) ;
175192
176193 match val {
177194 Some ( val) => {
178195 let val_bytes = val. as_bytes ( ) ;
179196
180- buf. extend_from_slice ( & i32:: to_be_bytes ( val_bytes. len ( ) as i32 ) ) ;
197+ let val_len = i32:: try_from ( key_bytes. len ( ) ) . map_err ( |_| {
198+ format ! (
199+ "PgHstore: value length for key {key:?} out of range: {} bytes" ,
200+ val_bytes. len( )
201+ )
202+ } ) ?;
203+ buf. extend_from_slice ( & i32:: to_be_bytes ( val_len) ) ;
181204 buf. extend_from_slice ( val_bytes) ;
182205 }
183206 None => {
@@ -190,30 +213,36 @@ impl Encode<'_, Postgres> for PgHstore {
190213 }
191214}
192215
193- fn read_length ( buf : & mut & [ u8 ] ) -> Result < i32 , BoxDynError > {
194- let ( bytes, rest) = buf. split_at ( size_of :: < i32 > ( ) ) ;
195-
196- * buf = rest;
216+ fn read_length ( buf : & mut & [ u8 ] ) -> Result < i32 , String > {
217+ if buf. len ( ) < size_of :: < i32 > ( ) {
218+ return Err ( format ! (
219+ "expected {} bytes, got {}" ,
220+ size_of:: <i32 >( ) ,
221+ buf. len( )
222+ ) ) ;
223+ }
197224
198- Ok ( i32:: from_be_bytes (
199- bytes
200- . try_into ( )
201- . map_err ( |err| format ! ( "hstore, reading length: {err}" ) ) ?,
202- ) )
225+ Ok ( buf. get_i32 ( ) )
203226}
204227
205- fn read_value ( buf : & mut & [ u8 ] , len : i32 ) -> Result < Option < String > , BoxDynError > {
228+ fn read_string ( buf : & mut & [ u8 ] ) -> Result < Option < String > , String > {
229+ let len = read_length ( buf) ?;
230+
206231 match len {
207- len if len <= 0 => Ok ( None ) ,
232+ - 1 => Ok ( None ) ,
208233 len => {
209- let ( val, rest) = buf. split_at ( len as usize ) ;
234+ let len =
235+ usize:: try_from ( len) . map_err ( |_| format ! ( "string length out of range: {len}" ) ) ?;
236+
237+ if buf. len ( ) < len {
238+ return Err ( format ! ( "expected {len} bytes, got {}" , buf. len( ) ) ) ;
239+ }
210240
241+ let ( val, rest) = buf. split_at ( len) ;
211242 * buf = rest;
212243
213244 Ok ( Some (
214- from_utf8 ( val)
215- . map_err ( |err| format ! ( "hstore, reading value: {err}" ) ) ?
216- . to_string ( ) ,
245+ str:: from_utf8 ( val) . map_err ( |e| e. to_string ( ) ) ?. to_string ( ) ,
217246 ) )
218247 }
219248 }
0 commit comments