Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(general): Workaround for php frame vars #159

Merged
merged 2 commits into from
Jan 22, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 69 additions & 6 deletions general/src/protocol/stacktrace.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::protocol::{Addr, RegVal};
use crate::types::{Annotated, Array, Object, Value};
use crate::types::{Annotated, Array, FromValue, Object, Value};

/// Holds information about a single stacktrace frame.
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, ToValue, ProcessValue)]
Expand Down Expand Up @@ -72,8 +72,7 @@ pub struct Frame {

/// Local variables in a convenient format.
#[metastructure(pii = "true")]
#[metastructure(skip_serialization = "empty")]
pub vars: Annotated<Object<Value>>,
pub vars: Annotated<FrameVars>,

/// Start address of the containing code module (image).
pub image_addr: Annotated<Addr>,
Expand All @@ -93,6 +92,35 @@ pub struct Frame {
pub other: Object<Value>,
}

#[derive(Clone, Debug, Default, PartialEq, Empty, ToValue, ProcessValue)]
pub struct FrameVars(#[metastructure(skip_serialization = "empty")] pub Object<Value>);

impl From<Object<Value>> for FrameVars {
fn from(value: Object<Value>) -> Self {
FrameVars(value)
}
}

impl FromValue for FrameVars {
fn from_value(mut value: Annotated<Value>) -> Annotated<FrameVars> {
value = value.map_value(|value| {
if let Value::Array(value) = value {
Value::Object(
value
.into_iter()
.enumerate()
.map(|(i, v)| (i.to_string(), v))
.collect(),
)
} else {
value
}
});

FromValue::from_value(value).map_value(FrameVars)
}
}

/// Holds information about an entirey stacktrace.
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, ToValue, ProcessValue)]
#[metastructure(process_func = "process_stacktrace", value_type = "Stacktrace")]
Expand Down Expand Up @@ -157,7 +185,7 @@ fn test_frame_roundtrip() {
"variable".to_string(),
Annotated::new(Value::String("value".to_string())),
);
Annotated::new(vars)
Annotated::new(vars.into())
},
image_addr: Annotated::new(Addr(0x400)),
instruction_addr: Annotated::new(Addr(0x404)),
Expand Down Expand Up @@ -258,7 +286,7 @@ fn test_frame_vars_null_preserved() {
vars: Annotated::new({
let mut vars = Object::new();
vars.insert("despacito".to_string(), Annotated::empty());
vars
vars.into()
}),
..Default::default()
});
Expand All @@ -280,7 +308,7 @@ fn test_frame_vars_empty_annotated_is_serialized() {
let mut vars = Object::new();
vars.insert("despacito".to_string(), Annotated::empty());
vars.insert("despacito2".to_string(), Annotated::empty());
vars
vars.into()
}),
..Default::default()
});
Expand Down Expand Up @@ -310,3 +338,38 @@ fn test_frame_empty_context_lines() {
assert_eq_dbg!(frame, Annotated::from_json(json).unwrap());
assert_eq_str!(json, frame.to_json_pretty().unwrap());
}

#[test]
fn test_php_frame_vars() {
// Buggy PHP SDKs send us this stuff
//
// Port of https://github.com/getsentry/sentry/commit/73d9a061dcac3ab8c318a09735601a12e81085dd

let input = r#"{
"vars": ["foo", "bar", "baz", null]
}"#;

let output = r#"{
"vars": {
"0": "foo",
"1": "bar",
"2": "baz",
"3": null
}
}"#;

let frame = Annotated::new(Frame {
vars: Annotated::new({
let mut vars = Object::new();
vars.insert("0".to_string(), Annotated::new("foo".to_string().into()));
vars.insert("1".to_string(), Annotated::new("bar".to_string().into()));
vars.insert("2".to_string(), Annotated::new("baz".to_string().into()));
vars.insert("3".to_string(), Annotated::empty());
vars.into()
}),
..Default::default()
});

assert_eq_dbg!(frame, Annotated::from_json(input).unwrap());
assert_eq_str!(output, frame.to_json_pretty().unwrap());
}