77
77
FALSY_ENV_VALUES = frozenset (("false" , "f" , "n" , "no" , "off" , "0" ))
78
78
TRUTHY_ENV_VALUES = frozenset (("true" , "t" , "y" , "yes" , "on" , "1" ))
79
79
80
+ MAX_STACK_FRAMES = 2000
81
+ """Maximum number of stack frames to send to Sentry.
82
+
83
+ If we have more than this number of stack frames, we will stop processing
84
+ the stacktrace to avoid getting stuck in a long-lasting loop. This value
85
+ exceeds the default sys.getrecursionlimit() of 1000, so users will only
86
+ be affected by this limit if they have a custom recursion limit.
87
+ """
88
+
80
89
81
90
def env_to_bool (value , * , strict = False ):
82
91
# type: (Any, Optional[bool]) -> bool | None
@@ -732,10 +741,23 @@ def single_exception_from_error_tuple(
732
741
max_value_length = max_value_length ,
733
742
custom_repr = custom_repr ,
734
743
)
735
- for tb in iter_stacks (tb )
744
+ # Process at most MAX_STACK_FRAMES + 1 frames, to avoid hanging on
745
+ # processing a super-long stacktrace.
746
+ for tb , _ in zip (iter_stacks (tb ), range (MAX_STACK_FRAMES + 1 ))
736
747
] # type: List[Dict[str, Any]]
737
748
738
- if frames :
749
+ if len (frames ) > MAX_STACK_FRAMES :
750
+ # If we have more frames than the limit, we remove the stacktrace completely.
751
+ # We don't trim the stacktrace here because we have not processed the whole
752
+ # thing (see above, we stop at MAX_STACK_FRAMES + 1). Normally, Relay would
753
+ # intelligently trim by removing frames in the middle of the stacktrace, but
754
+ # since we don't have the whole stacktrace, we can't do that. Instead, we
755
+ # drop the entire stacktrace.
756
+ exception_value ["stacktrace" ] = AnnotatedValue .removed_because_over_size_limit (
757
+ value = None
758
+ )
759
+
760
+ elif frames :
739
761
if not full_stack :
740
762
new_frames = frames
741
763
else :
@@ -941,7 +963,7 @@ def to_string(value):
941
963
942
964
943
965
def iter_event_stacktraces (event ):
944
- # type: (Event) -> Iterator[Dict[str, Any]]
966
+ # type: (Event) -> Iterator[Annotated[ Dict[str, Any] ]]
945
967
if "stacktrace" in event :
946
968
yield event ["stacktrace" ]
947
969
if "threads" in event :
@@ -950,20 +972,26 @@ def iter_event_stacktraces(event):
950
972
yield thread ["stacktrace" ]
951
973
if "exception" in event :
952
974
for exception in event ["exception" ].get ("values" ) or ():
953
- if "stacktrace" in exception :
975
+ if isinstance ( exception , dict ) and "stacktrace" in exception :
954
976
yield exception ["stacktrace" ]
955
977
956
978
957
979
def iter_event_frames (event ):
958
980
# type: (Event) -> Iterator[Dict[str, Any]]
959
981
for stacktrace in iter_event_stacktraces (event ):
982
+ if isinstance (stacktrace , AnnotatedValue ):
983
+ stacktrace = stacktrace .value or {}
984
+
960
985
for frame in stacktrace .get ("frames" ) or ():
961
986
yield frame
962
987
963
988
964
989
def handle_in_app (event , in_app_exclude = None , in_app_include = None , project_root = None ):
965
990
# type: (Event, Optional[List[str]], Optional[List[str]], Optional[str]) -> Event
966
991
for stacktrace in iter_event_stacktraces (event ):
992
+ if isinstance (stacktrace , AnnotatedValue ):
993
+ stacktrace = stacktrace .value or {}
994
+
967
995
set_in_app_in_frames (
968
996
stacktrace .get ("frames" ),
969
997
in_app_exclude = in_app_exclude ,
0 commit comments