Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Check more arithmetic operations #22

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 20 additions & 16 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::externs::{free, malloc, memcpy, memmove, memset, realloc, strdup, strlen};
use crate::ops::{ForceAdd as _, ForceMul as _};
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t};
use crate::{
Expand Down Expand Up @@ -53,7 +54,7 @@ pub(crate) unsafe fn yaml_string_extend(
) {
let new_start: *mut yaml_char_t = yaml_realloc(
*start as *mut libc::c_void,
((*end).c_offset_from(*start) as libc::c_long * 2_i64) as size_t,
(((*end).c_offset_from(*start) as libc::c_long).force_mul(2_i64)) as size_t,
) as *mut yaml_char_t;
memset(
new_start.wrapping_offset((*end).c_offset_from(*start) as libc::c_long as isize)
Expand All @@ -62,8 +63,9 @@ pub(crate) unsafe fn yaml_string_extend(
(*end).c_offset_from(*start) as libc::c_long as libc::c_ulong,
);
*pointer = new_start.wrapping_offset((*pointer).c_offset_from(*start) as libc::c_long as isize);
*end =
new_start.wrapping_offset(((*end).c_offset_from(*start) as libc::c_long * 2_i64) as isize);
*end = new_start.wrapping_offset(
(((*end).c_offset_from(*start) as libc::c_long).force_mul(2_i64)) as isize,
);
*start = new_start;
}

Expand Down Expand Up @@ -99,16 +101,16 @@ pub(crate) unsafe fn yaml_stack_extend(
) {
let new_start: *mut libc::c_void = yaml_realloc(
*start,
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as size_t,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long)
.force_mul(2_i64)) as size_t,
);
*top = (new_start as *mut libc::c_char).wrapping_offset(
(*top as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
as isize,
) as *mut libc::c_void;
*end = (new_start as *mut libc::c_char).wrapping_offset(
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as isize,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long)
.force_mul(2_i64)) as isize,
) as *mut libc::c_void;
*start = new_start;
}
Expand All @@ -122,8 +124,9 @@ pub(crate) unsafe fn yaml_queue_extend(
if *start == *head && *tail == *end {
let new_start: *mut libc::c_void = yaml_realloc(
*start,
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as size_t,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char)
as libc::c_long)
.force_mul(2_i64)) as size_t,
);
*head = (new_start as *mut libc::c_char).wrapping_offset(
(*head as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
Expand All @@ -134,8 +137,9 @@ pub(crate) unsafe fn yaml_queue_extend(
as isize,
) as *mut libc::c_void;
*end = (new_start as *mut libc::c_char).wrapping_offset(
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as isize,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char)
as libc::c_long)
.force_mul(2_i64)) as isize,
) as *mut libc::c_void;
*start = new_start;
}
Expand Down Expand Up @@ -374,7 +378,7 @@ unsafe fn yaml_string_write_handler(
size,
);
let fresh153 = addr_of_mut!((*(*emitter).output.string.size_written));
*fresh153 = (*fresh153 as libc::c_ulong).wrapping_add(size) as size_t;
*fresh153 = (*fresh153 as libc::c_ulong).force_add(size) as size_t;
1
}

