@@ -2,18 +2,18 @@ use std::{
2
2
collections:: { btree_map, BTreeMap } ,
3
3
mem:: size_of,
4
4
ops:: { Deref , DerefMut } ,
5
- str:: from_utf8 ,
5
+ str,
6
6
} ;
7
7
8
- use serde:: { Deserialize , Serialize } ;
9
-
10
8
use crate :: {
11
9
decode:: Decode ,
12
10
encode:: { Encode , IsNull } ,
13
11
error:: BoxDynError ,
14
12
types:: Type ,
15
13
PgArgumentBuffer , PgTypeInfo , PgValueRef , Postgres ,
16
14
} ;
15
+ use serde:: { Deserialize , Serialize } ;
16
+ use sqlx_core:: bytes:: Buf ;
17
17
18
18
/// Key-value support (`hstore`) for Postgres.
19
19
///
@@ -143,41 +143,64 @@ impl<'r> Decode<'r, Postgres> for PgHstore {
143
143
let mut buf = <& [ u8 ] as Decode < Postgres > >:: decode ( value) ?;
144
144
let len = read_length ( & mut buf) ?;
145
145
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}" ) ) ?;
149
148
150
149
let mut result = Self :: default ( ) ;
151
150
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" ) ) ?;
155
155
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}" ) ) ?;
158
158
159
159
result. insert ( key, value) ;
160
160
}
161
161
162
+ if !buf. is_empty ( ) {
163
+ tracing:: warn!( "{} unread bytes at the end of HSTORE value" , buf. len( ) ) ;
164
+ }
165
+
162
166
Ok ( result)
163
167
}
164
168
}
165
169
166
170
impl Encode < ' _ , Postgres > for PgHstore {
167
171
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 ( ) {
171
180
let key_bytes = key. as_bytes ( ) ;
172
181
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) ) ;
174
191
buf. extend_from_slice ( key_bytes) ;
175
192
176
193
match val {
177
194
Some ( val) => {
178
195
let val_bytes = val. as_bytes ( ) ;
179
196
180
- buf. extend_from_slice ( & i32:: to_be_bytes ( val_bytes. len ( ) as i32 ) ) ;
197
+ let val_len = i32:: try_from ( val_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) ) ;
181
204
buf. extend_from_slice ( val_bytes) ;
182
205
}
183
206
None => {
@@ -190,30 +213,36 @@ impl Encode<'_, Postgres> for PgHstore {
190
213
}
191
214
}
192
215
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
+ }
197
224
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 ( ) )
203
226
}
204
227
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
+
206
231
match len {
207
- len if len <= 0 => Ok ( None ) ,
232
+ - 1 => Ok ( None ) ,
208
233
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
+ }
210
240
241
+ let ( val, rest) = buf. split_at ( len) ;
211
242
* buf = rest;
212
243
213
244
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 ( ) ,
217
246
) )
218
247
}
219
248
}
@@ -258,7 +287,7 @@ mod test {
258
287
}
259
288
260
289
#[ test]
261
- #[ should_panic( expected = "hstore, invalid entry count : -5" ) ]
290
+ #[ should_panic( expected = "PgHstore: length out of range : -5" ) ]
262
291
fn hstore_deserialize_buffer_length_error ( ) {
263
292
let buf = PgValueRef {
264
293
value : Some ( & [ 255 , 255 , 255 , 251 ] ) ,
0 commit comments