Skip to content

Commit 4504f9c

Browse files
committed
Properly detect overflow
1 parent 6635aaf commit 4504f9c

File tree

4 files changed

+52
-14
lines changed

4 files changed

+52
-14
lines changed

src/message.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,23 +161,23 @@ impl<W: Write> WriteMessage for W {
161161
try!(buf.write_cstr(portal));
162162
try!(buf.write_cstr(statement));
163163

164-
try!(buf.write_u16::<BigEndian>(formats.len() as u16));
164+
try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(formats.len()))));
165165
for &format in formats {
166166
try!(buf.write_i16::<BigEndian>(format));
167167
}
168168

169-
try!(buf.write_u16::<BigEndian>(values.len() as u16));
169+
try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(values.len()))));
170170
for value in values {
171171
match *value {
172172
None => try!(buf.write_i32::<BigEndian>(-1)),
173173
Some(ref value) => {
174-
try!(buf.write_i32::<BigEndian>(value.len() as i32));
174+
try!(buf.write_i32::<BigEndian>(try!(i32::from_usize(value.len()))));
175175
try!(buf.write_all(&**value));
176176
}
177177
}
178178
}
179179

180-
try!(buf.write_u16::<BigEndian>(result_formats.len() as u16));
180+
try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(result_formats.len()))));
181181
for &format in result_formats {
182182
try!(buf.write_i16::<BigEndian>(format));
183183
}
@@ -215,7 +215,7 @@ impl<W: Write> WriteMessage for W {
215215
ident = Some(b'P');
216216
try!(buf.write_cstr(name));
217217
try!(buf.write_cstr(query));
218-
try!(buf.write_u16::<BigEndian>(param_types.len() as u16));
218+
try!(buf.write_u16::<BigEndian>(try!(u16::from_usize(param_types.len()))));
219219
for &ty in param_types {
220220
try!(buf.write_u32::<BigEndian>(ty));
221221
}
@@ -246,7 +246,7 @@ impl<W: Write> WriteMessage for W {
246246
}
247247

248248
// add size of length value
249-
try!(self.write_u32::<BigEndian>((buf.len() + mem::size_of::<u32>()) as u32));
249+
try!(self.write_u32::<BigEndian>(try!(u32::from_usize(buf.len() + mem::size_of::<u32>()))));
250250
try!(self.write_all(&*buf));
251251

252252
Ok(())
@@ -407,3 +407,25 @@ fn read_row_description<R: BufRead>(buf: &mut R) -> io::Result<BackendMessage> {
407407

408408
Ok(RowDescription { descriptions: types })
409409
}
410+
411+
trait FromUsize {
412+
fn from_usize(x: usize) -> io::Result<Self>;
413+
}
414+
415+
macro_rules! from_usize {
416+
($t:ty) => {
417+
impl FromUsize for $t {
418+
fn from_usize(x: usize) -> io::Result<$t> {
419+
if x > <$t>::max_value() as usize {
420+
Err(io::Error::new(io::ErrorKind::InvalidInput, "value too large to transmit"))
421+
} else {
422+
Ok(x as $t)
423+
}
424+
}
425+
}
426+
}
427+
}
428+
429+
from_usize!(u16);
430+
from_usize!(i32);
431+
from_usize!(u32);

src/types/chrono.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
extern crate chrono;
22

3+
use std::error;
34
use std::io::prelude::*;
45
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
56
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC};
67

78
use Result;
9+
use error::Error;
810
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
911

1012
fn base() -> NaiveDateTime {
@@ -61,8 +63,13 @@ impl FromSql for NaiveDate {
6163

6264
impl ToSql for NaiveDate {
6365
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo) -> Result<IsNull> {
64-
let jd = *self - base().date();
65-
try!(w.write_i32::<BigEndian>(jd.num_days() as i32));
66+
let jd = (*self - base().date()).num_days();
67+
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
68+
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
69+
return Err(Error::Conversion(err));
70+
}
71+
72+
try!(w.write_i32::<BigEndian>(jd as i32));
6673
Ok(IsNull::No)
6774
}
6875

src/types/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -934,15 +934,15 @@ impl ToSql for HashMap<String, Option<String>> {
934934

935935
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
936936
-> Result<IsNull> {
937-
try!(w.write_i32::<BigEndian>(self.len() as i32));
937+
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
938938

939939
for (key, val) in self {
940-
try!(w.write_i32::<BigEndian>(key.len() as i32));
940+
try!(w.write_i32::<BigEndian>(try!(downcast(key.len()))));
941941
try!(w.write_all(key.as_bytes()));
942942

943943
match *val {
944944
Some(ref val) => {
945-
try!(w.write_i32::<BigEndian>(val.len() as i32));
945+
try!(w.write_i32::<BigEndian>(try!(downcast(val.len()))));
946946
try!(w.write_all(val.as_bytes()));
947947
}
948948
None => try!(w.write_i32::<BigEndian>(-1))
@@ -959,3 +959,12 @@ impl ToSql for HashMap<String, Option<String>> {
959959
}
960960
}
961961
}
962+
963+
fn downcast(len: usize) -> Result<i32> {
964+
if len > i32::max_value() as usize {
965+
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
966+
Err(Error::Conversion(err))
967+
} else {
968+
Ok(len as i32)
969+
}
970+
}

src/types/slice.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use byteorder::{WriteBytesExt, BigEndian};
33

44
use Result;
55
use error::Error;
6-
use types::{Type, ToSql, Kind, IsNull, SessionInfo};
6+
use types::{Type, ToSql, Kind, IsNull, SessionInfo, downcast};
77

88
/// An adapter type mapping slices to Postgres arrays.
99
///
@@ -48,14 +48,14 @@ impl<'a, T: 'a + ToSql> ToSql for Slice<'a, T> {
4848
try!(w.write_i32::<BigEndian>(1)); // has nulls
4949
try!(w.write_u32::<BigEndian>(member_type.oid()));
5050

51-
try!(w.write_i32::<BigEndian>(self.0.len() as i32));
51+
try!(w.write_i32::<BigEndian>(try!(downcast(self.0.len()))));
5252
try!(w.write_i32::<BigEndian>(0)); // index offset
5353

5454
let mut inner_buf = vec![];
5555
for e in self.0 {
5656
match try!(e.to_sql(&member_type, &mut inner_buf, ctx)) {
5757
IsNull::No => {
58-
try!(w.write_i32::<BigEndian>(inner_buf.len() as i32));
58+
try!(w.write_i32::<BigEndian>(try!(downcast(inner_buf.len()))));
5959
try!(w.write_all(&inner_buf));
6060
}
6161
IsNull::Yes => try!(w.write_i32::<BigEndian>(-1)),

0 commit comments

Comments
 (0)