Fix parsing of \x0\ in partial strings

This commit is contained in:
bakaq
2025-03-02 18:51:57 -03:00
committed by Mark Thom
parent fadcfb966e
commit 9daf016d63
2 changed files with 69 additions and 24 deletions

View File

@@ -485,7 +485,7 @@ mod tests {
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 8);
assert_eq!(heap.cell_len(), 10);
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
@@ -493,12 +493,14 @@ mod tests {
heap.slice_to_str(heap_index!(2), "a stuttered".len()),
"a stuttered"
);
assert_eq!(heap[4], pstr_loc_as_cell!(heap_index!(5)));
assert_eq!(heap[4], list_loc_as_cell!(5));
assert_eq!(heap[5], char_as_cell!('\u{0}'));
assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(
heap.slice_to_str(heap_index!(5), " string".len()),
heap.slice_to_str(heap_index!(7), " string".len()),
" string"
);
assert_eq!(heap[7], empty_list_as_cell!());
assert_eq!(heap[9], empty_list_as_cell!());
}
#[test]

View File

@@ -251,31 +251,73 @@ impl ReservedHeapSection {
}
pub(crate) fn push_pstr(&mut self, mut src: &str) -> Option<HeapCellValue> {
let orig_h = self.cell_len();
if src.is_empty() {
return if orig_h == self.heap_cell_len {
// src is empty and always was. nothing allocated
// in this case, so nothing to point to in heap.
None
} else {
self.push_cell(heap_loc_as_cell!(orig_h));
Some(heap_loc_as_cell!(orig_h))
};
}
let anchor = self.cell_len();
let mut ret = None;
loop {
let null_char_idx = src.find('\u{0}').unwrap_or(src.len());
let cells_written = self.push_pstr_segment(&src[0..null_char_idx]);
// Eat the first null chars
while let Some('\u{0}') = src.chars().next() {
match ret {
Some(_) => {
debug_assert_ne!(anchor, self.cell_len());
self.push_cell(list_loc_as_cell!(self.cell_len() + 1));
}
None => {
debug_assert_eq!(anchor, self.cell_len());
ret = Some(list_loc_as_cell!(self.cell_len()));
}
}
self.push_cell(char_as_cell!('\u{0}'));
src = &src[1..];
}
if src.is_empty() {
return ret;
}
debug_assert!(!src.is_empty());
if let Some(null_char_idx) = src.find('\u{0}') {
debug_assert_ne!(null_char_idx, 0);
match ret {
Some(_) => {
debug_assert_ne!(anchor, self.cell_len());
self.push_cell(pstr_loc_as_cell!(heap_index!(self.cell_len() + 1)));
}
None => {
debug_assert_eq!(anchor, self.cell_len());
ret = Some(pstr_loc_as_cell!(heap_index!(self.cell_len())));
}
}
self.push_pstr_segment(&src[0..null_char_idx]);
// Put the \x0\
self.push_cell(list_loc_as_cell!(self.cell_len() + 1));
self.push_cell(char_as_cell!('\u{0}'));
if cells_written == 0 {
return None;
} else if null_char_idx + 1 < src.len() {
let tail_idx = self.cell_len();
self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1)));
src = &src[null_char_idx + 1..];
if src.is_empty() {
return ret;
}
} else {
return Some(pstr_loc_as_cell!(heap_index!(orig_h)));
match ret {
Some(_) => {
debug_assert_ne!(anchor, self.cell_len());
self.push_cell(pstr_loc_as_cell!(heap_index!(self.cell_len() + 1)));
}
None => {
debug_assert_eq!(anchor, self.cell_len());
ret = Some(pstr_loc_as_cell!(heap_index!(self.cell_len())));
}
}
self.push_pstr_segment(&src);
return ret;
}
}
}
@@ -812,6 +854,7 @@ impl Heap {
pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
let size_in_heap = Self::compute_pstr_size(src);
let pstr_loc = heap_index!(self.cell_len());
Ok(if size_in_heap > 0 {