Expand Down Expand Up @@ -532,8 +536,8 @@ unsafe fn yaml_check_utf8(start: *const yaml_char_t, length: size_t) -> Success
if octet & 0xC0 != 0x80 {
return FAIL;
}
value = (value << 6).wrapping_add((octet & 0x3F) as libc::c_uint);
k = k.wrapping_add(1);
value = (value << 6).force_add((octet & 0x3F) as libc::c_uint);
k = k.force_add(1);
}
if !(width == 1
|| width == 2 && value >= 0x80
Expand Down Expand Up @@ -826,7 +830,7 @@ pub unsafe fn yaml_scalar_event_initialize(
length = strlen(value as *mut libc::c_char) as libc::c_int;
}
if yaml_check_utf8(value, length as size_t).ok {
value_copy = yaml_malloc((length + 1) as size_t) as *mut yaml_char_t;
value_copy = yaml_malloc(length.force_add(1) as size_t) as *mut yaml_char_t;
memcpy(
value_copy as *mut libc::c_void,
value as *const libc::c_void,
Expand Down Expand Up @@ -1333,7 +1337,7 @@ pub unsafe fn yaml_document_add_scalar(
length = strlen(value as *mut libc::c_char) as libc::c_int;
}
if yaml_check_utf8(value, length as size_t).ok {
value_copy = yaml_malloc((length + 1) as size_t) as *mut yaml_char_t;
value_copy = yaml_malloc(length.force_add(1) as size_t) as *mut yaml_char_t;
memcpy(
value_copy as *mut libc::c_void,
value as *const libc::c_void,
Expand Down
5 changes: 3 additions & 2 deletions src/dumper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::api::{yaml_free, yaml_malloc};
use crate::externs::{memset, strcmp};
use crate::fmt::WriteToPtr;
use crate::ops::ForceMul as _;
use crate::success::{Success, FAIL, OK};
use crate::yaml::{
yaml_anchors_t, yaml_char_t, yaml_document_t, yaml_emitter_t, yaml_event_t, yaml_mark_t,
Expand Down Expand Up @@ -116,14 +117,14 @@ pub unsafe fn yaml_emitter_dump(
let fresh1 = addr_of_mut!((*emitter).anchors);
*fresh1 = yaml_malloc(
(size_of::<yaml_anchors_t>() as libc::c_ulong)
.wrapping_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
.force_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
as libc::c_long as libc::c_ulong),
) as *mut yaml_anchors_t;
memset(
(*emitter).anchors as *mut libc::c_void,
0,
(size_of::<yaml_anchors_t>() as libc::c_ulong)
.wrapping_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
.force_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
as libc::c_long as libc::c_ulong),
);
memset(
Expand Down
50 changes: 22 additions & 28 deletions src/emitter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::api::{yaml_free, yaml_queue_extend, yaml_stack_extend, yaml_strdup};
use crate::externs::{strcmp, strlen, strncmp};
use crate::ops::{ForceAdd as _, ForceMul as _};
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t, yaml_string_t};
use crate::{
Expand Down Expand Up @@ -296,7 +297,9 @@ unsafe fn yaml_emitter_emit_stream_start(
if (*emitter).best_indent < 2 || (*emitter).best_indent > 9 {
(*emitter).best_indent = 2;
}
if (*emitter).best_width >= 0 && (*emitter).best_width <= (*emitter).best_indent * 2 {
if (*emitter).best_width >= 0
&& (*emitter).best_width <= (*emitter).best_indent.force_mul(2)
{
(*emitter).best_width = 80;
}
if (*emitter).best_width < 0 {
Expand Down Expand Up @@ -1045,45 +1048,36 @@ unsafe fn yaml_emitter_check_simple_key(emitter: *mut yaml_emitter_t) -> bool {
let mut length: size_t = 0_u64;
match (*event).type_ {
YAML_ALIAS_EVENT => {
length = (length as libc::c_ulong).wrapping_add((*emitter).anchor_data.anchor_length)
as size_t;
length =
(length as libc::c_ulong).force_add((*emitter).anchor_data.anchor_length) as size_t;
}
YAML_SCALAR_EVENT => {
if (*emitter).scalar_data.multiline {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length)
.wrapping_add((*emitter).scalar_data.length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length)
.force_add((*emitter).scalar_data.length) as size_t;
}
YAML_SEQUENCE_START_EVENT => {
if !yaml_emitter_check_empty_sequence(emitter) {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length) as size_t;
}
YAML_MAPPING_START_EVENT => {
if !yaml_emitter_check_empty_mapping(emitter) {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length) as size_t;
}
_ => return false,
}
Expand Down Expand Up @@ -1825,15 +1819,15 @@ unsafe fn yaml_emitter_write_tag_content(
}
if PUT(
emitter,
(value >> 4).wrapping_add(if (value >> 4) < 10 { b'0' } else { b'A' - 10 }),
(value >> 4).force_add(if (value >> 4) < 10 { b'0' } else { b'A' - 10 }),
)
.fail
{
return FAIL;
}
if PUT(
emitter,
(value & 0x0F).wrapping_add(if (value & 0x0F) < 10 { b'0' } else { b'A' - 10 }),
(value & 0x0F).force_add(if (value & 0x0F) < 10 { b'0' } else { b'A' - 10 }),
)
.fail
{
Expand Down Expand Up @@ -2051,7 +2045,7 @@ unsafe fn yaml_emitter_write_double_quoted_scalar(
k = 1;
while k < width as libc::c_int {
octet = *string.pointer.wrapping_offset(k as isize);
value_0 = (value_0 << 6).wrapping_add((octet & 0x3F) as libc::c_uint);
value_0 = (value_0 << 6).force_add((octet & 0x3F) as libc::c_uint);
k += 1;
}
string.pointer = string.pointer.wrapping_offset(width as isize);
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ mod api;
mod dumper;
mod emitter;
mod loader;
mod ops;
mod parser;
mod reader;
mod scanner;
Expand Down
88 changes: 88 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
pub(crate) trait ForceAdd: Sized {
fn force_add(self, rhs: Self) -> Self;
}

impl ForceAdd for u8 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for i32 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for u32 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for u64 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

pub(crate) trait ForceMul: Sized {
fn force_mul(self, rhs: Self) -> Self;
}

impl ForceMul for i32 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

impl ForceMul for i64 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

impl ForceMul for u64 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

// Deterministically abort on arithmetic overflow, instead of wrapping and
// continuing with invalid behavior.
//
// This is impossible or nearly impossible to hit as the arithmetic computations
// in libyaml are all related to either:
//
// - small integer processing (ascii, hex digits)
// - allocation sizing
//
// and the only allocations in libyaml are for fixed-sized objects and
// geometrically growing buffers with a growth factor of 2. So in order for an
// allocation computation to overflow usize, the previous allocation for that
// container must have been filled to a size of usize::MAX/2, which is an
// allocation that would have failed in the allocator. But we check for this to
// be pedantic and to find out if it ever does happen.
//
// No-std abort is implemented using a double panic. On most platforms the
// current mechanism for this is for core::intrinsics::abort to invoke an
// invalid instruction. On Unix, the process will probably terminate with a
// signal like SIGABRT, SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise
// behaviour is not guaranteed and not stable, but is safe.
#[cold]
pub(crate) fn die<T>() -> T {
struct PanicAgain;

impl Drop for PanicAgain {
fn drop(&mut self) {
panic!("arithmetic overflow");
}
}

fn do_die() -> ! {
let _panic_again = PanicAgain;
panic!("arithmetic overflow");
}

do_die();
}
9 changes: 4 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::api::{yaml_free, yaml_malloc, yaml_stack_extend, yaml_strdup};
use crate::externs::{memcpy, memset, strcmp, strlen};
use crate::ops::ForceAdd as _;
use crate::scanner::yaml_parser_fetch_more_tokens;
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t};
Expand Down Expand Up @@ -504,9 +505,8 @@ unsafe fn yaml_parser_parse_node(
let prefix_len: size_t =
strlen((*tag_directive).prefix as *mut libc::c_char);
let suffix_len: size_t = strlen(tag_suffix as *mut libc::c_char);
tag = yaml_malloc(
prefix_len.wrapping_add(suffix_len).wrapping_add(1_u64),
) as *mut yaml_char_t;
tag = yaml_malloc(prefix_len.force_add(suffix_len).force_add(1_u64))
as *mut yaml_char_t;
memcpy(
tag as *mut libc::c_void,
(*tag_directive).prefix as *const libc::c_void,
Expand All @@ -517,8 +517,7 @@ unsafe fn yaml_parser_parse_node(
tag_suffix as *const libc::c_void,
suffix_len,
);
*tag.wrapping_offset(prefix_len.wrapping_add(suffix_len) as isize) =
b'\0';
*tag.wrapping_offset(prefix_len.force_add(suffix_len) as isize) = b'\0';
yaml_free(tag_handle as *mut libc::c_void);
yaml_free(tag_suffix as *mut libc::c_void);
tag_suffix = ptr::null_mut::<yaml_char_t>();
Expand Down