Skip to content

Commit b3bbdab

Browse files
authored
Fix panic in Postgres Bytes decode (#1948)
This function can panic due to slicing out of bounds when the server responds without the `\x` prefix. With this commit we instead error and also ensure that the prefix is what we expect instead of blindly removing it. Not directly related to the panic, we replace as_str() with as_bytes() because there is no reason to perform a utf8 validity check when hex::decode already checks that the content is valid.
1 parent 79ebd30 commit b3bbdab

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

sqlx-core/src/postgres/types/bytes.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ impl Decode<'_, Postgres> for Vec<u8> {
5555
PgValueFormat::Binary => value.as_bytes()?.to_owned(),
5656
PgValueFormat::Text => {
5757
// BYTEA is formatted as \x followed by hex characters
58-
hex::decode(&value.as_str()?[2..])?
58+
let text = value
59+
.as_bytes()?
60+
.strip_prefix(b"\\x")
61+
.ok_or("text does not start with \\x")?;
62+
hex::decode(text)?
5963
}
6064
})
6165
}

tests/postgres/postgres.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,3 +1713,16 @@ async fn test_advisory_locks() -> anyhow::Result<()> {
17131713

17141714
Ok(())
17151715
}
1716+
1717+
#[sqlx_macros::test]
1718+
async fn test_postgres_bytea_hex_deserialization_errors() -> anyhow::Result<()> {
1719+
let mut conn = new::<Postgres>().await?;
1720+
conn.execute("SET bytea_output = 'escape';").await?;
1721+
for value in ["", "DEADBEEF"] {
1722+
let query = format!("SELECT '\\x{}'::bytea", value);
1723+
let res: sqlx::Result<Vec<u8>> = conn.fetch_one(query.as_str()).await?.try_get(0usize);
1724+
// Deserialization only supports hex format so this should error and definitely not panic.
1725+
res.unwrap_err();
1726+
}
1727+
Ok(())
1728+
}

0 commit comments

Comments
 (0)