From 1300d4323f4e50146defc4a97010556f7ec0a3d7 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi Date: Sun, 16 Aug 2026 18:31:40 -0500 Subject: [PATCH 1/3] feat(value): freeze objects into boxed-slice storage Introduce a compact storage representation for Object values to cut per-object memory overhead. `Object` now uses a private `Repr` enum: - Empty no allocation - Inline(Box>) small maps in one compact allocation - Frozen(Box<[(k, v)]>) read-mostly objects packed into a boxed slice - BTree(BTreeMap) large, mutable ordered maps Objects deserialized/constructed as data are frozen into boxed slices; the first structural mutation thaws back to an inline SmallVec (<= INLINE_CAP) or BTreeMap. Value-overwrite and get_mut of an existing key stay frozen (value-only mutation preserves storage). Call sites that mutate objects (builtins, engine, interpreter, rvm, azure_policy templates) are adapted to the freeze/thaw boundary. This is an internal representation change with no public API changes. Freezing is depth-bounded (MAX_MERGE_DEPTH) to prevent a stack overflow on adversarially nested data that reaches freezing via programmatic construction. Iteration uses a self-owned, key-based ObjectCursor that resumes correctly across storage transitions. The object module is split into cohesive sub-300-line files (mod/mutate/freeze/cursor/iter/serde). Adds freeze/thaw unit tests (src/value/tests.rs) and SARIF/corpus memory-residency integration tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ac07e53-88fc-4050-bd56-c0d9761b911b --- .../template_functions_collection.rs | 30 +- .../azure_policy/template_functions_misc.rs | 6 +- src/builtins/objects.rs | 3 +- src/engine.rs | 15 +- src/rvm/program/serialization/value.rs | 9 +- src/rvm/vm/comprehension.rs | 25 +- src/value/mod.rs | 8 +- src/value/object/cursor.rs | 75 + src/value/object/freeze.rs | 88 + src/value/object/iter.rs | 153 +- src/value/object/mod.rs | 253 +- src/value/object/mutate.rs | 155 + src/value/object/serde.rs | 5 + src/value/tests.rs | 174 + tests/data/sarif_memory/input.json | 9742 +++++++++++++++++ tests/data/sarif_memory/policy.rego | 84 + tests/sarif_memory.rs | 224 + 17 files changed, 10833 insertions(+), 216 deletions(-) create mode 100644 src/value/object/cursor.rs create mode 100644 src/value/object/freeze.rs create mode 100644 src/value/object/mutate.rs create mode 100644 tests/data/sarif_memory/input.json create mode 100644 tests/data/sarif_memory/policy.rego create mode 100644 tests/sarif_memory.rs diff --git a/src/builtins/azure_policy/template_functions_collection.rs b/src/builtins/azure_policy/template_functions_collection.rs index 974063264..18c0e289d 100644 --- a/src/builtins/azure_policy/template_functions_collection.rs +++ b/src/builtins/azure_policy/template_functions_collection.rs @@ -10,7 +10,6 @@ use crate::builtins; use crate::lexer::Span; use crate::value::Object; use crate::value::Value; -use crate::Rc; use alloc::vec::Vec; use anyhow::Result; @@ -79,7 +78,9 @@ fn fn_intersection( }; result.retain(|k, v| other.get(k).is_some_and(|ov| *ov == *v)); } - Ok(Value::Object(Rc::new(result))) + let value = result.into_value(); + crate::utils::limits::enforce_memory_limit().map_err(anyhow::Error::new)?; + Ok(value) } _ => Ok(Value::Undefined), } @@ -123,14 +124,19 @@ fn fn_union(_span: &Span, _params: &[Ref], args: &[Value], _strict: bool) #[allow(clippy::needless_borrowed_reference)] let merged = match (result.get(k), v) { (Some(&Value::Object(ref prev)), &Value::Object(ref next)) => { - merge_objects(prev, next) + merge_objects(prev, next)? } _ => v.clone(), }; result.insert(k.clone(), merged); + // Throttled check bounds peak allocation across nested merges. + crate::utils::limits::check_memory_limit_if_needed() + .map_err(anyhow::Error::new)?; } } - Ok(Value::Object(Rc::new(result))) + let value = result.into_value(); + crate::utils::limits::enforce_memory_limit().map_err(anyhow::Error::new)?; + Ok(value) } _ => Ok(Value::Undefined), } @@ -274,27 +280,35 @@ fn fn_create_object( #[allow(clippy::pattern_type_mismatch)] if let [key, value] = pair { map.insert(key.clone(), value.clone()); + // Throttled check bounds peak allocation while building the object. + crate::utils::limits::check_memory_limit_if_needed().map_err(anyhow::Error::new)?; } } - Ok(Value::Object(Rc::new(map))) + let value = map.into_value(); + crate::utils::limits::enforce_memory_limit().map_err(anyhow::Error::new)?; + Ok(value) } // ── Helpers ─────────────────────────────────────────────────────────── /// Recursively merge two objects. Nested objects are merged; everything /// else (including arrays) uses the value from `incoming`. -fn merge_objects(base: &Object, overlay: &Object) -> Value { +fn merge_objects(base: &Object, overlay: &Object) -> Result { let mut result = base.clone(); for (k, v) in overlay.iter() { #[allow(clippy::needless_borrowed_reference)] let merged = match (result.get(k), v) { - (Some(&Value::Object(ref prev)), &Value::Object(ref next)) => merge_objects(prev, next), + (Some(&Value::Object(ref prev)), &Value::Object(ref next)) => { + merge_objects(prev, next)? + } _ => v.clone(), }; result.insert(k.clone(), merged); + // Throttled check bounds peak allocation across recursive merges. + crate::utils::limits::check_memory_limit_if_needed().map_err(anyhow::Error::new)?; } - Value::Object(Rc::new(result)) + Ok(result.into_value()) } fn extract_usize(v: &Value) -> Option { diff --git a/src/builtins/azure_policy/template_functions_misc.rs b/src/builtins/azure_policy/template_functions_misc.rs index dea7e9c19..c304078da 100644 --- a/src/builtins/azure_policy/template_functions_misc.rs +++ b/src/builtins/azure_policy/template_functions_misc.rs @@ -10,7 +10,6 @@ use crate::builtins; use crate::lexer::Span; use crate::value::Object; use crate::value::Value; -use crate::Rc; use alloc::string::{String, ToString as _}; use alloc::vec::Vec; @@ -88,8 +87,11 @@ fn fn_items(_span: &Span, _params: &[Ref], args: &[Value], _strict: bool) let mut entry = Object::new(); entry.insert(Value::from("key"), k.clone()); entry.insert(Value::from("value"), v.clone()); - result.push(Value::Object(Rc::new(entry))); + result.push(entry.into_value()); + // Throttled check bounds peak allocation while building large results. + crate::utils::limits::check_memory_limit_if_needed().map_err(anyhow::Error::new)?; } + crate::utils::limits::enforce_memory_limit().map_err(anyhow::Error::new)?; Ok(Value::from_array(result)) } diff --git a/src/builtins/objects.rs b/src/builtins/objects.rs index 9d8a844c3..2e339acdb 100644 --- a/src/builtins/objects.rs +++ b/src/builtins/objects.rs @@ -399,7 +399,8 @@ fn object_union(span: &Span, params: &[Ref], args: &[Value], _strict: bool let _ = ensure_object(name, ¶ms[0], args[0].clone())?; let _ = ensure_object(name, ¶ms[1], args[1].clone())?; - union(&args[0], &args[1]) + let result = union(&args[0], &args[1])?; + Ok(result) } fn object_union_n( diff --git a/src/engine.rs b/src/engine.rs index b291ef804..97aa6ef97 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -398,6 +398,13 @@ impl Engine { /// # } /// ``` pub fn set_input(&mut self, input: Value) { + // Store the document as-is -- this is a pure setter. Inputs produced by + // `set_input_json`/`from_json_str` already carry compact frozen storage; a + // programmatically-built `Value` is kept in whatever representation the caller + // supplied. Not freezing here avoids a full recursive traversal and the + // unnecessary materialization (BTree -> boxed slice) of a value we were + // just handed, and keeps the API free of any infallible allocation under + // `allocator-memory-limits`. self.interpreter.set_input(input); } @@ -484,13 +491,15 @@ impl Engine { // allocating, so validate then deep-merge in place (zero-copy fast path). self.interpreter.get_init_data().check_mergeable(&data)?; self.prepared = false; - self.interpreter.get_init_data_mut().deep_merge(data) + self.interpreter.get_init_data_mut().deep_merge(data)?; + Ok(()) } #[cfg(feature = "allocator-memory-limits")] { // A limit failure can strike mid-merge and can't be predicted, so merge into a - // candidate and commit only on success. `Value` is copy-on-write, so only touched - // subtrees are cloned. + // candidate and commit only on success; `deep_merge` limit-checks each insertion, + // so the committed document is already bounded. `Value` is copy-on-write, so only + // touched subtrees are cloned. let mut candidate = self.interpreter.get_init_data().clone(); candidate.deep_merge(data)?; *self.interpreter.get_init_data_mut() = candidate; diff --git a/src/rvm/program/serialization/value.rs b/src/rvm/program/serialization/value.rs index 02868a0ce..8a650f23d 100644 --- a/src/rvm/program/serialization/value.rs +++ b/src/rvm/program/serialization/value.rs @@ -265,8 +265,15 @@ impl<'de> Visitor<'de> for BinaryValueVisitor { let mut map = Object::new(); for (key, value) in entries { map.insert(key.into_value(), value.into_value()); + crate::utils::limits::check_memory_limit_if_needed() + .map_err(|err| de::Error::custom(format!("{err}")))?; } - Ok(BinaryValue(Value::Object(crate::Rc::new(map)))) + let object = map.into_value(); + // Mirror the JSON object path: re-check after `into_value` compacts + // storage so binary program loading honors allocator memory limits. + crate::utils::limits::check_memory_limit_if_needed() + .map_err(|err| de::Error::custom(format!("{err}")))?; + Ok(BinaryValue(object)) } (BinaryVariant::Undefined, variant) => { variant.unit_variant()?; diff --git a/src/rvm/vm/comprehension.rs b/src/rvm/vm/comprehension.rs index 3ccff1997..b5c4c19b9 100644 --- a/src/rvm/vm/comprehension.rs +++ b/src/rvm/vm/comprehension.rs @@ -4,7 +4,6 @@ use crate::rvm::instructions::{ComprehensionBeginParams, ComprehensionMode}; use crate::value::Object; use crate::value::Value; -use crate::Rc; use alloc::format; use alloc::sync::Arc; use alloc::vec::Vec; @@ -34,7 +33,7 @@ impl RegoVM { let initial_result = match params.mode { ComprehensionMode::Set => Value::new_set(), ComprehensionMode::Array => Value::new_array(), - ComprehensionMode::Object => Value::Object(Rc::new(Object::new())), + ComprehensionMode::Object => Object::new().into_value(), }; self.set_register(params.result_reg, initial_result.clone())?; @@ -118,7 +117,7 @@ impl RegoVM { let initial_result = match params.mode { ComprehensionMode::Set => Value::new_set(), ComprehensionMode::Array => Value::new_array(), - ComprehensionMode::Object => Value::Object(Rc::new(Object::new())), + ComprehensionMode::Object => Object::new().into_value(), }; self.set_register(params.result_reg, initial_result.clone())?; @@ -519,15 +518,15 @@ impl RegoVM { // `ComprehensionEnd` is reached from a loaded program; an empty stack // here means malformed user-supplied bytecode, which must still surface // as a typed error rather than a panic — including in debug builds. - self.comprehension_stack.pop().map_or_else( - || { - Err(VmError::InvalidIteration { - value: Value::String(Arc::from("No active comprehension context")), - pc: self.pc, - }) - }, - |_context| Ok(()), - ) + // The accumulated result already resides in its result register and needs + // no post-processing, so popping the context to unwind the stack suffices. + self.comprehension_stack + .pop() + .ok_or_else(|| VmError::InvalidIteration { + value: Value::String(Arc::from("No active comprehension context")), + pc: self.pc, + })?; + Ok(()) } fn execute_comprehension_end_suspendable(&mut self) -> Result<()> { @@ -558,6 +557,8 @@ impl RegoVM { return_pc: _, context, } => { + // The accumulated result already resides in `result_reg`; no + // post-processing is required before resuming. let raw_target = context.resume_pc; let resume_pc = if raw_target <= self.pc { self.pc.saturating_add(1) diff --git a/src/value/mod.rs b/src/value/mod.rs index 78d16fbcf..80da18d3b 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -245,7 +245,11 @@ impl<'de> Visitor<'de> for ValueVisitor { // Enforce allocator limit while expanding a deserialized object. enforce_limit_for::()?; } - Ok(Value::from(map)) + let value = Value::from(map); + // The freeze into compact object storage allocates after the final map insert. + // Re-check fallible deserialization paths so allocator-limit builds observe it. + enforce_limit_for::()?; + Ok(value) } else { Ok(Value::new_object()) } @@ -808,7 +812,7 @@ impl From> for Value { /// # Ok(()) /// # } fn from(s: BTreeMap) -> Self { - Value::Object(Rc::new(Object::from(s))) + Object::from(s).into_value() } } diff --git a/src/value/object/cursor.rs b/src/value/object/cursor.rs new file mode 100644 index 000000000..e79d0cff1 --- /dev/null +++ b/src/value/object/cursor.rs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! Resumable, self-owned cursor over an [`Object`]'s entries. + +use core::ops::Bound; + +use super::{Object, Repr}; +use crate::value::Value; + +impl Object { + /// Create a resumable cursor over entries in implementation-defined + /// order. Stable for the lifetime of `&self`. O(1). + #[inline] + pub const fn cursor(&self) -> ObjectCursor { + ObjectCursor { + inner: ObjectCursorInner::Start, + } + } + + /// Advance `cursor` and yield the next entry. + pub fn next<'a>(&'a self, cursor: &mut ObjectCursor) -> Option<(&'a Value, &'a Value)> { + match (&self.repr, &mut cursor.inner) { + (Repr::Empty, _) => None, + (Repr::Frozen(v), ObjectCursorInner::Start) => { + if let Some((k, val)) = v.first() { + cursor.inner = ObjectCursorInner::Key(k.clone()); + Some((k, val)) + } else { + None + } + } + (Repr::Frozen(v), ObjectCursorInner::Key(prev)) => { + let i = match v.binary_search_by(|(k, _)| k.cmp(prev)) { + Ok(i) => i.saturating_add(1), + Err(i) => i, + }; + if let Some((k, val)) = v.get(i) { + cursor.inner = ObjectCursorInner::Key(k.clone()); + Some((k, val)) + } else { + None + } + } + (Repr::BTree(m), ObjectCursorInner::Start) => { + let (k, val) = m.iter().next()?; + cursor.inner = ObjectCursorInner::Key(k.clone()); + Some((k, val)) + } + (Repr::BTree(m), ObjectCursorInner::Key(prev)) => { + let (k, val) = m + .range((Bound::Excluded(prev.clone()), Bound::Unbounded)) + .next()?; + cursor.inner = ObjectCursorInner::Key(k.clone()); + Some((k, val)) + } + } + } +} + +/// Opaque resumable cursor over an [`Object`]'s entries in +/// implementation-defined order. +/// +/// Self-owned: holds no borrow on the `Object`, so it can be stored as a +/// field of a long-lived state struct (e.g. an RVM iteration frame). +#[derive(Debug, Clone)] +pub struct ObjectCursor { + inner: ObjectCursorInner, +} + +#[derive(Debug, Clone)] +enum ObjectCursorInner { + Start, + Key(Value), +} diff --git a/src/value/object/freeze.rs b/src/value/object/freeze.rs new file mode 100644 index 000000000..5dbb19b76 --- /dev/null +++ b/src/value/object/freeze.rs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! Freeze/thaw transitions between mutable `BTree` storage and compact +//! read-mostly `Frozen` boxed-slice storage. + +use alloc::boxed::Box; +use alloc::vec::Vec; + +use super::{Object, Repr}; +use crate::value::Value; + +impl Object { + /// Convert to the immutable boxed-slice representation. + pub(crate) fn freeze(mut self) -> Self { + self.freeze_in_place(); + self + } + + /// Wrap into a `Value::Object`. + #[inline] + pub fn into_value(self) -> Value { + Value::Object(crate::Rc::new(self.freeze())) + } + + #[cfg(test)] + #[doc(hidden)] + pub(crate) const fn storage_variant_for_memory_diagnostics(&self) -> &'static str { + match &self.repr { + Repr::Empty => "Empty", + Repr::Frozen(_) => "Frozen", + Repr::BTree(_) => "BTree", + } + } + + fn freeze_in_place(&mut self) { + match core::mem::take(&mut self.repr) { + Repr::Empty => { + self.repr = Repr::Frozen(Box::new([])); + } + Repr::Frozen(v) => { + debug_assert_sorted_dedup(&v); + self.repr = Repr::Frozen(v); + } + Repr::BTree(m) => { + let boxed = m.into_iter().collect::>().into_boxed_slice(); + // Release-critical invariant: BTreeMap iteration is sorted and deduplicated + // before Frozen binary-search storage is constructed. + debug_assert_sorted_dedup(&boxed); + self.repr = Repr::Frozen(boxed); + } + } + } + + pub(super) fn thawed_repr(v: Box<[(Value, Value)]>) -> Repr { + debug_assert_sorted_dedup(&v); + if v.is_empty() { + Repr::Empty + } else { + Repr::BTree(Vec::from(v).into_iter().collect()) + } + } + + pub(super) fn thaw(&mut self) { + let repr = core::mem::take(&mut self.repr); + self.repr = match repr { + Repr::Frozen(v) => Self::thawed_repr(v), + other => other, + }; + } +} + +#[cfg(debug_assertions)] +fn debug_assert_sorted_dedup(v: &[(Value, Value)]) { + // This debug-only check documents a release-critical invariant: Frozen storage is + // always sorted and deduplicated by construction, and release binary searches depend on it. + for pair in v.windows(2) { + debug_assert!( + pair[0].0.cmp(&pair[1].0).is_lt(), + "Object Frozen entries must be strictly sorted and deduplicated; \ + TODO(Number): revisit NaN ordering/equality semantics in src/number.rs:290-316" + ); + } +} + +#[cfg(not(debug_assertions))] +#[inline] +fn debug_assert_sorted_dedup(_: &[(Value, Value)]) {} diff --git a/src/value/object/iter.rs b/src/value/object/iter.rs index 609f9bea9..8e903185d 100644 --- a/src/value/object/iter.rs +++ b/src/value/object/iter.rs @@ -2,45 +2,62 @@ // Licensed under the MIT License. //! Opaque iterator types for [`Object`]. -//! -//! These newtypes wrap the storage backend's iterators so the backend can be -//! swapped without changing any iterator type signatures observed by callers. use alloc::collections::btree_map; +use alloc::vec::Vec; use core::iter::FusedIterator; -use super::Object; +use super::{Object, Repr}; use crate::value::Value; /// Owned iterator over `(Value, Value)` entries. #[derive(Debug)] pub struct IntoIter { - pub(super) inner: btree_map::IntoIter, + pub(super) inner: IntoIterInner, +} + +#[derive(Debug)] +pub(super) enum IntoIterInner { + Empty, + Frozen(alloc::vec::IntoIter<(Value, Value)>), + BTree(btree_map::IntoIter), } impl Iterator for IntoIter { type Item = (Value, Value); - #[inline] fn next(&mut self) -> Option { - self.inner.next() + match &mut self.inner { + IntoIterInner::Empty => None, + IntoIterInner::Frozen(it) => it.next(), + IntoIterInner::BTree(it) => it.next(), + } } - #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + match &self.inner { + IntoIterInner::Empty => (0, Some(0)), + IntoIterInner::Frozen(it) => it.size_hint(), + IntoIterInner::BTree(it) => it.size_hint(), + } } } -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + match &self.inner { + IntoIterInner::Empty => 0, + IntoIterInner::Frozen(it) => it.len(), + IntoIterInner::BTree(it) => it.len(), + } } } -impl ExactSizeIterator for IntoIter { - #[inline] - fn len(&self) -> usize { - self.inner.len() +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + match &mut self.inner { + IntoIterInner::Empty => None, + IntoIterInner::Frozen(it) => it.next_back(), + IntoIterInner::BTree(it) => it.next_back(), + } } } @@ -49,32 +66,51 @@ impl FusedIterator for IntoIter {} /// Borrowed iterator over `(&Value, &Value)` entries. #[derive(Debug, Clone)] pub struct Iter<'a> { - pub(super) inner: btree_map::Iter<'a, Value, Value>, + pub(super) inner: IterInner<'a>, +} + +#[derive(Debug, Clone)] +pub(super) enum IterInner<'a> { + Empty, + Frozen(core::slice::Iter<'a, (Value, Value)>), + BTree(btree_map::Iter<'a, Value, Value>), } impl<'a> Iterator for Iter<'a> { type Item = (&'a Value, &'a Value); - #[inline] fn next(&mut self) -> Option { - self.inner.next() + match &mut self.inner { + IterInner::Empty => None, + IterInner::Frozen(it) => it.next().map(|(k, v)| (k, v)), + IterInner::BTree(it) => it.next(), + } } - #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + match &self.inner { + IterInner::Empty => (0, Some(0)), + IterInner::Frozen(it) => it.size_hint(), + IterInner::BTree(it) => it.size_hint(), + } } } -impl<'a> DoubleEndedIterator for Iter<'a> { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() +impl<'a> ExactSizeIterator for Iter<'a> { + fn len(&self) -> usize { + match &self.inner { + IterInner::Empty => 0, + IterInner::Frozen(it) => it.len(), + IterInner::BTree(it) => it.len(), + } } } -impl<'a> ExactSizeIterator for Iter<'a> { - #[inline] - fn len(&self) -> usize { - self.inner.len() +impl<'a> DoubleEndedIterator for Iter<'a> { + fn next_back(&mut self) -> Option { + match &mut self.inner { + IterInner::Empty => None, + IterInner::Frozen(it) => it.next_back().map(|(k, v)| (k, v)), + IterInner::BTree(it) => it.next_back(), + } } } @@ -83,32 +119,46 @@ impl<'a> FusedIterator for Iter<'a> {} /// Borrowed iterator over `(&Value, &mut Value)` entries. #[derive(Debug)] pub struct IterMut<'a> { - pub(super) inner: btree_map::IterMut<'a, Value, Value>, + pub(super) inner: IterMutInner<'a>, +} + +#[derive(Debug)] +pub(super) enum IterMutInner<'a> { + Empty, + BTree(btree_map::IterMut<'a, Value, Value>), } impl<'a> Iterator for IterMut<'a> { type Item = (&'a Value, &'a mut Value); - #[inline] fn next(&mut self) -> Option { - self.inner.next() + match &mut self.inner { + IterMutInner::Empty => None, + IterMutInner::BTree(it) => it.next(), + } } - #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + match &self.inner { + IterMutInner::Empty => (0, Some(0)), + IterMutInner::BTree(it) => it.size_hint(), + } } } -impl<'a> DoubleEndedIterator for IterMut<'a> { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() +impl<'a> ExactSizeIterator for IterMut<'a> { + fn len(&self) -> usize { + match &self.inner { + IterMutInner::Empty => 0, + IterMutInner::BTree(it) => it.len(), + } } } -impl<'a> ExactSizeIterator for IterMut<'a> { - #[inline] - fn len(&self) -> usize { - self.inner.len() +impl<'a> DoubleEndedIterator for IterMut<'a> { + fn next_back(&mut self) -> Option { + match &mut self.inner { + IterMutInner::Empty => None, + IterMutInner::BTree(it) => it.next_back(), + } } } @@ -117,10 +167,13 @@ impl<'a> FusedIterator for IterMut<'a> {} impl IntoIterator for Object { type Item = (Value, Value); type IntoIter = IntoIter; - #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { - inner: self.inner.into_iter(), + inner: match self.repr { + Repr::Empty => IntoIterInner::Empty, + Repr::Frozen(v) => IntoIterInner::Frozen(Vec::from(v).into_iter()), + Repr::BTree(m) => IntoIterInner::BTree(m.into_iter()), + }, } } } @@ -128,21 +181,15 @@ impl IntoIterator for Object { impl<'a> IntoIterator for &'a Object { type Item = (&'a Value, &'a Value); type IntoIter = Iter<'a>; - #[inline] fn into_iter(self) -> Self::IntoIter { - Iter { - inner: self.inner.iter(), - } + self.iter_sorted() } } impl<'a> IntoIterator for &'a mut Object { type Item = (&'a Value, &'a mut Value); type IntoIter = IterMut<'a>; - #[inline] fn into_iter(self) -> Self::IntoIter { - IterMut { - inner: self.inner.iter_mut(), - } + self.iter_mut() } } diff --git a/src/value/object/mod.rs b/src/value/object/mod.rs index 04078eb2c..f82f15a50 100644 --- a/src/value/object/mod.rs +++ b/src/value/object/mod.rs @@ -2,24 +2,41 @@ // Licensed under the MIT License. //! See [`Object`]. - +//! +//! `Object` uses private storage variants tuned for memory and mutation cost. +//! `Frozen` means compact boxed-slice storage, not semantic immutability: +//! mutable APIs such as [`Object::insert`], [`Object::remove`], and +//! [`Object::get_mut`] may update values in place or thaw storage +//! transparently. `Empty`, `Frozen`, and `BTree` are optimization +//! details and callers must not depend on which representation is selected. +//! +//! The implementation is split across sibling modules that share the private +//! `repr` field: [`mutate`] (insert/remove/retain/get_or_insert_with), +//! [`freeze`] (freeze/thaw transitions), and [`cursor`] (resumable iteration). + +mod cursor; +mod freeze; mod iter; +mod mutate; mod serde; +use alloc::boxed::Box; use alloc::collections::BTreeMap; use core::cmp::Ordering; use core::fmt; -use core::ops::Bound; use crate::value::Value; +#[cfg(feature = "rvm")] +pub use cursor::ObjectCursor; pub use iter::{IntoIter, Iter, IterMut}; /// Opaque, ordered key-value map keyed by [`Value`]. /// -/// The current backing storage is `BTreeMap`. The inner field -/// is private so the representation can change (two-tier inline+hash, lazy, -/// schema-shared) without touching call sites. +/// Backed by a three-variant representation: empty objects use zero-allocation +/// storage, mutable objects use `BTreeMap`, and read-mostly objects freeze to an +/// exact-size boxed slice. The representation is private so it can change +/// without touching call sites. /// /// # Iteration /// @@ -28,54 +45,89 @@ pub use iter::{IntoIter, Iter, IterMut}; /// - [`Object::cursor`] / [`Object::next`] — implementation-defined order, /// resumable; cheapest per-step cost. Used by interpreter/RVM when iteration /// must yield mid-flight. -#[derive(Default, Clone, Eq, PartialEq)] +#[derive(Default, Clone)] pub struct Object { - inner: BTreeMap, + pub(super) repr: Repr, +} + +#[derive(Clone)] +pub(super) enum Repr { + Empty, + /// Compact sorted, deduplicated entries with no spare capacity. + /// + /// Release-critical invariant: Frozen keys are strictly sorted and deduplicated. + /// `get`/`insert`/cursor resume use binary search in all builds, so every construction + /// path must preserve this before entering `Repr::Frozen`. + Frozen(Box<[(Value, Value)]>), + BTree(BTreeMap), +} + +impl Default for Repr { + #[inline] + fn default() -> Self { + Repr::Empty + } } impl Object { /// Create an empty `Object`. #[inline] pub const fn new() -> Self { - Self { - inner: BTreeMap::new(), - } + Self { repr: Repr::Empty } } #[inline] pub fn len(&self) -> usize { - self.inner.len() + match &self.repr { + Repr::Empty => 0, + Repr::Frozen(v) => v.len(), + Repr::BTree(m) => m.len(), + } } #[inline] pub fn is_empty(&self) -> bool { - self.inner.is_empty() + self.len() == 0 } - #[inline] pub fn get(&self, key: &Value) -> Option<&Value> { - self.inner.get(key) + match &self.repr { + Repr::Empty => None, + Repr::Frozen(v) => match v.binary_search_by(|(k, _)| k.cmp(key)) { + Ok(i) => Some(&v[i].1), + Err(_) => None, + }, + Repr::BTree(m) => m.get(key), + } } #[inline] pub fn contains_key(&self, key: &Value) -> bool { - self.inner.contains_key(key) + self.get(key).is_some() } - #[inline] pub fn get_mut(&mut self, key: &Value) -> Option<&mut Value> { - self.inner.get_mut(key) + // Returning `&mut Value` for an existing key is a value-only mutation: + // it never reorders or removes keys, so `Frozen` storage is preserved + // in place rather than thawed (mirrors `insert`/`get_or_insert_with`). + match &mut self.repr { + Repr::Empty => None, + Repr::Frozen(v) => match v.binary_search_by(|(k, _)| k.cmp(key)) { + Ok(i) => Some(&mut v[i].1), + Err(_) => None, + }, + Repr::BTree(m) => m.get_mut(key), + } } /// Iteration in implementation-defined order. Non-resumable. /// - /// For the current BTree-backed storage this happens to be sorted, but - /// callers MUST NOT depend on that. Use [`Object::iter_sorted`] when + /// For both current backends this happens to be sorted by `Value::Ord`, + /// but callers MUST NOT depend on that. Use [`Object::iter_sorted`] when /// deterministic order is required, or [`Object::cursor`] when iteration /// must yield and resume. - #[inline] pub fn iter(&self) -> impl Iterator + '_ { - self.inner.iter() + self.iter_sorted() } /// Iteration in sorted key order (by `Value::Ord`). Non-resumable. @@ -84,136 +136,62 @@ impl Object { /// `object.keys` builtin, etc. #[inline] pub fn iter_sorted(&self) -> Iter<'_> { - // BTree backend iterates sorted natively. Iter { - inner: self.inner.iter(), + inner: match &self.repr { + Repr::Empty => iter::IterInner::Empty, + Repr::Frozen(v) => iter::IterInner::Frozen(v.iter()), + Repr::BTree(m) => iter::IterInner::BTree(m.iter()), + }, } } - #[inline] pub fn keys(&self) -> impl Iterator + '_ { - self.inner.keys() + self.iter_sorted().map(|(k, _)| k) } - /// Keys in sorted order (by `Value::Ord`). Symmetric with - /// [`Object::iter_sorted`]. - #[inline] pub fn keys_sorted(&self) -> impl Iterator + '_ { self.iter_sorted().map(|(k, _)| k) } - #[inline] pub fn values(&self) -> impl Iterator + '_ { - self.inner.values() + self.iter_sorted().map(|(_, v)| v) } #[inline] pub fn iter_mut(&mut self) -> IterMut<'_> { + // Frozen storage is read-only, so thaw it in place before handing out + // mutable element references. After this, repr is never Frozen. + self.thaw(); IterMut { - inner: self.inner.iter_mut(), + inner: match &mut self.repr { + // `thaw` above guarantees repr is not Frozen here; the Frozen + // arm is dead, but yielding an empty iterator keeps the match + // total without a panic. + Repr::Empty | Repr::Frozen(_) => iter::IterMutInner::Empty, + Repr::BTree(m) => iter::IterMutInner::BTree(m.iter_mut()), + }, } } +} - /// Insert a key-value pair. Returns the previous value if any. - #[inline] - pub fn insert(&mut self, key: Value, value: Value) -> Option { - self.inner.insert(key, value) - } - - #[inline] - pub fn remove(&mut self, key: &Value) -> Option { - self.inner.remove(key) - } - - #[inline] - pub fn retain(&mut self, f: F) - where - F: FnMut(&Value, &mut Value) -> bool, - { - self.inner.retain(f); - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear(); - } - - #[inline] - pub fn append(&mut self, other: &mut Object) { - self.inner.append(&mut other.inner); - } - - /// Gets a mutable reference to the value associated with `key`, inserting - /// the result of `default()` if absent. Single O(log n) probe. - pub fn get_or_insert_with Value>( - &mut self, - key: Value, - default: F, - ) -> &mut Value { - self.inner.entry(key).or_insert_with(default) - } - - /// Wrap into a `Value::Object`. - #[inline] - pub fn into_value(self) -> Value { - Value::Object(crate::Rc::new(self)) - } - - /// Create a resumable cursor over entries in implementation-defined - /// order. Stable for the lifetime of `&self`. O(1). - /// - /// The cursor is fully self-owned (it stores a clone of the last-seen - /// key, not a reference) so it can be stored as a field of a - /// long-lived state struct — e.g. an RVM iteration frame that persists - /// across instruction dispatches. As a consequence, mutating the - /// `Object` between `next()` calls is not rejected by the borrow - /// checker; the resulting iteration order in that case is unspecified. - #[inline] - pub const fn cursor(&self) -> ObjectCursor { - ObjectCursor { - inner: ObjectCursorInner::BTree(None), +// ---- Hand-written PartialEq/Eq/Ord ------------------------------------- +// +// Defined in terms of `iter_sorted()` so equality and ordering are +// consistent with the canonical (sorted) view of the entries and are +// therefore independent of the storage variant. A derived PartialEq on +// `Repr` would incorrectly distinguish `Frozen` from `BTree` even when they +// hold identical entries. + +impl PartialEq for Object { + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; } + self.iter_sorted().eq(other.iter_sorted()) } - - /// Advance `cursor` and yield the next entry. O(log n) for the BTree - /// backend (range probe); future hash/inline variants may be O(1). - pub fn next<'a>(&'a self, cursor: &mut ObjectCursor) -> Option<(&'a Value, &'a Value)> { - let ObjectCursorInner::BTree(ref mut last) = cursor.inner; - let next = last.as_ref().map_or_else( - || self.inner.iter().next(), - |prev| { - self.inner - .range((Bound::Excluded(prev.clone()), Bound::Unbounded)) - .next() - }, - ); - let (k, v) = next?; - *last = Some(k.clone()); - Some((k, v)) - } -} - -/// Opaque resumable cursor over an [`Object`]'s entries in -/// implementation-defined order. -/// -/// Self-owned: holds no borrow on the `Object`, so it can be stored as a -/// field of a long-lived state struct (e.g. an RVM iteration frame). -#[derive(Debug, Clone)] -pub struct ObjectCursor { - inner: ObjectCursorInner, -} - -#[derive(Debug, Clone)] -enum ObjectCursorInner { - /// BTree backend cursor: tracks last-seen key. `None` means "before start". - BTree(Option), } -// ---- Hand-written Ord/PartialOrd ---------------------------------------- -// -// Implemented in terms of `iter_sorted()` so ordering is consistent with the -// canonical (sorted) view of the entries and is therefore independent of -// the storage variant. +impl Eq for Object {} impl Ord for Object { fn cmp(&self, other: &Self) -> Ordering { @@ -230,30 +208,37 @@ impl PartialOrd for Object { impl fmt::Debug for Object { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Use sorted iteration so Debug output is stable across storage - // variants. f.debug_map().entries(self.iter_sorted()).finish() } } impl Extend<(Value, Value)> for Object { fn extend>(&mut self, iter: I) { - self.inner.extend(iter); + for (k, v) in iter { + self.insert(k, v); + } } } impl FromIterator<(Value, Value)> for Object { fn from_iter>(iter: I) -> Self { - Self { - inner: BTreeMap::from_iter(iter), + let mut o = Object::new(); + for (k, v) in iter { + o.insert(k, v); } + o } } impl From> for Object { - #[inline] fn from(map: BTreeMap) -> Self { - Self { inner: map } + if map.is_empty() { + Self { repr: Repr::Empty } + } else { + Self { + repr: Repr::BTree(map), + } + } } } diff --git a/src/value/object/mutate.rs b/src/value/object/mutate.rs new file mode 100644 index 000000000..0b5d578ed --- /dev/null +++ b/src/value/object/mutate.rs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! In-place mutation of an [`Object`]: insert/remove/retain/clear/append and +//! the entry-style `get_or_insert_with`. These operations may thaw `Frozen` +//! storage to `BTree` transparently. + +use alloc::collections::BTreeMap; +use alloc::vec::Vec; + +use super::{Object, Repr}; +use crate::value::Value; + +impl Object { + /// Insert a key-value pair. Returns the previous value if any. + pub fn insert(&mut self, key: Value, value: Value) -> Option { + match core::mem::take(&mut self.repr) { + Repr::Empty => { + let mut m = BTreeMap::new(); + m.insert(key, value); + self.repr = Repr::BTree(m); + None + } + Repr::Frozen(mut v) => { + // Value-only mutation preserves sorted keys and keeps compact Frozen storage. + // Structural mutation (new key or remove) thaws below. + if let Ok(i) = v.binary_search_by(|(k, _)| k.cmp(&key)) { + let prev = core::mem::replace(&mut v[i].1, value); + self.repr = Repr::Frozen(v); + return Some(prev); + } + self.repr = Self::thawed_repr(v); + self.insert(key, value) + } + Repr::BTree(mut m) => { + let prev = m.insert(key, value); + self.repr = Repr::BTree(m); + prev + } + } + } + + pub fn remove(&mut self, key: &Value) -> Option { + match core::mem::take(&mut self.repr) { + Repr::Empty => { + self.repr = Repr::Empty; + None + } + Repr::Frozen(v) => { + // Absent key: keep compact Frozen storage untouched. + // Present key: thaw to a mutable representation, then remove. + if v.binary_search_by(|(k, _)| k.cmp(key)).is_err() { + self.repr = Repr::Frozen(v); + return None; + } + self.repr = Self::thawed_repr(v); + self.remove(key) + } + Repr::BTree(mut m) => { + let prev = m.remove(key); + self.repr = Repr::BTree(m); + prev + } + } + } + + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&Value, &mut Value) -> bool, + { + match core::mem::take(&mut self.repr) { + Repr::Empty => { + self.repr = Repr::Empty; + } + Repr::Frozen(v) => { + self.repr = Self::thawed_repr(v); + self.retain(f); + } + Repr::BTree(mut m) => { + m.retain(|k, v| f(k, v)); + self.repr = Repr::BTree(m); + } + } + } + + #[inline] + pub fn clear(&mut self) { + self.repr = Repr::Empty; + } + + pub fn append(&mut self, other: &mut Object) { + let drained: Vec<(Value, Value)> = match core::mem::take(&mut other.repr) { + Repr::Empty => Vec::new(), + Repr::Frozen(v) => Vec::from(v), + Repr::BTree(m) => m.into_iter().collect(), + }; + other.repr = Repr::Empty; + for (k, v) in drained { + self.insert(k, v); + } + } + + /// Gets a mutable reference to the value associated with `key`, inserting + /// the result of `default()` if absent. + pub fn get_or_insert_with Value>( + &mut self, + key: Value, + default: F, + ) -> &mut Value { + self.repr.get_or_insert_with(key, default) + } +} + +impl Repr { + /// Entry-style lookup that inserts `default()` when the key is absent. + /// + /// An existing key in `Frozen` storage returns its value slot in place, keeping + /// the compact representation. Otherwise storage is normalized to `BTree` before + /// inserting. Recursion is bounded to at most 3 frames: each call advances the repr + /// state toward the terminal `BTree` arm (`Frozen` -> `Empty`/`BTree`, `Empty` -> + /// `BTree`), never on data depth, so there is no stack-overflow risk on any input. + fn get_or_insert_with Value>(&mut self, key: Value, default: F) -> &mut Value { + // Locate an existing key in Frozen storage up front (scoped borrow, yields an + // index by value). Splitting this from the in-place return below sidesteps NLL + // problem case 3, where a conditionally-returned borrow would block the thaw. + let frozen_index = match self { + Repr::Frozen(v) => v.binary_search_by(|(k, _)| k.cmp(&key)).ok(), + _ => None, + }; + + // Absent key (or non-Frozen storage): normalize to `BTree`, thawing Frozen on + // the way, then insert. This branch always returns, so no borrow reaches below. + if frozen_index.is_none() { + match self { + Repr::Empty => *self = Repr::BTree(BTreeMap::new()), + Repr::BTree(m) => return m.entry(key).or_insert_with(default), + Repr::Frozen(_) => { + let repr = core::mem::take(self); + *self = match repr { + Repr::Frozen(v) => Object::thawed_repr(v), + other => other, + }; + } + } + return self.get_or_insert_with(key, default); + } + + // Existing key in Frozen storage: return its value slot in place, keeping the + // compact representation (keys are unchanged, so the sort order still holds). + match (self, frozen_index) { + (Repr::Frozen(v), Some(i)) => &mut v[i].1, + (this, _) => this.get_or_insert_with(key, default), + } + } +} diff --git a/src/value/object/serde.rs b/src/value/object/serde.rs index dc0be2fae..96eee178b 100644 --- a/src/value/object/serde.rs +++ b/src/value/object/serde.rs @@ -48,6 +48,11 @@ impl<'de> Visitor<'de> for ObjectVisitor { crate::utils::limits::check_memory_limit_if_needed() .map_err(|err| A::Error::custom(err.to_string()))?; } + let obj = obj.freeze(); + // `freeze` allocates compact boxed-slice storage after the final insert; keep this + // fallible deserialization path honest under allocator memory limits. + crate::utils::limits::check_memory_limit_if_needed() + .map_err(|err| A::Error::custom(err.to_string()))?; Ok(obj) } } diff --git a/src/value/tests.rs b/src/value/tests.rs index 162d13dd0..eba83b549 100644 --- a/src/value/tests.rs +++ b/src/value/tests.rs @@ -866,3 +866,177 @@ fn check_mergeable_rejects_excessive_depth() { "expected a depth-limit error, got: {err}" ); } + +const CONST_OBJECT_NEW: Object = Object::new(); + +#[test] +fn object_new_is_const_context() { + assert!(CONST_OBJECT_NEW.is_empty()); +} + +#[test] +fn object_mutable_inserts_use_btree_storage() { + let mut obj = Object::new(); + obj.insert(val(1), val(10)); + obj.insert(val(2), val(20)); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + obj.insert(val(3), val(30)); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); +} + +#[test] +fn object_btree_freeze_mutate_insert_and_refreeze_roundtrip() { + let mut obj: Object = make_pairs(3).into_iter().collect(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + obj = obj.freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + obj.insert(val(99), val(100)); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + assert_eq!(obj.get(&val(99)), Some(&val(100))); + obj = obj.freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert_eq!(obj.get(&val(99)), Some(&val(100))); +} + +#[test] +fn object_empty_freeze_get_iter_and_cursor() { + let obj = Object::new().freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert!(obj.get(&val(0)).is_none()); + assert_eq!(obj.iter().count(), 0); + let mut cursor = obj.cursor(); + assert!(obj.next(&mut cursor).is_none()); +} + +#[test] +fn object_from_large_btreemap_into_value_is_frozen() { + let map: BTreeMap = make_pairs(3).into_iter().collect(); + let value = Object::from(map).into_value(); + let object = value.as_object().expect("object"); + assert_eq!(object.storage_variant_for_memory_diagnostics(), "Frozen"); +} + +#[test] +fn object_cross_variant_partial_eq_ignores_storage() { + let empty_frozen = Object::from_iter(core::iter::empty()).freeze(); + assert_eq!(Object::new(), empty_frozen); + + let mutable: Object = make_pairs(2).into_iter().collect(); + assert_eq!(mutable.storage_variant_for_memory_diagnostics(), "BTree"); + let frozen = mutable.clone().freeze(); + + let mut btree: Object = make_pairs(3).into_iter().collect(); + btree.remove(&val(2)); + assert_eq!(btree.storage_variant_for_memory_diagnostics(), "BTree"); + + assert_eq!(mutable, frozen); + assert_eq!(mutable, btree); +} + +#[test] +fn object_cursor_frozen_one_entry_yields_once() { + let obj = Object::from_iter([(val(1), val(2))]).freeze(); + let mut cursor = obj.cursor(); + assert_eq!(obj.next(&mut cursor), Some((&val(1), &val(2)))); + assert!(obj.next(&mut cursor).is_none()); +} + +#[test] +fn object_cursor_resumes_after_frozen_storage_thaws() { + let mut obj = Object::from_iter(make_pairs(4)).freeze(); + let mut cursor = obj.cursor(); + + assert_eq!(obj.next(&mut cursor), Some((&val(0), &val(0)))); + obj.insert(val(5), val(10)); + + // Cursors resume after the last yielded key. Structural mutation may change the storage + // representation, but continuing from the key yields the remaining greater keys. + let remainder: Vec<(Value, Value)> = core::iter::from_fn(|| { + obj.next(&mut cursor) + .map(|(key, value)| (key.clone(), value.clone())) + }) + .collect(); + assert_eq!( + remainder, + Vec::from([ + (val(1), val(2)), + (val(2), val(4)), + (val(3), val(6)), + (val(5), val(10)), + ]) + ); +} + +#[test] +fn object_iter_mut_on_frozen_persists_changes() { + let mut obj = Object::from_iter([(val(1), val(2))]).freeze(); + for (_, value) in obj.iter_mut() { + *value = val(3); + } + assert_eq!(obj.get(&val(1)), Some(&val(3))); +} + +#[test] +fn object_hybrid_insert_existing_on_frozen_stays_frozen() { + let mut obj = Object::from_iter([(val(1), val(2))]).freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert_eq!(obj.insert(val(1), val(9)), Some(val(2))); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert_eq!(obj.get(&val(1)), Some(&val(9))); +} + +#[test] +fn object_get_or_insert_existing_on_frozen_stays_frozen() { + let mut obj = Object::from_iter(make_pairs(3)).freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + + // Existing key: the default must not run and storage must stay compact. + let slot = obj.get_or_insert_with(val(1), || panic!("default must not be called")); + assert_eq!(*slot, val(2)); + *slot = val(42); + + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert_eq!(obj.get(&val(1)), Some(&val(42))); +} + +#[test] +fn object_get_or_insert_absent_on_frozen_thaws_and_inserts() { + let mut obj = Object::from_iter(make_pairs(3)).freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + + let slot = obj.get_or_insert_with(val(99), || val(100)); + assert_eq!(*slot, val(100)); + + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + assert_eq!(obj.get(&val(99)), Some(&val(100))); + // Pre-existing keys survive the thaw unchanged. + assert_eq!(obj.get(&val(1)), Some(&val(2))); +} + +#[test] +fn object_get_or_insert_on_empty_frozen_inserts() { + let mut obj = Object::new().freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + + let slot = obj.get_or_insert_with(val(1), || val(7)); + assert_eq!(*slot, val(7)); + + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + assert_eq!(obj.get(&val(1)), Some(&val(7))); +} + +#[test] +fn object_remove_absent_on_frozen_stays_frozen() { + let mut obj = Object::from_iter(make_pairs(3)).freeze(); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + + // Removing a key that is not present must not disturb the compact storage. + assert_eq!(obj.remove(&val(99)), None); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "Frozen"); + assert_eq!(obj.len(), 3); + + // Removing a present key thaws to the mutable representation. + assert_eq!(obj.remove(&val(1)), Some(val(2))); + assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); + assert_eq!(obj.get(&val(1)), None); +} diff --git a/tests/data/sarif_memory/input.json b/tests/data/sarif_memory/input.json new file mode 100644 index 000000000..bd4de06c0 --- /dev/null +++ b/tests/data/sarif_memory/input.json @@ -0,0 +1,9742 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "results": [ + { + "ruleId": "26036", + "message": { + "text": "Possible postcondition violation due to failure to null terminate string\nBuffer result.wcscpy created during call to wcscpy on line 120\nAnnotation on function ua_wcscpy requires that result.ua_wcscpy is null terminated\n[Annotation SAL_nullTerminated at c:\\somepath\\winnt.h(368)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/stralign.h", + "index": 0 + }, + "region": { + "startLine": 120, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 0, + "fullyQualifiedName": "ua_wcscpy" + } + ], + "properties": { + "funcline": "109" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/stralign.h", + "index": 0 + }, + "region": { + "startLine": 109, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/stralign.h", + "index": 0 + }, + "region": { + "startLine": 120, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/stralign.h", + "index": 0 + }, + "region": { + "startLine": 120, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26018", + "message": { + "text": "Potential read overflow of null terminated buffer using expression '* (_Cpc1 += result.wcsspn)'\nBuffer access is apparently unbounded by the buffer size. \n\nIn particular: offset(_Cpc1)`725 is not constrained by nullpos(_Cpc1)`725\n\nBuffer _Cpc1 is a parameter to this function declared on line 725\nBuffer is of length 2*nullpos(_Cpc1)`725 + 2 bytes [length of zero terminated string]\nAccessing 2 bytes starting at byte offset 2*result.wcsspn`731a\n\nValues of variables:\nPointer _Cpc1 is at offset 2*result.wcsspn`731a bytes from the start of the buffer\nresult.wcsspn = result.wcsspn`731a\n\nwhere\noffset(_Cpc1)`725 == 0\nnullpos(_Cpc1)`725 >= 0\nresult.wcsspn`731a >= 0\n\nOverrun access occurs when\n2*result.wcsspn`731a >= 2*nullpos(_Cpc1)`725 + 1\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 731, + "startColumn": 29 + } + }, + "logicalLocations": [ + { + "index": 1, + "fullyQualifiedName": "_wcsspnp" + } + ], + "properties": { + "funcline": "725" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 725, + "startColumn": 203 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 731, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 731, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 731, + "startColumn": 29 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26018", + "message": { + "text": "Potential overflow of null terminated buffer using expression '_Dst'\nBuffer access is apparently unbounded by the buffer size. \n\nIn particular: offset(_Dst)`770 is not constrained by nullpos(_Dst)`770\n\nBuffer _Dst is a parameter to this function declared on line 770\nBuffer is of length 2*nullpos(_Dst)`770 + 2 bytes [length of zero terminated string]\nAccessing 2*_Count`770 bytes starting at byte offset 0\nAnnotation on function wcsncat requires that {parameter 1} is of length >= {parameter 3} elements (2 bytes/element)\n where {parameter 1} is _Dst; {parameter 3} is _Count\n[Annotation SAL_writableTo(elementCount({parameter 3})) at c:\\somepath\\crt\\string.h(295)]\n\n\nValues of variables:\nPointer _Dst is at offset 0 bytes from the start of the buffer\n_Count = _Count`770\n\nwhere\noffset(_Dst)`770 == 0\n_Count`770 >= 0\nnullpos(_Dst)`770 >= 0\n\nOverrun access occurs when\n2*_Count`770 >= 2*nullpos(_Dst)`770 + 3\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 781, + "startColumn": 19 + } + }, + "logicalLocations": [ + { + "index": 2, + "fullyQualifiedName": "_wcsncat_l" + } + ], + "properties": { + "funcline": "770" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 770, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/tchar.h", + "index": 1 + }, + "region": { + "startLine": 781, + "startColumn": 19 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26036", + "message": { + "text": "Possible postcondition violation due to failure to null terminate string\nThe function has a __success annotation that is satisfied\nBuffer pszDest is a parameter to this function declared on line 1459\nAnnotation on function StringCbCopyExW requires that pszDest is null terminated\n[Annotation SAL_nullTerminated at c:\\somepath\\strsafe.h(1459)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1575, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 3, + "fullyQualifiedName": "StringCbCopyExW" + } + ], + "properties": { + "funcline": "1459" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1459, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1467, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1468, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1468, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1470, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1470, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1472, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1474, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1474, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1475, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1475, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1477, + "startColumn": 34 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1477, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1479, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1481, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1483, + "startColumn": 20 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1485, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1543, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1544, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1556, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1556, + "startColumn": 43 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 1575, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26019", + "message": { + "text": "Potential read overflow using expression '& pszSrc'\nBuffer access is apparently unbounded by the buffer size. \n\nIn particular: any constant is not constrained by cbToCopy`2571\n\nBuffer pszSrc is a parameter to this function declared on line 2571\nBuffer is of length offset(pszSrc)`2571 + cbToCopy`2571 bytes [from annotation SAL_readableTo(byteCount(cbToCopy)) at c:\\somepath\\strsafe.h(2571)]\nAccessing 2 bytes starting at byte offset 0\nAnnotation on function StringExValidateSrcW requires that * {parameter 1} is of length >= 1 elements (2 bytes/element)\n where * {parameter 1} is & pszSrc\n[Annotation SAL_readableTo(elementCount(1)) at c:\\somepath\\strsafe.h(227)]\n\n\nValues of variables:\nPointer pszSrc is at offset 0 bytes from the start of the buffer\n\nwhere\noffset(pszSrc)`2571 == 0\ncbToCopy`2571 == 2*{cbToCopy / 2}`2589 + {(cbToCopy`2571) % 2}`2589\ncbToCopy`2571 >= 1\n{(cbToCopy`2571) % 2}`2589 <= 1\n{(cbToCopy`2571) % 2}`2589 >= 0\n{cbToCopy / 2}`2589 >= 0\n\nOverrun access occurs when\ncbToCopy`2571 == 1\n\nThere are other instances of this error:\nPotential read overflow using expression 'pszSrc' at line 2628\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2591, + "startColumn": 34 + } + }, + "logicalLocations": [ + { + "index": 4, + "fullyQualifiedName": "StringCbCopyNExW" + } + ], + "properties": { + "funcline": "2571" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2571, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2580, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2581, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2581, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2583, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2583, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2585, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2587, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2587, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2588, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2588, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2589, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2589, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 2591, + "startColumn": 34 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26019", + "message": { + "text": "Potential read overflow using expression '& pszSrc'\nBuffer access is apparently unbounded by the buffer size. \n\nIn particular: any constant is not constrained by cbToAppend`4631\n\nBuffer pszSrc is a parameter to this function declared on line 4631\nBuffer is of length offset(pszSrc)`4631 + cbToAppend`4631 bytes [from annotation SAL_readableTo(byteCount(cbToAppend)) at c:\\somepath\\strsafe.h(4631)]\nAccessing 2 bytes starting at byte offset 0\nAnnotation on function StringExValidateSrcW requires that * {parameter 1} is of length >= 1 elements (2 bytes/element)\n where * {parameter 1} is & pszSrc\n[Annotation SAL_readableTo(elementCount(1)) at c:\\somepath\\strsafe.h(227)]\n\n\nValues of variables:\nPointer pszSrc is at offset 0 bytes from the start of the buffer\n\nwhere\noffset(pszSrc)`4631 == 0\ncbToAppend`4631 == 2*{cbToAppend / 2}`4654 + {(cbToAppend`4631) % 2}`4654\ncbToAppend`4631 >= 1\n{(cbToAppend`4631) % 2}`4654 <= 1\n{(cbToAppend`4631) % 2}`4654 >= 0\n{cbToAppend / 2}`4654 >= 0\n\nOverrun access occurs when\ncbToAppend`4631 == 1\n\nThere are other instances of this error:\nPotential read overflow using expression 'pszSrc' at line 4683\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4656, + "startColumn": 34 + } + }, + "logicalLocations": [ + { + "index": 5, + "fullyQualifiedName": "StringCbCatNExW" + } + ], + "properties": { + "funcline": "4631" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4631, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4640, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4641, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4641, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4642, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4644, + "startColumn": 40 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4644, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4650, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4652, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4652, + "startColumn": 45 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4653, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4653, + "startColumn": 39 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4654, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4654, + "startColumn": 41 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 4656, + "startColumn": 34 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26036", + "message": { + "text": "Possible postcondition violation due to failure to null terminate string\nThe function has a __success annotation that is satisfied\nBuffer pszDest is a parameter to this function declared on line 6791\nAnnotation on function StringCbPrintfExW requires that pszDest is null terminated\n[Annotation SAL_nullTerminated at c:\\somepath\\strsafe.h(6791)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6913, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 6, + "fullyQualifiedName": "StringCbPrintfExW" + } + ], + "properties": { + "funcline": "6791" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6791, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6800, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6801, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6801, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6803, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6803, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6805, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6807, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6807, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6808, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6808, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6810, + "startColumn": 34 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6810, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6812, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6814, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6816, + "startColumn": 20 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6818, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6881, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6882, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6894, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6894, + "startColumn": 43 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 6913, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26036", + "message": { + "text": "Possible postcondition violation due to failure to null terminate string\nThe function has a __success annotation that is satisfied\nBuffer pszDest is a parameter to this function declared on line 9374\nAnnotation on function StringCbGetsExW requires that pszDest is null terminated\n[Annotation SAL_nullTerminated at c:\\somepath\\strsafe.h(9374)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9466, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 7, + "fullyQualifiedName": "StringCbGetsExW" + } + ], + "properties": { + "funcline": "9374" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9374, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9381, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9382, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9382, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9384, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9384, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9386, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9388, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9388, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9389, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9389, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9391, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9393, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9395, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9432, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9433, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9445, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9446, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9447, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9466, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26071", + "message": { + "text": "Potential range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringCchLengthA requires that * pcchLength is <= _String_length_(psz)\n[Annotation SAL_relop(\"<=\", _String_length_(psz)) at c:\\somepath\\strsafe.h(9552)]\n\nValues of variables:\n(*pcchLength) = (*pcchLength)`9565a\nPointer psz is at offset 0 bytes from the start of psz\n\nwhere\noffset(psz)`9552 == 0\n(*pcchLength)`9565a >= 0\ncchMax`9552 <= 2147483647\ncchMax`9552 >= (*pcchLength)`9565a + 1\ncchMax`9552 >= 1\ncchMax`9552 >= nullpos(psz)`9565 + 1\nnullpos(psz)`9565 >= 0\n\nRange violation occurs when\nnullpos(psz)`9565 >= (*pcchLength)`9565a + 1\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9573, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 8, + "fullyQualifiedName": "StringCchLengthA" + } + ], + "properties": { + "funcline": "9552" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9552, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9557, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9559, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9559, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9565, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9565, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9568, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9573, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26071", + "message": { + "text": "Potential range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringCchLengthW requires that * pcchLength is <= _String_length_(psz)\n[Annotation SAL_relop(\"<=\", _String_length_(psz)) at c:\\somepath\\strsafe.h(9584)]\n\nValues of variables:\n(*pcchLength) = (*pcchLength)`9597a\nPointer psz is at offset offset(psz)`9584 bytes from the start of psz\n\nwhere\n(*pcchLength)`9597a >= 0\ncchMax`9584 <= 2147483647\ncchMax`9584 >= (*pcchLength)`9597a + 1\ncchMax`9584 >= 1\ncchMax`9584 >= nullpos(psz)`9597 + 1\nnullpos(psz)`9597 >= 0\n\nRange violation occurs when\nnullpos(psz)`9597 >= (*pcchLength)`9597a + 1\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9605, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 9, + "fullyQualifiedName": "StringCchLengthW" + } + ], + "properties": { + "funcline": "9584" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9584, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9589, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9591, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9591, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9597, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9597, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9600, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 9605, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26061", + "message": { + "text": "Range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringValidateDestAndLengthA requires that cchDest > 0 && cchDest <= cchMax\n[Annotation SAL_satisfies(cchDest > 0 && cchDest <= cchMax) at c:\\somepath\\strsafe.h(250)]\n\nValues of variables:\ncchDest = cchDest`10240\ncchMax = cchMax`10240\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10259, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 10, + "fullyQualifiedName": "StringValidateDestAndLengthA" + } + ], + "properties": { + "funcline": "10240" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10240, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10246, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10248, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10248, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10250, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10252, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10252, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10259, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26061", + "message": { + "text": "Range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringValidateDestAndLengthW requires that cchDest > 0 && cchDest <= cchMax\n[Annotation SAL_satisfies(cchDest > 0 && cchDest <= cchMax) at c:\\somepath\\strsafe.h(271)]\n\nValues of variables:\ncchDest = cchDest`10296\ncchMax = cchMax`10296\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10315, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 11, + "fullyQualifiedName": "StringValidateDestAndLengthW" + } + ], + "properties": { + "funcline": "10296" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10296, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10302, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10304, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10304, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10306, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10308, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10308, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 10315, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26071", + "message": { + "text": "Potential range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringExHandleOtherFlagsA requires that * pcchRemaining is <= cbDest / 1\n[Annotation SAL_range(0, cbDest / 1) at c:\\somepath\\strsafe.h(474)]\n\nValues of variables:\n(*pcchRemaining) = (*pcchRemaining)`11069\ncbDest = 1\n\nwhere\ncbDest`11010 == 1\nnullpos(pszDest)`11069 == 0\noffset(pszDest)`11010 == 0\n{(cbDest`11010) % 1}`11010 == 0\n{(cbDest`11010) / 1}`11010 == 1\n(*pcchRemaining)`11069 >= 0\n\nRange violation occurs when\n(*pcchRemaining)`11069 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11068, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 12, + "fullyQualifiedName": "StringExHandleOtherFlagsA" + } + ], + "properties": { + "funcline": "11010" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11010, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11018, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11018, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11020, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11022, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11022, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11035, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11059, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11059, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11068, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26071", + "message": { + "text": "Potential range postcondition violation\nThe function has a __success annotation that is satisfied\nAnnotation on function StringExHandleOtherFlagsW requires that * pcchRemaining is <= cbDest / 2\n[Annotation SAL_range(0, cbDest / 2) at c:\\somepath\\strsafe.h(490)]\n\nValues of variables:\n(*pcchRemaining) = (*pcchRemaining)`11138\ncbDest = cbDest`11079\n\nwhere\n{(cbDest`11079) / 2}`11079 == 0\ncbDest`11079 == 2*{(cbDest`11079) / 2}`11079 + {(cbDest`11079) % 2}`11079\n(*pcchRemaining)`11138 >= 0\ncbDest`11079 <= 2\ncbDest`11079 >= 1\n{(cbDest`11079) % 2}`11079 <= 1\n{(cbDest`11079) % 2}`11079 >= 0\n\nRange violation occurs when\n(*pcchRemaining)`11138 + 1 <= 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11137, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "index": 13, + "fullyQualifiedName": "StringExHandleOtherFlagsW" + } + ], + "properties": { + "funcline": "11079" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11079, + "startColumn": 1 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11087, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11087, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11089, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11091, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11104, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11128, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/strsafe.h", + "index": 2 + }, + "region": { + "startLine": 11137, + "startColumn": 5 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26035", + "message": { + "text": "Possible precondition violation due to failure to null terminate string '_First'\nBuffer _First is a parameter to this function declared on line 326\nAnnotation on function wcslen requires that {parameter 1} is null terminated\n where {parameter 1} is _First [Annotation _Null_terminated(0)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 329, + "startColumn": 19 + } + }, + "logicalLocations": [ + { + "index": 14, + "fullyQualifiedName": "std::char_traits::length" + } + ], + "properties": { + "funcline": "326" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 326, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 329, + "startColumn": 19 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential read overflow using expression '(const void *)_First2'\nBuffer _First2 is a parameter to this function declared on line 340\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First2)`340 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(340)]\nAccessing 2*_Count`340 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 3} is of length >= {parameter 4} bytes\n where {parameter 3} is (const void *)_First2; {parameter 4} is _Count * 2\n[Annotation SAL_readableTo(byteCount({parameter 4})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _First2 is at offset 0 bytes from the start of the buffer\n_Count = _Count`340\n\nwhere\noffset(_First2)`340 == 0\n_Count`340 >= 0\n\nOverrun access occurs when\n_Count`340 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 345, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 15, + "fullyQualifiedName": "std::char_traits::_Copy_s" + } + ], + "properties": { + "funcline": "340" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 340, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 345, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nPotential overflow using expression '(void *)_First1'\nBuffer _First1 is a parameter to this function declared on line 340\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First1)`340 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(340)]\nAccessing 2*_Size_in_words`340 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 1} is of length >= {parameter 2} bytes\n where {parameter 1} is (void *)_First1; {parameter 2} is _Size_in_words * 2\n[Annotation SAL_writableTo(byteCount({parameter 2})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _First1 is at offset 0 bytes from the start of the buffer\n_Size_in_words = _Size_in_words`340\n\nwhere\noffset(_First1)`340 == 0\n_Size_in_words`340 >= 0\n\nOverrun access occurs when\n_Size_in_words`340 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 345, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 15, + "fullyQualifiedName": "std::char_traits::_Copy_s" + } + ], + "properties": { + "funcline": "340" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 340, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 345, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential read overflow using expression '_First2'\nBuffer _First2 is a parameter to this function declared on line 364\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First2)`364 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(364)]\nAccessing 2*_Count`364 bytes starting at byte offset 0\nAnnotation on function wmemmove_s requires that {parameter 3} is of length >= {parameter 4} elements (2 bytes/element)\n where {parameter 3} is _First2; {parameter 4} is _Count\n[Annotation SAL_readableTo(elementCount({parameter 4})) at c:\\somepath\\crt\\wchar.h(1270)]\n\n\nValues of variables:\nPointer _First2 is at offset 0 bytes from the start of the buffer\n_Count = _Count`364\n\nwhere\noffset(_First2)`364 == 0\n_Count`364 >= 0\n\nOverrun access occurs when\n_Count`364 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 369, + "startColumn": 15 + } + }, + "logicalLocations": [ + { + "index": 16, + "fullyQualifiedName": "std::char_traits::_Move_s" + } + ], + "properties": { + "funcline": "364" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 364, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 369, + "startColumn": 15 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nPotential overflow using expression '_First1'\nBuffer _First1 is a parameter to this function declared on line 364\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First1)`364 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(364)]\nAccessing 2*_Size_in_words`364 bytes starting at byte offset 0\nAnnotation on function wmemmove_s requires that {parameter 1} is of length >= {parameter 2} elements (2 bytes/element)\n where {parameter 1} is _First1; {parameter 2} is _Size_in_words\n[Annotation SAL_writableTo(elementCount({parameter 2})) at c:\\somepath\\crt\\wchar.h(1270)]\n\n\nValues of variables:\nPointer _First1 is at offset 0 bytes from the start of the buffer\n_Size_in_words = _Size_in_words`364\n\nwhere\noffset(_First1)`364 == 0\n_Size_in_words`364 >= 0\n\nOverrun access occurs when\n_Size_in_words`364 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 369, + "startColumn": 15 + } + }, + "logicalLocations": [ + { + "index": 16, + "fullyQualifiedName": "std::char_traits::_Move_s" + } + ], + "properties": { + "funcline": "364" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 364, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 369, + "startColumn": 15 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26035", + "message": { + "text": "Possible precondition violation due to failure to null terminate string '_First'\nBuffer _First is a parameter to this function declared on line 441\nAnnotation on function strlen requires that {parameter 1} is null terminated\n where {parameter 1} is _First [Annotation _Null_terminated(0)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 444, + "startColumn": 19 + } + }, + "logicalLocations": [ + { + "index": 17, + "fullyQualifiedName": "std::char_traits::length" + } + ], + "properties": { + "funcline": "441" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 441, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 444, + "startColumn": 19 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential overflow using expression '(void *)_First1'\nBuffer _First1 is a parameter to this function declared on line 455\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First1)`455 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(455)]\nAccessing _Size_in_bytes`455 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 1} is of length >= {parameter 2} bytes\n where {parameter 1} is (void *)_First1; {parameter 2} is _Size_in_bytes\n[Annotation SAL_writableTo(byteCount({parameter 2})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _First1 is at offset 0 bytes from the start of the buffer\n_Size_in_bytes = _Size_in_bytes`455\n\nwhere\noffset(_First1)`455 == 0\n_Size_in_bytes`455 >= 0\n\nOverrun access occurs when\n_Size_in_bytes`455 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 460, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 18, + "fullyQualifiedName": "std::char_traits::_Copy_s" + } + ], + "properties": { + "funcline": "455" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 455, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 460, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential read overflow using expression '(const void *)_First2'\nBuffer _First2 is a parameter to this function declared on line 455\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First2)`455 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(455)]\nAccessing _Count`455 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 3} is of length >= {parameter 4} bytes\n where {parameter 3} is (const void *)_First2; {parameter 4} is _Count\n[Annotation SAL_readableTo(byteCount({parameter 4})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _First2 is at offset 0 bytes from the start of the buffer\n_Count = _Count`455\n\nwhere\noffset(_First2)`455 == 0\n_Count`455 >= 0\n\nOverrun access occurs when\n_Count`455 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 460, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 18, + "fullyQualifiedName": "std::char_traits::_Copy_s" + } + ], + "properties": { + "funcline": "455" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 455, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 460, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential overflow using expression '(void *)_First1'\nBuffer _First1 is a parameter to this function declared on line 479\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First1)`479 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(479)]\nAccessing _Size_in_bytes`479 bytes starting at byte offset 0\nAnnotation on function memmove_s requires that {parameter 1} is of length >= {parameter 2} bytes\n where {parameter 1} is (void *)_First1; {parameter 2} is _Size_in_bytes\n[Annotation SAL_writableTo(byteCount({parameter 2})) at c:\\somepath\\crt\\string.h(102)]\n\n\nValues of variables:\nPointer _First1 is at offset 0 bytes from the start of the buffer\n_Size_in_bytes = _Size_in_bytes`479\n\nwhere\noffset(_First1)`479 == 0\n_Size_in_bytes`479 >= 0\n\nOverrun access occurs when\n_Size_in_bytes`479 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 484, + "startColumn": 14 + } + }, + "logicalLocations": [ + { + "index": 19, + "fullyQualifiedName": "std::char_traits::_Move_s" + } + ], + "properties": { + "funcline": "479" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 479, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 484, + "startColumn": 14 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential read overflow using expression '(const void *)_First2'\nBuffer _First2 is a parameter to this function declared on line 479\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First2)`479 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\iosfwd(479)]\nAccessing _Count`479 bytes starting at byte offset 0\nAnnotation on function memmove_s requires that {parameter 3} is of length >= {parameter 4} bytes\n where {parameter 3} is (const void *)_First2; {parameter 4} is _Count\n[Annotation SAL_readableTo(byteCount({parameter 4})) at c:\\somepath\\crt\\string.h(102)]\n\n\nValues of variables:\nPointer _First2 is at offset 0 bytes from the start of the buffer\n_Count = _Count`479\n\nwhere\noffset(_First2)`479 == 0\n_Count`479 >= 0\n\nOverrun access occurs when\n_Count`479 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 484, + "startColumn": 14 + } + }, + "logicalLocations": [ + { + "index": 19, + "fullyQualifiedName": "std::char_traits::_Move_s" + } + ], + "properties": { + "funcline": "479" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 479, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd", + "index": 3 + }, + "region": { + "startLine": 484, + "startColumn": 14 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26035", + "message": { + "text": "Possible precondition violation due to failure to null terminate string '_Ptr'\nBuffer _Ptr is a parameter to this function declared on line 605\nAnnotation on function strlen requires that {parameter 1} is null terminated\n where {parameter 1} is _Ptr [Annotation _Null_terminated(0)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 615, + "startColumn": 20 + } + }, + "logicalLocations": [ + { + "index": 20, + "fullyQualifiedName": "std::_Maklocstr" + } + ], + "properties": { + "funcline": "605" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 605, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 608, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 608, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 609, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 610, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 611, + "startColumn": 6 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 612, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 613, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 613, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 615, + "startColumn": 20 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nOverflow using expression '_Mid2'\nBuffer _First2 is a parameter to this function declared on line 872\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First2)`872 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(872)] OR\n offset(_First2)`872 + 2*{loop iterations}'882 + 2 bytes [from annotation SAL_readableTo(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocinfo.h(110) on function _Mbrtowc called at line 883]\nAccessing 2 bytes starting at byte offset 2\nAnnotation on function _Mbrtowc requires that {parameter 1} is of length >= 1 elements (2 bytes/element)\n where {parameter 1} is _Mid2\n[Annotation SAL_writableTo(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocinfo.h(110)]\n\n\nValues of variables:\nPointer (*_Mid2) is at offset 2 bytes from the start of the buffer\nPointer _Mid2 is at offset 0 bytes from the start of _Mid2\n\nwhere\noffset(_First2)`872 == 0\n{loop iterations}'882 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + }, + "logicalLocations": [ + { + "index": 21, + "fullyQualifiedName": "std::codecvt::do_in" + } + ], + "properties": { + "funcline": "872" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 872, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 880, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 899, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 901, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 902, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 903, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPossible precondition violation due to failure to null terminate string '_Mid1'\nBuffer _First1 is a parameter to this function declared on line 872\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First1)`872 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(872)]\nAnnotation on function strlen requires that {parameter 1} is null terminated\n where {parameter 1} is _Mid1 [Annotation _Null_terminated(0)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 28 + } + }, + "logicalLocations": [ + { + "index": 21, + "fullyQualifiedName": "std::codecvt::do_in" + } + ], + "properties": { + "funcline": "872" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 872, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 880, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 894, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 28 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '_Mid1'\nBuffer _First1 is a parameter to this function declared on line 872\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First1)`872 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(872)] OR\n offset(_First1)`872 + result.strlen`895a + 1 bytes [from annotation _In_(elementCount(return + 1)) on function strlen called at line 895]\nAccessing 1 bytes starting at byte offset result.strlen`895a + 1\nAnnotation on function strlen requires that {parameter 1} is of length >= 1 elements (1 bytes/element)\n where {parameter 1} is _Mid1\n[Annotation _Pre_valid_(elementCount(1))]\n\n\nValues of variables:\nPointer (*_Mid1) is at offset result.strlen`895a + 1 bytes from the start of the buffer\nPointer _Mid1 is at offset 0 bytes from the start of _Mid1\n\nwhere\noffset((*_Mid1))`882 == 0\noffset(_First1)`872 == 0\noffset(_Last1)`872 == 0\noffset(_First1)`872 + result.strlen`895a == nullpos(_First1)`895\nnullpos(_First1)`895 >= 0\nresult.strlen`895a >= 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 28 + } + }, + "logicalLocations": [ + { + "index": 21, + "fullyQualifiedName": "std::codecvt::do_in" + } + ], + "properties": { + "funcline": "872" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 872, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 878, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 879, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 880, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 894, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 899, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 901, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 902, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 903, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 882, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 883, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 894, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 895, + "startColumn": 28 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential overflow using expression '_Mid2'\nBuffer _First2 is a parameter to this function declared on line 908\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First2)`908 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(908)]\nAccessing 1 bytes starting at byte offset result._Wcrtomb`920a\nAnnotation on function _Wcrtomb requires that {parameter 1} is of length >= 1 elements (1 bytes/element)\n where {parameter 1} is _Mid2\n[Annotation SAL_writableTo(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocinfo.h(112)]\n\n\nValues of variables:\nPointer (*_Mid2) is at offset result._Wcrtomb`920a bytes from the start of the buffer\nPointer _Mid2 is at offset 0 bytes from the start of _Mid2\n\nwhere\noffset((*_Mid2))`918 == 0\noffset(_First2)`908 == 0\noffset(_Last2)`908 == 0\nresult._Wcrtomb`920a >= 0\nresult.___mb_cur_max_func`919a + result._Wcrtomb`920a <= 0\n\nOverrun access occurs when\nresult._Wcrtomb`920a >= 1\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + }, + "logicalLocations": [ + { + "index": 22, + "fullyQualifiedName": "std::codecvt::do_out" + } + ], + "properties": { + "funcline": "908" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 908, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 914, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 914, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 916, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 921, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 6 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* (_Mid1)'\nBuffer _First1 is a parameter to this function declared on line 908\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First1)`908 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(908)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer (*_Mid1) is at offset 2 bytes from the start of the buffer\nPointer _Mid1 is at offset 0 bytes from the start of _Mid1\n\nwhere\ndelta_offset((*_Mid1))`918 == 0\noffset(_First1)`908 == 0\noffset(_Last1)`908 == 0\n{loop iterations}'918 == 0\n\nThere are other instances of this error:\nPossibly incorrect single element annotation on buffer at line 930\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + }, + "logicalLocations": [ + { + "index": 22, + "fullyQualifiedName": "std::codecvt::do_out" + } + ], + "properties": { + "funcline": "908" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 908, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 914, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 914, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 915, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 916, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 921, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 6 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 924, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 918, + "startColumn": 35 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 919, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 920, + "startColumn": 27 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPossible precondition violation due to failure to null terminate string '_Mid1'\nBuffer _First1 is a parameter to this function declared on line 972\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First1)`972 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(972)]\nAnnotation on function strlen requires that {parameter 1} is null terminated\n where {parameter 1} is _Mid1 [Annotation _Null_terminated(0)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 28 + } + }, + "logicalLocations": [ + { + "index": 23, + "fullyQualifiedName": "std::codecvt::do_length" + } + ], + "properties": { + "funcline": "972" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 972, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 976, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 977, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 978, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 978, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 980, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 980, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 20 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 38 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 983, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 984, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 996, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 28 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '_Mid1'\nBuffer _First1 is a parameter to this function declared on line 972\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First1)`972 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(972)] OR\n offset(_First1)`972 + result.strlen`997a + 1 bytes [from annotation _In_(elementCount(return + 1)) on function strlen called at line 997]\nAccessing 1 bytes starting at byte offset result.strlen`997a + 1\nAnnotation on function strlen requires that {parameter 1} is of length >= 1 elements (1 bytes/element)\n where {parameter 1} is _Mid1\n[Annotation _Pre_valid_(elementCount(1))]\n\n\nValues of variables:\nPointer _Mid1 is at offset result.strlen`997a + 1 bytes from the start of the buffer\n\nwhere\noffset(_First1)`972 == 0\noffset(_Mid1)`981 == 0\noffset(_First1)`972 + result.strlen`997a == nullpos(_First1)`997\nnullpos(_First1)`997 >= 0\nresult.strlen`997a >= 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 28 + } + }, + "logicalLocations": [ + { + "index": 23, + "fullyQualifiedName": "std::codecvt::do_length" + } + ], + "properties": { + "funcline": "972" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 972, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 976, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 977, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 978, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 978, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 980, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 980, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 20 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 38 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 983, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 984, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 996, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1001, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1003, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1004, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 20 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 981, + "startColumn": 38 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 983, + "startColumn": 8 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 984, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 19 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 986, + "startColumn": 4 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 996, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 997, + "startColumn": 28 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1520\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First)`1520 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1520)]\nAccessing the byte at byte offset 1\n\nValues of variables:\nPointer _First is at offset 1 bytes from the start of the buffer\n\nwhere\noffset(_First)`1520 == 0\n{loop iterations}'1524 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1525, + "startColumn": 29 + } + }, + "logicalLocations": [ + { + "index": 24, + "fullyQualifiedName": "std::ctype::do_tolower" + } + ], + "properties": { + "funcline": "1520" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1520, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1524, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1525, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1525, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1524, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1524, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1525, + "startColumn": 29 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1534\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First)`1534 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1534)]\nAccessing the byte at byte offset 1\n\nValues of variables:\nPointer _First is at offset 1 bytes from the start of the buffer\n\nwhere\noffset(_First)`1534 == 0\n{loop iterations}'1538 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1539, + "startColumn": 29 + } + }, + "logicalLocations": [ + { + "index": 25, + "fullyQualifiedName": "std::ctype::do_toupper" + } + ], + "properties": { + "funcline": "1534" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1534, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1538, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1539, + "startColumn": 29 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1539, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1538, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1538, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1539, + "startColumn": 29 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nPotential overflow using expression '(void *)_Dest'\nBuffer _Dest is a parameter to this function declared on line 1557\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Dest)`1557 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1557)]\nAccessing _Dest_size`1557 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 1} is of length >= {parameter 2} bytes\n where {parameter 1} is (void *)_Dest; {parameter 2} is _Dest_size\n[Annotation SAL_writableTo(byteCount({parameter 2})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _Dest is at offset 0 bytes from the start of the buffer\n_Dest_size = _Dest_size`1557\n\nwhere\noffset(_Dest)`1557 == 0\noffset(_First)`1557 == 0\noffset(_Last)`1557 == 0\n_Dest_size`1557 >= 0\n_Dest_size`1557 >= 0\n\nOverrun access occurs when\n_Dest_size`1557 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1563, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 26, + "fullyQualifiedName": "std::ctype::_Do_widen_s" + } + ], + "properties": { + "funcline": "1557" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1557, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1562, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1563, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nPotential overflow using expression '(void *)_Dest'\nBuffer _Dest is a parameter to this function declared on line 1581\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Dest)`1581 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1581)]\nAccessing _Dest_size`1581 bytes starting at byte offset 0\nAnnotation on function memcpy_s requires that {parameter 1} is of length >= {parameter 2} bytes\n where {parameter 1} is (void *)_Dest; {parameter 2} is _Dest_size\n[Annotation SAL_writableTo(byteCount({parameter 2})) at c:\\somepath\\crt\\string.h(55)]\n\n\nValues of variables:\nPointer _Dest is at offset 0 bytes from the start of the buffer\n_Dest_size = _Dest_size`1581\n\nwhere\noffset(_Dest)`1581 == 0\noffset(_First)`1581 == 0\noffset(_Last)`1581 == 0\n_Dest_size`1581 >= 0\n_Dest_size`1581 >= 0\n\nOverrun access occurs when\n_Dest_size`1581 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1587, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 27, + "fullyQualifiedName": "std::ctype::_Do_narrow_s" + } + ], + "properties": { + "funcline": "1581" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1581, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1586, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1587, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1756\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First)`1756 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1756)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _First is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_First)`1756 == 0\n{loop iterations}'1760 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 17 + } + }, + "logicalLocations": [ + { + "index": 28, + "fullyQualifiedName": "std::ctype::do_scan_is" + } + ], + "properties": { + "funcline": "1756" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1756, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 38 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1760, + "startColumn": 17 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1765\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First)`1765 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1765)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _First is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_First)`1765 == 0\n{loop iterations}'1769 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 16 + } + }, + "logicalLocations": [ + { + "index": 29, + "fullyQualifiedName": "std::ctype::do_scan_not" + } + ], + "properties": { + "funcline": "1765" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1765, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 37 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1769, + "startColumn": 16 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1779\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First)`1779 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1779)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _First is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_First)`1779 == 0\n{loop iterations}'1783 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1784, + "startColumn": 23 + } + }, + "logicalLocations": [ + { + "index": 30, + "fullyQualifiedName": "std::ctype::do_tolower" + } + ], + "properties": { + "funcline": "1779" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1779, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1783, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1784, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1784, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1783, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1783, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1784, + "startColumn": 23 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1793\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_First)`1793 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1793)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _First is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_First)`1793 == 0\n{loop iterations}'1797 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1798, + "startColumn": 23 + } + }, + "logicalLocations": [ + { + "index": 31, + "fullyQualifiedName": "std::ctype::do_toupper" + } + ], + "properties": { + "funcline": "1793" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1793, + "startColumn": 24 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1797, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1798, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1798, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1797, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1797, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1798, + "startColumn": 23 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1824\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First)`1824 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1824)]\nAccessing the byte at byte offset 1\n\nValues of variables:\nPointer _First is at offset 1 bytes from the start of the buffer\n\nwhere\noffset(_First)`1824 == 0\noffset(_Last)`1824 == 0\n{loop iterations}'1830 == 0\n_Dest_size`1824 >= 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 21 + } + }, + "logicalLocations": [ + { + "index": 32, + "fullyQualifiedName": "std::ctype::_Do_widen_s" + } + ], + "properties": { + "funcline": "1824" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1824, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1829, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 21 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nOverflow using expression '* _Dest'\nBuffer _Dest is a parameter to this function declared on line 1824\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Dest)`1824 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1824)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _Dest is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_Dest)`1824 == 0\n{loop iterations}'1830 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 11 + } + }, + "logicalLocations": [ + { + "index": 32, + "fullyQualifiedName": "std::ctype::_Do_widen_s" + } + ], + "properties": { + "funcline": "1824" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1824, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1829, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1830, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1831, + "startColumn": 11 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nRead overflow using expression '* _First'\nBuffer _First is a parameter to this function declared on line 1857\nBuffer lengths are from an assumed __in annotation on the parameter\nBuffer is of length offset(_First)`1857 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1857)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _First is at offset 2 bytes from the start of the buffer\n\nwhere\noffset(_First)`1857 == 0\noffset(_Last)`1857 == 0\n{(offset(_Last)`1857 - offset(_First)`1857) % 2}`1862 == 0\n{(offset(_Last)`1857) / 2}`1862 == 0\n{loop iterations}'1863 == 0\n_Dest_size`1857 >= 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 22 + } + }, + "logicalLocations": [ + { + "index": 33, + "fullyQualifiedName": "std::ctype::_Do_narrow_s" + } + ], + "properties": { + "funcline": "1857" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1857, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1862, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 22 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nOverflow using expression '* _Dest'\nBuffer _Dest is a parameter to this function declared on line 1857\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Dest)`1857 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\xlocale(1857)]\nAccessing the byte at byte offset 1\n\nValues of variables:\nPointer _Dest is at offset 1 bytes from the start of the buffer\n\nwhere\noffset(_Dest)`1857 == 0\n{loop iterations}'1863 == 0\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 11 + } + }, + "logicalLocations": [ + { + "index": 33, + "fullyQualifiedName": "std::ctype::_Do_narrow_s" + } + ], + "properties": { + "funcline": "1857" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1857, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1862, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 7 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1863, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 22 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/xlocale", + "index": 4 + }, + "region": { + "startLine": 1864, + "startColumn": 11 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26035", + "message": { + "text": "Possible precondition violation due to failure to null terminate string '++ pVersions'\nBuffer result.strchr created during call to strchr on line 108\nAnnotation on function atoi requires that {parameter 1} is null terminated\n where {parameter 1} is ++ pVersions [Annotation SAL_nullTerminated at c:\\somepath\\crt\\stdlib.h(456)]\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 113, + "startColumn": 31 + } + }, + "logicalLocations": [ + { + "index": 34, + "fullyQualifiedName": "ReadBinHeader" + } + ], + "properties": { + "funcline": "57" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 57, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 49 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 60, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 62, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 64, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 68, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 70, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 73, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 78, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 85, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 85, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 86, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 91, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 91, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 98, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 99, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 99, + "startColumn": 53 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 103, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 103, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 104, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 108, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 108, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 109, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 113, + "startColumn": 31 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26019", + "message": { + "text": "Potential read overflow using expression '* ((int *)pBuf)'\nBuffer access is apparently unbounded by the buffer size. \n\nIn particular: any constant is not constrained by cBuf`57\n\nBuffer pBuf is a parameter to this function declared on line 57\nBuffer is of length offset(pBuf)`57 + cBuf`57 bytes [from annotation SAL_readableTo(byteCount(cBuf)) at d:\\dev\\win8\\drivers\\tablet\\recognition\\ink\\core\\inferno\\inc\\loadtdnnbin.h(70)]\nAccessing 4 bytes starting at byte offset 32\n\nValues of variables:\nPointer pBuf is at offset 32 bytes from the start of the buffer\n\nwhere\noffset(pBuf)`57 == 0\ncBuf`57 >= 33\n\nOverrun access occurs when\ncBuf`57 <= 35\n\nThere are other instances of this error:\nPotential read overflow using expression '* ((TDNN_TYPES *)pBuf)' at line 125\nPotential read overflow using expression '* ((TDNN_CREATE *)pBuf)' at line 142\nPotential read overflow using expression '* ((DWORD *)pBuf)' at line 150\nPotential read overflow using expression '* ((__time64_t *)pBuf)' at line 159\nPotential read overflow using expression '* ((TDNN_CREATE *)pBuf)' at line 168\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 116, + "startColumn": 17 + } + }, + "logicalLocations": [ + { + "index": 34, + "fullyQualifiedName": "ReadBinHeader" + } + ], + "properties": { + "funcline": "57" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 57, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 59, + "startColumn": 49 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 60, + "startColumn": 11 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 61, + "startColumn": 30 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 62, + "startColumn": 17 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 64, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 68, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 70, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 73, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 78, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 85, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 85, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 86, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 91, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 91, + "startColumn": 21 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 98, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 99, + "startColumn": 18 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 99, + "startColumn": 53 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 103, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 103, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 104, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 108, + "startColumn": 23 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 108, + "startColumn": 15 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 109, + "startColumn": 9 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 113, + "startColumn": 31 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 113, + "startColumn": 25 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 115, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp", + "index": 5 + }, + "region": { + "startLine": 116, + "startColumn": 17 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26006", + "message": { + "text": "Possibly incorrect single element annotation on string buffer\nOverflow using expression '* (_Ptr ++)'\nBuffer _Ptr is a parameter to this function declared on line 324\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Ptr)`324 + 2 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\streambuf(324)]\nAccessing 2 bytes starting at byte offset 2\n\nValues of variables:\nPointer _Ptr is at offset 4 bytes from the start of the buffer\n\nwhere\ndelta__Copied`330 == 0\ndelta__Count`330 == 0\ndelta_offset(_Ptr)`330 == 0\noffset(_Ptr)`324 == 0\n{loop iterations}'330 == 0\n_Count`324 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 35, + "fullyQualifiedName": "std::basic_streambuf >::_Xsgetn_s" + } + ], + "properties": { + "funcline": "324" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 324, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 327, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 3 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 63 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 56 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 347, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 348, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 63 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 56 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "26007", + "message": { + "text": "Possibly incorrect single element annotation on buffer\nOverflow using expression '* (_Ptr ++)'\nBuffer _Ptr is a parameter to this function declared on line 324\nBuffer lengths are from an assumed __inout annotation on the parameter\nBuffer is of length offset(_Ptr)`324 + 1 bytes [from annotation valid(elementCount(1)) at c:\\somepath\\crt\\stl70\\streambuf(324)]\nAccessing the byte at byte offset 1\n\nValues of variables:\nPointer _Ptr is at offset 2 bytes from the start of the buffer\n\nwhere\ndelta__Copied`330 == 0\ndelta__Count`330 == 0\ndelta_offset(_Ptr)`330 == 0\noffset(_Ptr)`324 == 0\n{loop iterations}'330 == 0\n_Count`324 >= 2\n" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + }, + "logicalLocations": [ + { + "index": 36, + "fullyQualifiedName": "std::basic_streambuf >::_Xsgetn_s" + } + ], + "properties": { + "funcline": "324" + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 324, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 327, + "startColumn": 12 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 14 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 28 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 328, + "startColumn": 3 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 16 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 63 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 56 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 347, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 348, + "startColumn": 5 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 330, + "startColumn": 2 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 26 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 331, + "startColumn": 10 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 63 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 56 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 46 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 342, + "startColumn": 33 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 36 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/somepath/crt/stl70/streambuf", + "index": 6 + }, + "region": { + "startLine": 346, + "startColumn": 13 + } + } + } + } + ] + } + ] + } + ] + } + ], + "tool": { + "driver": { + "name": "PREfast", + "fullName": "PREfast Code Analysis" + } + }, + "artifacts": [ + { + "location": { + "uri": "file:///c:/somepath/stralign.h" + } + }, + { + "location": { + "uri": "file:///c:/somepath/crt/tchar.h" + } + }, + { + "location": { + "uri": "file:///c:/somepath/strsafe.h" + } + }, + { + "location": { + "uri": "file:///c:/somepath/crt/stl70/iosfwd" + } + }, + { + "location": { + "uri": "file:///c:/somepath/crt/stl70/xlocale" + } + }, + { + "location": { + "uri": "file:///d:/dev/win8/drivers/tablet/recognition/ink/core/inferno/src/loadtdnnbin.cpp" + } + }, + { + "location": { + "uri": "file:///c:/somepath/crt/stl70/streambuf" + } + } + ], + "logicalLocations": [ + { + "fullyQualifiedName": "ua_wcscpy", + "decoratedName": "ua_wcscpy" + }, + { + "fullyQualifiedName": "_wcsspnp", + "decoratedName": "_wcsspnp" + }, + { + "fullyQualifiedName": "_wcsncat_l", + "decoratedName": "_wcsncat_l" + }, + { + "fullyQualifiedName": "StringCbCopyExW", + "decoratedName": "?StringCbCopyExW@@YGJPAGIPBGPAPAGPAIK@Z" + }, + { + "fullyQualifiedName": "StringCbCopyNExW", + "decoratedName": "?StringCbCopyNExW@@YGJPAGIPBGIPAPAGPAIK@Z" + }, + { + "fullyQualifiedName": "StringCbCatNExW", + "decoratedName": "?StringCbCatNExW@@YGJPAGIPBGIPAPAGPAIK@Z" + }, + { + "fullyQualifiedName": "StringCbPrintfExW", + "decoratedName": "?StringCbPrintfExW@@YAJPAGIPAPAGPAIKPBGZZ" + }, + { + "fullyQualifiedName": "StringCbGetsExW", + "decoratedName": "?StringCbGetsExW@@YGJPAGIPAPAGPAIK@Z" + }, + { + "fullyQualifiedName": "StringCchLengthA", + "decoratedName": "?StringCchLengthA@@YGJPBDIPAI@Z" + }, + { + "fullyQualifiedName": "StringCchLengthW", + "decoratedName": "?StringCchLengthW@@YGJPBGIPAI@Z" + }, + { + "fullyQualifiedName": "StringValidateDestAndLengthA", + "decoratedName": "?StringValidateDestAndLengthA@@YGJPBDIPAII@Z" + }, + { + "fullyQualifiedName": "StringValidateDestAndLengthW", + "decoratedName": "?StringValidateDestAndLengthW@@YGJPBGIPAII@Z" + }, + { + "fullyQualifiedName": "StringExHandleOtherFlagsA", + "decoratedName": "?StringExHandleOtherFlagsA@@YGJPADIIPAPADPAIK@Z" + }, + { + "fullyQualifiedName": "StringExHandleOtherFlagsW", + "decoratedName": "?StringExHandleOtherFlagsW@@YGJPAGIIPAPAGPAIK@Z" + }, + { + "name": "length", + "fullyQualifiedName": "std::char_traits::length", + "decoratedName": "?length@?$char_traits@G@std@@SAIPBG@Z" + }, + { + "name": "_Copy_s", + "fullyQualifiedName": "std::char_traits::_Copy_s", + "decoratedName": "?_Copy_s@?$char_traits@G@std@@SAPAGPAGIPBGI@Z" + }, + { + "name": "_Move_s", + "fullyQualifiedName": "std::char_traits::_Move_s", + "decoratedName": "?_Move_s@?$char_traits@G@std@@SAPAGPAGIPBGI@Z" + }, + { + "name": "length", + "fullyQualifiedName": "std::char_traits::length", + "decoratedName": "?length@?$char_traits@D@std@@SAIPBD@Z" + }, + { + "name": "_Copy_s", + "fullyQualifiedName": "std::char_traits::_Copy_s", + "decoratedName": "?_Copy_s@?$char_traits@D@std@@SAPADPADIPBDI@Z" + }, + { + "name": "_Move_s", + "fullyQualifiedName": "std::char_traits::_Move_s", + "decoratedName": "?_Move_s@?$char_traits@D@std@@SAPADPADIPBDI@Z" + }, + { + "name": "_Maklocstr", + "fullyQualifiedName": "std::_Maklocstr", + "decoratedName": "??$_Maklocstr@G@std@@YAPAGPBDPAGABU_Cvtvec@@@Z" + }, + { + "name": "do_in", + "fullyQualifiedName": "std::codecvt::do_in", + "decoratedName": "?do_in@?$codecvt@GDH@std@@MBEHAAHPBD1AAPBDPAG3AAPAG@Z" + }, + { + "name": "do_out", + "fullyQualifiedName": "std::codecvt::do_out", + "decoratedName": "?do_out@?$codecvt@GDH@std@@MBEHAAHPBG1AAPBGPAD3AAPAD@Z" + }, + { + "name": "do_length", + "fullyQualifiedName": "std::codecvt::do_length", + "decoratedName": "?do_length@?$codecvt@GDH@std@@MBEHABHPBD1I@Z" + }, + { + "name": "do_tolower", + "fullyQualifiedName": "std::ctype::do_tolower", + "decoratedName": "?do_tolower@?$ctype@D@std@@MBEPBDPADPBD@Z" + }, + { + "name": "do_toupper", + "fullyQualifiedName": "std::ctype::do_toupper", + "decoratedName": "?do_toupper@?$ctype@D@std@@MBEPBDPADPBD@Z" + }, + { + "name": "_Do_widen_s", + "fullyQualifiedName": "std::ctype::_Do_widen_s", + "decoratedName": "?_Do_widen_s@?$ctype@D@std@@IBEPBDPBD0PADI@Z" + }, + { + "name": "_Do_narrow_s", + "fullyQualifiedName": "std::ctype::_Do_narrow_s", + "decoratedName": "?_Do_narrow_s@?$ctype@D@std@@IBEPBDPBD0DPADI@Z" + }, + { + "name": "do_scan_is", + "fullyQualifiedName": "std::ctype::do_scan_is", + "decoratedName": "?do_scan_is@?$ctype@G@std@@MBEPBGFPBG0@Z" + }, + { + "name": "do_scan_not", + "fullyQualifiedName": "std::ctype::do_scan_not", + "decoratedName": "?do_scan_not@?$ctype@G@std@@MBEPBGFPBG0@Z" + }, + { + "name": "do_tolower", + "fullyQualifiedName": "std::ctype::do_tolower", + "decoratedName": "?do_tolower@?$ctype@G@std@@MBEPBGPAGPBG@Z" + }, + { + "name": "do_toupper", + "fullyQualifiedName": "std::ctype::do_toupper", + "decoratedName": "?do_toupper@?$ctype@G@std@@MBEPBGPAGPBG@Z" + }, + { + "name": "_Do_widen_s", + "fullyQualifiedName": "std::ctype::_Do_widen_s", + "decoratedName": "?_Do_widen_s@?$ctype@G@std@@IBEPBDPBD0PAGI@Z" + }, + { + "name": "_Do_narrow_s", + "fullyQualifiedName": "std::ctype::_Do_narrow_s", + "decoratedName": "?_Do_narrow_s@?$ctype@G@std@@IBEPBGPBG0DPADI@Z" + }, + { + "fullyQualifiedName": "ReadBinHeader", + "decoratedName": "?ReadBinHeader@@YAPBEPAUtagNET_DESC@@PBEH@Z" + }, + { + "name": "_Xsgetn_s", + "fullyQualifiedName": "std::basic_streambuf >::_Xsgetn_s", + "decoratedName": "?_Xsgetn_s@?$basic_streambuf@GU?$char_traits@G@std@@@std@@IAEHPAGIH@Z" + }, + { + "name": "_Xsgetn_s", + "fullyQualifiedName": "std::basic_streambuf >::_Xsgetn_s", + "decoratedName": "?_Xsgetn_s@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IAEHPADIH@Z" + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} diff --git a/tests/data/sarif_memory/policy.rego b/tests/data/sarif_memory/policy.rego new file mode 100644 index 000000000..a6cf677d2 --- /dev/null +++ b/tests/data/sarif_memory/policy.rego @@ -0,0 +1,84 @@ +package staticAnalysisResult.Verification + +# Final verdict as a string +default compliant := "noncompliant" + +################################################## +# Locate runs +################################################## + +# indices of runs in the SARIF doc +runs_indices contains i if { + doc := input.PrefastConfigContent.resolvedData.content + doc.runs[i] +} + +has_runs if { runs_indices[_] } + +################################################## +# Invocation checks (per run index i) +################################################## + +# at least one success +inv_any_true contains i if { + doc := input.PrefastConfigContent.resolvedData.content + doc.runs[i] # bind i + some j + doc.runs[i].invocations[j].executionSuccessful == true +} + +# any explicit failure +inv_has_false contains i if { + doc := input.PrefastConfigContent.resolvedData.content + doc.runs[i] # bind i + some j + doc.runs[i].invocations[j].executionSuccessful == false +} + +# invocation OK iff there is at least one true AND no false +inv_ok contains i if { + runs_indices[i] # bind i + inv_any_true[i] + not inv_has_false[i] +} + +################################################## +# Results empty (per run index i) +################################################## + +# missing results counts as empty +results_empty contains i if { + doc := input.PrefastConfigContent.resolvedData.content + doc.runs[i] # bind i + not doc.runs[i].results +} + +# results exists and is an empty array +results_empty contains i if { + doc := input.PrefastConfigContent.resolvedData.content + doc.runs[i] # bind i + is_array(doc.runs[i].results) + count(doc.runs[i].results) == 0 +} + +################################################## +# Per-run and overall +################################################## + +run_ok contains i if { + runs_indices[i] # bind i + inv_ok[i] + results_empty[i] +} + +# any run index that exists but is not ok +any_non_ok if { + i := runs_indices[_] + not run_ok[i] +} + +# overall verdict string +compliant := "compliant" if { + has_runs + not any_non_ok +} else := "noncompliant" diff --git a/tests/sarif_memory.rs b/tests/sarif_memory.rs new file mode 100644 index 000000000..4f2f59a60 --- /dev/null +++ b/tests/sarif_memory.rs @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! Memory-residency measurement on a real SARIF workload. +//! +//! This test wraps the system allocator to track live / peak memory while +//! parsing a SARIF JSON payload into a `Value`, building an engine, and +//! evaluating a small compliance policy. It prints the numbers and applies +//! coarse sanity bounds so a catastrophic memory regression breaks CI. +//! +//! It is intentionally **the only test in this file** so the custom global +//! allocator's counters reflect only this workload (a cargo integration test +//! file is compiled as its own binary). +//! +//! The dataset can be amplified by setting the `MULT` env var (default 1). +//! `MULT=50` reproduces the original customer-scale memory-pressure scenario +//! that motivated the storage abstractions: ~6.6 MiB JSON → ~227 MiB peak +//! on the unmodified `BTreeMap`-backed `Object`. + +// The custom global allocator below conflicts with regorus's `mimalloc` +// global allocator (set when the `mimalloc` feature is enabled). When that +// feature is on, this whole test becomes a no-op; the test only makes sense +// against the system allocator anyway. +#![cfg(not(feature = "mimalloc"))] + +use std::alloc::{GlobalAlloc, Layout, System}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; + +struct Tracking; + +static LIVE: AtomicUsize = AtomicUsize::new(0); +static PEAK: AtomicUsize = AtomicUsize::new(0); +static TOTAL_ALLOC: AtomicUsize = AtomicUsize::new(0); +static NALLOC: AtomicUsize = AtomicUsize::new(0); +static LOCK: Mutex<()> = Mutex::new(()); + +unsafe impl GlobalAlloc for Tracking { + unsafe fn alloc(&self, l: Layout) -> *mut u8 { + let p = System.alloc(l); + if !p.is_null() { + let n = l.size(); + let cur = LIVE.fetch_add(n, Ordering::Relaxed) + n; + TOTAL_ALLOC.fetch_add(n, Ordering::Relaxed); + NALLOC.fetch_add(1, Ordering::Relaxed); + let mut peak = PEAK.load(Ordering::Relaxed); + while cur > peak { + match PEAK.compare_exchange_weak(peak, cur, Ordering::Relaxed, Ordering::Relaxed) { + Ok(_) => break, + Err(p) => peak = p, + } + } + } + p + } + unsafe fn dealloc(&self, p: *mut u8, l: Layout) { + System.dealloc(p, l); + LIVE.fetch_sub(l.size(), Ordering::Relaxed); + } +} + +#[global_allocator] +static A: Tracking = Tracking; + +#[derive(Copy, Clone)] +struct Snap { + live: usize, + peak: usize, + total: usize, + nalloc: usize, +} + +fn snap() -> Snap { + Snap { + live: LIVE.load(Ordering::Relaxed), + peak: PEAK.load(Ordering::Relaxed), + total: TOTAL_ALLOC.load(Ordering::Relaxed), + nalloc: NALLOC.load(Ordering::Relaxed), + } +} + +fn reset_peak_to_live() { + PEAK.store(LIVE.load(Ordering::Relaxed), Ordering::Relaxed); +} + +fn mib(b: usize) -> f64 { + b as f64 / (1024.0 * 1024.0) +} + +fn report(label: &str, s: Snap, base: Snap) { + println!( + " {:30} live={:>9.3} MiB peak={:>9.3} MiB total_alloc={:>9.3} MiB nalloc={}", + label, + mib(s.live.saturating_sub(base.live)), + mib(s.peak.saturating_sub(base.peak)), + mib(s.total - base.total), + s.nalloc - base.nalloc, + ); +} + +#[test] +fn sarif_memory_residency() { + // The global allocator counters are process-wide; keep the measurement + // serialized even if another test is added to this binary later. + let _guard = LOCK.lock().expect("sarif memory measurement lock poisoned"); + let policy = + std::fs::read_to_string("tests/data/sarif_memory/policy.rego").expect("read policy.rego"); + let input = + std::fs::read_to_string("tests/data/sarif_memory/input.json").expect("read input.json"); + + let mult: usize = std::env::var("MULT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(1); + + // Amplify runs[0].results by MULT so larger workloads can be probed. + let mut v: serde_json::Value = serde_json::from_str(&input).expect("parse SARIF input as JSON"); + if let Some(runs) = v.get_mut("runs").and_then(|r| r.as_array_mut()) { + if let Some(r0) = runs.get_mut(0) { + if let Some(results) = r0.get_mut("results").and_then(|r| r.as_array_mut()) { + let original = results.clone(); + for _ in 1..mult { + results.extend(original.iter().cloned()); + } + } + // Synthesize an invocations array so the policy can succeed. + if r0.get("invocations").is_none() { + if let Some(obj) = r0.as_object_mut() { + obj.insert( + "invocations".into(), + serde_json::json!([{"executionSuccessful": true}]), + ); + } + } + } + } + + // Wrap to match policy schema: input.PrefastConfigContent.resolvedData.content + let wrapped = serde_json::json!({ + "PrefastConfigContent": { "resolvedData": { "content": v } } + }); + let input_json = serde_json::to_string(&wrapped).expect("serialize wrapped input"); + drop(wrapped); + + // Reset baseline so we only count work done from here on. + reset_peak_to_live(); + let base = snap(); + let raw_bytes = input_json.len(); + + println!(); + println!( + "=== SARIF memory residency (MULT={mult}, input JSON = {:.3} MiB) ===", + mib(raw_bytes) + ); + report("baseline", base, base); + + let mut engine = regorus::Engine::new(); + engine + .add_policy("policy.rego".into(), policy.clone()) + .expect("add policy"); + let after_policy = snap(); + report("after add_policy", after_policy, base); + + let input_value = + regorus::Value::from_json_str(&input_json).expect("parse input JSON to Value"); + let after_input_parse = snap(); + report("after Value::from_json_str", after_input_parse, base); + + drop(input_json); + let after_drop_json = snap(); + report("after drop JSON string", after_drop_json, base); + + engine.set_input(input_value); + let after_set_input = snap(); + report("after set_input", after_set_input, base); + + let results = engine + .eval_query( + "data.staticAnalysisResult.Verification.compliant".to_string(), + false, + ) + .expect("eval query"); + let after_eval = snap(); + report("after eval_query", after_eval, base); + + let result_value = results + .result + .first() + .and_then(|r| r.expressions.first()) + .map(|e| e.value.clone()); + println!(" query result: {result_value:?}"); + + let parse_live = after_input_parse.live.saturating_sub(after_policy.live); + let eval_live = after_eval.live.saturating_sub(after_set_input.live); + let peak_during_eval = after_eval.peak.saturating_sub(base.peak); + let value_blowup = parse_live as f64 / raw_bytes as f64; + + println!(); + println!( + " --> Value::from_json_str cost: live +{:.3} MiB ({:.2}× JSON size)", + mib(parse_live), + value_blowup + ); + println!( + " --> eval cost: live +{:.3} MiB", + mib(eval_live) + ); + println!( + " --> peak during run: {:.3} MiB", + mib(peak_during_eval) + ); + + // Coarse sanity bound: even an unoptimized BTreeMap-backed Object should + // not balloon to more than ~50× the JSON size for the un-amplified case + // (MULT=1). The historical baseline (MULT=50, BTreeMap) was ~30× live + // blow-up; we leave plenty of headroom for the unamplified case so this + // assert only catches genuinely catastrophic regressions. + let max_blowup = 50.0; + assert!( + value_blowup < max_blowup, + "Value blow-up ratio {value_blowup:.2}× exceeds {max_blowup}× — \ + possible memory regression in Value/Object representation" + ); +} From 1bb71ba552efe27070ff119a73a1053aea74d882 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi Date: Sun, 16 Aug 2026 18:31:40 -0500 Subject: [PATCH 2/3] test(opa): remove stale OPA checkout before cloning A stale/partial OPA checkout (left by a cancelled run or restored from a build cache) can exist under target/opa/branch/ without a `.git` directory. `git clone` refuses to clone into a non-empty directory, so the harness failed with "destination path already exists and is not an empty directory", breaking the debug/release/musl CI test jobs. Remove any such stale directory before cloning. Cherry-picked from microsoft/regorus#789. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ac07e53-88fc-4050-bd56-c0d9761b911b --- tests/opa.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/opa.rs b/tests/opa.rs index 79be338b0..a76f46c1b 100644 --- a/tests/opa.rs +++ b/tests/opa.rs @@ -685,6 +685,15 @@ fn main() -> Result<()> { Some(p) => p, None => { let branch_dir = format!("target/opa/branch/{OPA_BRANCH}"); + if std::path::Path::exists(Path::new(&branch_dir)) + && !std::path::Path::exists(Path::new(format!("{branch_dir}/.git").as_str())) + { + // A stale/partial checkout (e.g. left behind by a cancelled + // run or restored from a build cache) can exist without a + // `.git` directory. `git clone` refuses to clone into a + // non-empty directory, so remove any stale contents first. + std::fs::remove_dir_all(&branch_dir)?; + } std::fs::create_dir_all(&branch_dir)?; if !std::path::Path::exists(Path::new(format!("{branch_dir}/.git").as_str())) { let output = match Command::new("git") From 2430075d966989b090bbfa38433ec2b9248d5d85 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi Date: Sun, 16 Aug 2026 20:36:24 -0500 Subject: [PATCH 3/3] feat(value): intern object keys during JSON parsing Deduplicate object *keys* while parsing JSON in `Value::from_json_str` (and thus `from_json_file`). A homogeneous array of N objects that share K keys now allocates K key strings instead of N * K; every repeated key becomes a reference-count clone of a single `Rc`. Interning is scoped to a single parse via a thread-local table installed by an RAII `InternGuard`, so there is no thread-lifetime cache: the table is torn down when the parse completes (including on the error path). Only keys are interned -- string *values* are left untouched since their cardinality is unbounded. The new `interning` module is std-only; under `no_std` the hooks compile to no-ops. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ac07e53-88fc-4050-bd56-c0d9761b911b --- src/value/interning.rs | 101 ++++++++++++++++++++++++++++++++++++++ src/value/mod.rs | 28 ++++++++++- src/value/object/serde.rs | 11 ++++- src/value/tests.rs | 78 +++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 src/value/interning.rs diff --git a/src/value/interning.rs b/src/value/interning.rs new file mode 100644 index 000000000..982a1bda8 --- /dev/null +++ b/src/value/interning.rs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! Thread-local interning of object **keys** during JSON deserialization. +//! +//! [`Value::from_json_str`](crate::Value::from_json_str) installs a thread-local +//! [`InternTable`] for the duration of the parse (see [`InternGuard`]). Object +//! keys parsed while a table is installed are deduplicated: a homogeneous array +//! of `N` objects sharing `K` keys allocates `K` key strings instead of +//! `N * K`, and every later occurrence becomes a reference-count clone. Only +//! keys are interned -- string *values* are left untouched, since their +//! cardinality is unbounded and interning them can cost more than it saves. +//! +//! The table lives only for the parse and is torn down when the guard drops, so +//! there is no unbounded, thread-lifetime cache. This module is std-only: it +//! relies on `thread_local!`. + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A content-addressed interning table scoped to a single deserialization call. +/// +/// Stores each distinct key's own `Rc` (the allocation serde already made), +/// so interning a repeated key returns a reference-count clone of that existing +/// allocation and never copies the key bytes a second time. +struct InternTable { + set: HashSet>, +} + +impl InternTable { + fn new() -> Self { + Self { + set: HashSet::new(), + } + } + + /// Return an interned handle equal to `rc`. The first time a given key is + /// seen its own allocation is retained and returned; later occurrences reuse + /// that allocation and the caller's `rc` is dropped. + fn intern(&mut self, rc: crate::Rc) -> crate::Rc { + if let Some(existing) = self.set.get(rc.as_ref()) { + return crate::Rc::clone(existing); + } + self.set.insert(crate::Rc::clone(&rc)); + rc + } +} + +std::thread_local! { + static TABLE: RefCell> = const { RefCell::new(None) }; +} + +/// RAII guard that installs a thread-local [`InternTable`] for the duration of a +/// deserialization call. Re-entrant: if a table is already installed (e.g. a +/// nested parse), this guard reuses it and does not tear it down on drop. +pub struct InternGuard { + installed_by_us: bool, +} + +impl InternGuard { + /// Install a fresh intern table for the current thread, unless one is + /// already installed (in which case the existing table is reused). + pub fn install() -> Self { + let installed_by_us = TABLE.with(|t| { + let mut slot = t.borrow_mut(); + if slot.is_none() { + *slot = Some(InternTable::new()); + true + } else { + false + } + }); + Self { installed_by_us } + } +} + +impl Drop for InternGuard { + fn drop(&mut self) { + if self.installed_by_us { + TABLE.with(|t| { + *t.borrow_mut() = None; + }); + } + } +} + +/// Intern `rc` using the current thread's active [`InternTable`], if one is +/// installed. Outside a parse (no guard active) the original `rc` is returned +/// unchanged, so callers keep their allocation with no interning overhead. +pub fn intern_key(rc: crate::Rc) -> crate::Rc { + TABLE.with(|t| match t.borrow_mut().as_mut() { + Some(table) => table.intern(rc), + None => rc, + }) +} + +/// Test-only probe: whether an intern table is currently installed on this thread. +#[cfg(test)] +pub fn is_installed() -> bool { + TABLE.with(|t| t.borrow().is_some()) +} diff --git a/src/value/mod.rs b/src/value/mod.rs index 80da18d3b..84351fb74 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -15,6 +15,9 @@ mod array; mod object; mod set; +#[cfg(feature = "std")] +mod interning; + #[cfg(test)] mod tests; @@ -237,11 +240,11 @@ impl<'de> Visitor<'de> for ValueVisitor { } } let mut map = BTreeMap::new(); - map.insert(key, value); + map.insert(intern_object_key(key), value); // Enforce allocator limit while expanding a deserialized object. enforce_limit_for::()?; while let Some((key, value)) = visitor.next_entry()? { - map.insert(key, value); + map.insert(intern_object_key(key), value); // Enforce allocator limit while expanding a deserialized object. enforce_limit_for::()?; } @@ -256,6 +259,23 @@ impl<'de> Visitor<'de> for ValueVisitor { } } +/// Key-only interning hook for the JSON deserialization hot path (see +/// [`crate::value::interning`]). No-op when no interning session is installed +/// or when built without the `std` feature. +#[cfg(feature = "std")] +fn intern_object_key(key: Value) -> Value { + match key { + Value::String(rc) => Value::String(interning::intern_key(rc)), + other => other, + } +} + +/// No-op key hook for builds without the `std` feature (no interning table). +#[cfg(not(feature = "std"))] +const fn intern_object_key(key: Value) -> Value { + key +} + #[doc(hidden)] impl<'de> Deserialize<'de> for Value { fn deserialize(deserializer: D) -> Result @@ -362,6 +382,10 @@ impl Value { /// # } /// ``` pub fn from_json_str(json: &str) -> Result { + // Intern object keys for the duration of the parse: a homogeneous array + // of N objects sharing K keys allocates K key strings instead of N * K. + #[cfg(feature = "std")] + let _guard = interning::InternGuard::install(); match serde_json::from_str::(json) { Ok(value) => Ok(value), Err(err) => { diff --git a/src/value/object/serde.rs b/src/value/object/serde.rs index 96eee178b..6f3c3c23f 100644 --- a/src/value/object/serde.rs +++ b/src/value/object/serde.rs @@ -43,7 +43,16 @@ impl<'de> Visitor<'de> for ObjectVisitor { fn visit_map>(self, mut access: A) -> Result { let mut obj = Object::new(); - while let Some((k, v)) = access.next_entry::()? { + while let Some(k) = access.next_key::()? { + let v = access.next_value::()?; + // Key-only interning: dedup key `Rc` allocations across objects + // parsed within the same interning session. String *values* are left + // untouched. + #[cfg(feature = "std")] + let k = match k { + Value::String(rc) => Value::String(crate::value::interning::intern_key(rc)), + other => other, + }; obj.insert(k, v); crate::utils::limits::check_memory_limit_if_needed() .map_err(|err| A::Error::custom(err.to_string()))?; diff --git a/src/value/tests.rs b/src/value/tests.rs index eba83b549..2465951fc 100644 --- a/src/value/tests.rs +++ b/src/value/tests.rs @@ -1040,3 +1040,81 @@ fn object_remove_absent_on_frozen_stays_frozen() { assert_eq!(obj.storage_variant_for_memory_diagnostics(), "BTree"); assert_eq!(obj.get(&val(1)), None); } + +#[cfg(feature = "std")] +mod interning_tests { + use crate::Value; + use alloc::vec::Vec; + + // Parse a homogeneous array of objects sharing keys and return the parsed value. + fn parse(json: &str) -> Value { + Value::from_json_str(json).expect("valid json") + } + + #[test] + fn interning_preserves_values_round_trip() { + let json = r#"[{"ruleId":"A","level":"error"},{"ruleId":"B","level":"warning"}]"#; + let value = parse(json); + let arr = value.as_array().expect("array"); + assert_eq!(arr.len(), 2); + assert_eq!(arr[0].as_object().expect("object").len(), 2); + assert_eq!(arr[0]["ruleId"], Value::from("A")); + assert_eq!(arr[1]["level"], Value::from("warning")); + } + + #[test] + fn parse_error_cleans_up_intern_session() { + // Truncated input that is valid up to and including an interned key + // (`"k"`) before hitting EOF, so at least one key is interned before the + // parse fails. The guard must still tear the table down on the error + // path, leaving no session installed for the next parse. + Value::from_json_str(r#"{"k":1,"#).expect_err("truncated json must error"); + assert!( + !crate::value::interning::is_installed(), + "intern table must be torn down after a failed parse" + ); + let value = parse(r#"{"k":"v"}"#); + assert_eq!(value["k"], Value::from("v")); + } + + #[test] + fn nested_guards_reuse_and_teardown_once() { + use crate::value::interning::{is_installed, InternGuard}; + assert!(!is_installed(), "no session before install"); + let outer = InternGuard::install(); + assert!(is_installed(), "outer installs the table"); + { + let inner = InternGuard::install(); + assert!(is_installed(), "inner reuses the existing table"); + drop(inner); + // The inner guard did not install the table, so dropping it must not + // tear the table down out from under the outer guard. + assert!(is_installed(), "inner drop preserves the outer table"); + } + drop(outer); + assert!(!is_installed(), "only the installing guard tears down"); + } + + // Repeated keys across sibling objects share a single Rc allocation. + #[test] + fn repeated_keys_share_allocation() { + let json = r#"[{"ruleId":"A"},{"ruleId":"B"},{"ruleId":"C"}]"#; + let value = parse(json); + let arr = value.as_array().expect("array"); + + let mut ptrs = Vec::new(); + for elem in arr.iter() { + let obj = elem.as_object().expect("object"); + for (k, _) in obj.iter() { + if let Value::String(rc) = k { + ptrs.push(crate::Rc::as_ptr(rc)); + } + } + } + assert_eq!(ptrs.len(), 3); + assert!( + ptrs.windows(2).all(|w| core::ptr::addr_eq(w[0], w[1])), + "repeated object keys should share one interned allocation" + ); + } +}