make SvPVbyte safe

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-11-26 10:13:48 +01:00
parent ccde914a4c
commit 83147b1189
5 changed files with 24 additions and 14 deletions

View File

@ -81,7 +81,7 @@ impl Deserializer {
use crate::scalar::Flags;
if flags.contains(Flags::STRING) {
visitor.visit_str(value.pv_utf8())
visitor.visit_str(value.pv_string_utf8())
} else if flags.contains(Flags::DOUBLE) {
visitor.visit_f64(value.nv())
} else if flags.contains(Flags::INTEGER) {
@ -113,7 +113,7 @@ impl Deserializer {
} else if flags.contains(Flags::DOUBLE) {
visitor.visit_f64(value.nv())
} else if flags.contains(Flags::STRING) {
visitor.visit_str(value.pv_utf8())
visitor.visit_str(value.pv_string_utf8())
} else {
visitor.visit_unit()
}
@ -141,7 +141,7 @@ impl Deserializer {
} else if flags.contains(Flags::INTEGER) {
visitor.visit_i64(value.iv() as i64)
} else if flags.contains(Flags::STRING) {
visitor.visit_str(value.pv_utf8())
visitor.visit_str(value.pv_string_utf8())
} else {
visitor.visit_unit()
}
@ -277,11 +277,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer {
} else if flags.contains(Flags::DOUBLE) {
visitor.visit_f64(value.nv())
} else if flags.contains(Flags::STRING) {
let s = value.pv_utf8();
let s = value.pv_string_utf8();
let mut chars = s.chars();
match chars.next() {
Some(ch) if chars.next().is_none() => visitor.visit_char(ch),
_ => visitor.visit_str(value.pv_utf8()),
_ => visitor.visit_str(value.pv_string_utf8()),
}
} else {
visitor.visit_unit()

View File

@ -45,6 +45,7 @@ extern "C" {
pub fn RSPL_SvIV(sv: *mut SV) -> isize;
pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
pub fn RSPL_SvPV(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
/// This calls `sv_utf8_downgrade` first to avoid croaking, instead returns `NULL` on error.
pub fn RSPL_SvPVbyte(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
pub fn RSPL_sv_2mortal(sv: *mut SV) -> *mut SV;
pub fn RSPL_get_undef() -> *mut SV;

View File

@ -55,8 +55,11 @@ extern const char* RSPL_SvPV(SV *sv, size_t *out_len) {
return out;
}
/// SvPVbyte with a downgrade check to avoid croaking!
extern const char* RSPL_SvPVbyte(SV *sv, size_t *out_len) {
size_t length;
if (!sv_utf8_downgrade(sv, true))
return NULL;
const char *out = SvPVbyte(sv, length);
*out_len = length;
return out;

View File

@ -229,7 +229,7 @@ impl ScalarRef {
}
/// Coerce to an utf8 string value. (perlxs `SvPVutf8`)
pub fn pv_utf8(&self) -> &str {
pub fn pv_string_utf8(&self) -> &str {
unsafe {
let mut len: libc::size_t = 0;
let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8;
@ -238,7 +238,7 @@ impl ScalarRef {
}
/// Coerce to a string without utf8 encoding. (perlxs `SvPV`)
pub fn pv_string_bytes(&self) -> &[u8] {
pub fn pv_bytes(&self) -> &[u8] {
unsafe {
let mut len: libc::size_t = 0;
let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8;
@ -246,12 +246,18 @@ impl ScalarRef {
}
}
/// Coerce to a byte-string. (perlxs `SvPVbyte`)
pub fn pv_bytes(&self) -> &[u8] {
/// Coerce to a byte-string, downgrading from utf-8. (perlxs `SvPVbyte`)
///
/// May fail if there are values which don't fit into bytes in the contained utf-8 string, in
/// which case `None` is returned.
pub fn pv_utf8_to_bytes(&self) -> Option<&[u8]> {
unsafe {
let mut len: libc::size_t = 0;
let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8;
std::slice::from_raw_parts(ptr, len)
if ptr.is_null() {
return None;
}
Some(std::slice::from_raw_parts(ptr, len))
}
}
@ -314,7 +320,7 @@ impl std::fmt::Debug for ScalarRef {
match self.ty() {
Type::Scalar(flags) => {
if flags.intersects(Flags::STRING) {
Debug::fmt(self.pv_utf8(), f)
Debug::fmt(self.pv_string_utf8(), f)
} else if flags.intersects(Flags::INTEGER) {
write!(f, "{}", self.iv())
} else if flags.intersects(Flags::DOUBLE) {
@ -341,7 +347,7 @@ impl serde::Serialize for Scalar {
match self.ty() {
Type::Scalar(flags) => {
if flags.contains(Flags::STRING) {
serializer.serialize_str(self.pv_utf8())
serializer.serialize_str(self.pv_string_utf8())
} else if flags.contains(Flags::DOUBLE) {
serializer.serialize_f64(self.nv())
} else if flags.contains(Flags::INTEGER) {

View File

@ -137,7 +137,7 @@ impl Value {
if stash.is_null() {
return Err(Error(format!(
"failed to find package {:?}",
pkgsv.pv_utf8()
pkgsv.pv_string_utf8()
)));
}
@ -145,7 +145,7 @@ impl Value {
if value.is_null() {
return Err(Error(format!(
"failed to bless value into package {:?}",
pkgsv.pv_utf8()
pkgsv.pv_string_utf8()
)));
}