Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: runtime/vm/exceptions.cc

Issue 12320103: Fix for bug 6767 - Limit stack trace collection for stack overflow exceptions. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | runtime/vm/raw_object_snapshot.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/exceptions.h" 5 #include "vm/exceptions.h"
6 6
7 #include "vm/dart_api_impl.h" 7 #include "vm/dart_api_impl.h"
8 #include "vm/dart_entry.h" 8 #include "vm/dart_entry.h"
9 #include "vm/debugger.h" 9 #include "vm/debugger.h"
10 #include "vm/flags.h" 10 #include "vm/flags.h"
11 #include "vm/object.h" 11 #include "vm/object.h"
12 #include "vm/object_store.h" 12 #include "vm/object_store.h"
13 #include "vm/stack_frame.h" 13 #include "vm/stack_frame.h"
14 #include "vm/stub_code.h" 14 #include "vm/stub_code.h"
15 #include "vm/symbols.h" 15 #include "vm/symbols.h"
16 16
17 namespace dart { 17 namespace dart {
18 18
19 DEFINE_FLAG(bool, print_stacktrace_at_throw, false, 19 DEFINE_FLAG(bool, print_stacktrace_at_throw, false,
20 "Prints a stack trace everytime a throw occurs."); 20 "Prints a stack trace everytime a throw occurs.");
21 DEFINE_FLAG(bool, heap_profile_out_of_memory, false, 21 DEFINE_FLAG(bool, heap_profile_out_of_memory, false,
22 "Writes a heap profile on unhandled out-of-memory exceptions."); 22 "Writes a heap profile on unhandled out-of-memory exceptions.");
23 DEFINE_FLAG(bool, verbose_stacktrace, false, 23 DEFINE_FLAG(bool, verbose_stacktrace, false,
24 "Stack traces will include methods marked invisible."); 24 "Stack traces will include methods marked invisible.");
25 25
26 const char* Exceptions::kCastErrorDstName = "type cast"; 26 const char* Exceptions::kCastErrorDstName = "type cast";
27 27
28 28
29 class StacktraceBuilder : public ValueObject {
30 public:
31 StacktraceBuilder() { }
32 virtual ~StacktraceBuilder() { }
33
34 virtual void AddFrame(const Function& func,
35 const Code& code,
36 const Smi& offset) = 0;
37 };
38
39
40 class RegularStacktraceBuilder : public StacktraceBuilder {
41 public:
42 RegularStacktraceBuilder(const GrowableObjectArray& func_list,
43 const GrowableObjectArray& code_list,
44 const GrowableObjectArray& pc_offset_list)
45 : func_list_(func_list),
46 code_list_(code_list),
47 pc_offset_list_(pc_offset_list) { }
48 ~RegularStacktraceBuilder() { }
49
50 const GrowableObjectArray& func_list() const { return func_list_; }
51 const GrowableObjectArray& code_list() const { return code_list_; }
52 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; }
53
54 void AddFrame(const Function& func, const Code& code, const Smi& offset) {
55 func_list_.Add(func);
56 code_list_.Add(code);
57 pc_offset_list_.Add(offset);
58 }
59
60 private:
61 const GrowableObjectArray& func_list_;
62 const GrowableObjectArray& code_list_;
63 const GrowableObjectArray& pc_offset_list_;
64
65 DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder);
66 };
67
68
69 class PreallocatedStacktraceBuilder : public StacktraceBuilder {
70 public:
71 explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace)
72 : stacktrace_(stacktrace),
73 cur_index_(0) { }
74 ~PreallocatedStacktraceBuilder() { }
75
76 void AddFrame(const Function& func, const Code& code, const Smi& offset);
77
78 private:
79 static const int kNumTopframes = 3;
80
81 const Stacktrace& stacktrace_;
82 intptr_t cur_index_;
83
84 DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder);
85 };
86
87
88 void PreallocatedStacktraceBuilder::AddFrame(const Function& func,
89 const Code& code,
90 const Smi& offset) {
91 if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) {
92 // The number of frames is overflowing the preallocated stack trace object.
93 Function& frame_func = Function::Handle();
94 Code& frame_code = Code::Handle();
95 Smi& frame_offset = Smi::Handle();
96 intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1);
97 intptr_t null_slot = start - 2;
98 // Add an empty slot to indicate the overflow so that the toString
99 // method can account for the overflow.
100 if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) {
101 stacktrace_.SetFunctionAtFrame(null_slot, frame_func);
102 stacktrace_.SetCodeAtFrame(null_slot, frame_code);
103 }
104 // Move frames one slot down so that we can accomadate the new frame.
105 for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) {
hausner 2013/02/25 23:09:08 You could implement the top N slots as a circular
siva 2013/02/26 18:49:48 True. Will consider that as an optimization for an
106 intptr_t prev = (i - 1);
107 frame_func = stacktrace_.FunctionAtFrame(i);
108 frame_code = stacktrace_.CodeAtFrame(i);
109 frame_offset = stacktrace_.PcOffsetAtFrame(i);
110 stacktrace_.SetFunctionAtFrame(prev, frame_func);
111 stacktrace_.SetCodeAtFrame(prev, frame_code);
112 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset);
113 }
114 cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1);
115 }
116 stacktrace_.SetFunctionAtFrame(cur_index_, func);
117 stacktrace_.SetCodeAtFrame(cur_index_, code);
118 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset);
119 cur_index_ += 1;
120 }
121
122
29 static bool ShouldShowFunction(const Function& function) { 123 static bool ShouldShowFunction(const Function& function) {
30 if (FLAG_verbose_stacktrace) { 124 if (FLAG_verbose_stacktrace) {
31 return true; 125 return true;
32 } 126 }
33 return function.is_visible(); 127 return function.is_visible();
34 } 128 }
35 129
36 130
37 // Iterate through the stack frames and try to find a frame with an 131 // Iterate through the stack frames and try to find a frame with an
38 // exception handler. Once found, set the pc, sp and fp so that execution 132 // exception handler. Once found, set the pc, sp and fp so that execution
39 // can continue in that frame. 133 // can continue in that frame.
40 static bool FindExceptionHandler(uword* handler_pc, 134 static bool FindExceptionHandler(uword* handler_pc,
41 uword* handler_sp, 135 uword* handler_sp,
42 uword* handler_fp, 136 uword* handler_fp,
43 const GrowableObjectArray& func_list, 137 StacktraceBuilder* builder) {
44 const GrowableObjectArray& code_list,
45 const GrowableObjectArray& pc_offset_list) {
46 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); 138 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
47 StackFrame* frame = frames.NextFrame(); 139 StackFrame* frame = frames.NextFrame();
48 ASSERT(frame != NULL); // We expect to find a dart invocation frame. 140 ASSERT(frame != NULL); // We expect to find a dart invocation frame.
49 Function& func = Function::Handle(); 141 Function& func = Function::Handle();
50 Code& code = Code::Handle(); 142 Code& code = Code::Handle();
51 Smi& offset = Smi::Handle(); 143 Smi& offset = Smi::Handle();
52 while (!frame->IsEntryFrame()) { 144 while (!frame->IsEntryFrame()) {
53 if (frame->IsDartFrame()) { 145 if (frame->IsDartFrame()) {
54 code = frame->LookupDartCode(); 146 code = frame->LookupDartCode();
55 if (code.is_optimized()) { 147 if (code.is_optimized()) {
56 // For optimized frames, extract all the inlined functions if any 148 // For optimized frames, extract all the inlined functions if any
57 // into the stack trace. 149 // into the stack trace.
58 for (InlinedFunctionsIterator it(frame); !it.Done(); it.Advance()) { 150 for (InlinedFunctionsIterator it(frame); !it.Done(); it.Advance()) {
59 func = it.function(); 151 func = it.function();
60 code = it.code(); 152 code = it.code();
61 uword pc = it.pc(); 153 uword pc = it.pc();
62 ASSERT(pc != 0); 154 ASSERT(pc != 0);
63 ASSERT(code.EntryPoint() <= pc); 155 ASSERT(code.EntryPoint() <= pc);
64 ASSERT(pc < (code.EntryPoint() + code.Size())); 156 ASSERT(pc < (code.EntryPoint() + code.Size()));
65 if (ShouldShowFunction(func)) { 157 if (ShouldShowFunction(func)) {
66 offset = Smi::New(pc - code.EntryPoint()); 158 offset = Smi::New(pc - code.EntryPoint());
67 func_list.Add(func); 159 builder->AddFrame(func, code, offset);
68 code_list.Add(code);
69 pc_offset_list.Add(offset);
70 } 160 }
71 } 161 }
72 } else { 162 } else {
73 offset = Smi::New(frame->pc() - code.EntryPoint()); 163 offset = Smi::New(frame->pc() - code.EntryPoint());
74 func = code.function(); 164 func = code.function();
75 if (ShouldShowFunction(func)) { 165 if (ShouldShowFunction(func)) {
76 func_list.Add(func); 166 builder->AddFrame(func, code, offset);
77 code_list.Add(code);
78 pc_offset_list.Add(offset);
79 } 167 }
80 } 168 }
81 if (frame->FindExceptionHandler(handler_pc)) { 169 if (frame->FindExceptionHandler(handler_pc)) {
82 *handler_sp = frame->sp(); 170 *handler_sp = frame->sp();
83 *handler_fp = frame->fp(); 171 *handler_fp = frame->fp();
84 return true; 172 return true;
85 } 173 }
86 } 174 }
87 frame = frames.NextFrame(); 175 frame = frames.NextFrame();
88 ASSERT(frame != NULL); 176 ASSERT(frame != NULL);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 typedef void (*ErrorHandler)(uword, uword, uword, RawError*); 252 typedef void (*ErrorHandler)(uword, uword, uword, RawError*);
165 ErrorHandler func = reinterpret_cast<ErrorHandler>( 253 ErrorHandler func = reinterpret_cast<ErrorHandler>(
166 StubCode::JumpToErrorHandlerEntryPoint()); 254 StubCode::JumpToErrorHandlerEntryPoint());
167 func(program_counter, stack_pointer, frame_pointer, raw_error); 255 func(program_counter, stack_pointer, frame_pointer, raw_error);
168 UNREACHABLE(); 256 UNREACHABLE();
169 } 257 }
170 258
171 259
172 static void ThrowExceptionHelper(const Instance& incoming_exception, 260 static void ThrowExceptionHelper(const Instance& incoming_exception,
173 const Instance& existing_stacktrace) { 261 const Instance& existing_stacktrace) {
174 Instance& exception = Instance::Handle(incoming_exception.raw()); 262 bool use_preallocated_stacktrace = false;
263 Isolate* isolate = Isolate::Current();
264 Instance& exception = Instance::Handle(isolate, incoming_exception.raw());
175 if (exception.IsNull()) { 265 if (exception.IsNull()) {
176 exception ^= Exceptions::Create(Exceptions::kNullThrown, 266 exception ^= Exceptions::Create(Exceptions::kNullThrown,
177 Object::empty_array()); 267 Object::empty_array());
268 } else if (exception.raw() == isolate->object_store()->out_of_memory() ||
269 exception.raw() == isolate->object_store()->stack_overflow()) {
270 use_preallocated_stacktrace = true;
178 } 271 }
179 uword handler_pc = 0; 272 uword handler_pc = 0;
180 uword handler_sp = 0; 273 uword handler_sp = 0;
181 uword handler_fp = 0; 274 uword handler_fp = 0;
182 const GrowableObjectArray& func_list = 275 Stacktrace& stacktrace = Stacktrace::Handle(isolate);
183 GrowableObjectArray::Handle(GrowableObjectArray::New()); 276 bool handler_exists = false;
184 const GrowableObjectArray& code_list = 277 if (use_preallocated_stacktrace) {
185 GrowableObjectArray::Handle(GrowableObjectArray::New()); 278 stacktrace ^= isolate->object_store()->preallocated_stack_trace();
186 const GrowableObjectArray& pc_offset_list = 279 PreallocatedStacktraceBuilder frame_builder(stacktrace);
187 GrowableObjectArray::Handle(GrowableObjectArray::New()); 280 handler_exists = FindExceptionHandler(&handler_pc,
188 bool handler_exists = FindExceptionHandler(&handler_pc, 281 &handler_sp,
189 &handler_sp, 282 &handler_fp,
190 &handler_fp, 283 &frame_builder);
191 func_list, 284 } else {
192 code_list, 285 RegularStacktraceBuilder frame_builder(
193 pc_offset_list); 286 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()),
287 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()),
288 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()));
289 handler_exists = FindExceptionHandler(&handler_pc,
290 &handler_sp,
291 &handler_fp,
292 &frame_builder);
293 // TODO(5411263): At some point we can optimize by figuring out if a
294 // stack trace is needed based on whether the catch code specifies a
295 // stack trace object or there is a rethrow in the catch clause.
296 if (frame_builder.pc_offset_list().Length() != 0) {
297 // Create arrays for function, code and pc_offset triplet for each frame.
298 const Array& func_array =
299 Array::Handle(isolate, Array::MakeArray(frame_builder.func_list()));
300 const Array& code_array =
301 Array::Handle(isolate, Array::MakeArray(frame_builder.code_list()));
302 const Array& pc_offset_array =
303 Array::Handle(isolate,
304 Array::MakeArray(frame_builder.pc_offset_list()));
305 if (existing_stacktrace.IsNull()) {
306 stacktrace = Stacktrace::New(func_array, code_array, pc_offset_array);
307 } else {
308 stacktrace ^= existing_stacktrace.raw();
309 stacktrace.Append(func_array, code_array, pc_offset_array);
310 }
311 } else {
312 stacktrace ^= existing_stacktrace.raw();
313 }
314 }
194 // We expect to find a handler_pc, if the exception is unhandled 315 // We expect to find a handler_pc, if the exception is unhandled
195 // then we expect to at least have the dart entry frame on the 316 // then we expect to at least have the dart entry frame on the
196 // stack as Exceptions::Throw should happen only after a dart 317 // stack as Exceptions::Throw should happen only after a dart
197 // invocation has been done. 318 // invocation has been done.
198 ASSERT(handler_pc != 0); 319 ASSERT(handler_pc != 0);
199 320
200 // TODO(5411263): At some point we can optimize by figuring out if a
201 // stack trace is needed based on whether the catch code specifies a
202 // stack trace object or there is a rethrow in the catch clause.
203 Stacktrace& stacktrace = Stacktrace::Handle();
204 if (pc_offset_list.Length() != 0) {
205 if (existing_stacktrace.IsNull()) {
206 stacktrace = Stacktrace::New(func_list, code_list, pc_offset_list);
207 } else {
208 stacktrace ^= existing_stacktrace.raw();
209 stacktrace.Append(func_list, code_list, pc_offset_list);
210 }
211 } else {
212 stacktrace ^= existing_stacktrace.raw();
213 }
214 if (FLAG_print_stacktrace_at_throw) { 321 if (FLAG_print_stacktrace_at_throw) {
215 OS::Print("Exception '%s' thrown:\n", exception.ToCString()); 322 OS::Print("Exception '%s' thrown:\n", exception.ToCString());
216 OS::Print("%s\n", stacktrace.ToCString()); 323 OS::Print("%s\n", stacktrace.ToCString());
217 } 324 }
218 if (handler_exists) { 325 if (handler_exists) {
219 // Found a dart handler for the exception, jump to it. 326 // Found a dart handler for the exception, jump to it.
220 JumpToExceptionHandler(handler_pc, 327 JumpToExceptionHandler(handler_pc,
221 handler_sp, 328 handler_sp,
222 handler_fp, 329 handler_fp,
223 exception, 330 exception,
224 stacktrace); 331 stacktrace);
225 } else { 332 } else {
226 if (FLAG_heap_profile_out_of_memory) { 333 if (FLAG_heap_profile_out_of_memory) {
227 Isolate* isolate = Isolate::Current();
228 if (exception.raw() == isolate->object_store()->out_of_memory()) { 334 if (exception.raw() == isolate->object_store()->out_of_memory()) {
229 isolate->heap()->ProfileToFile("out-of-memory"); 335 isolate->heap()->ProfileToFile("out-of-memory");
230 } 336 }
231 } 337 }
232 // No dart exception handler found in this invocation sequence, 338 // No dart exception handler found in this invocation sequence,
233 // so we create an unhandled exception object and return to the 339 // so we create an unhandled exception object and return to the
234 // invocation stub so that it returns this unhandled exception 340 // invocation stub so that it returns this unhandled exception
235 // object. The C++ code which invoked this dart sequence can check 341 // object. The C++ code which invoked this dart sequence can check
236 // and do the appropriate thing (rethrow the exception to the 342 // and do the appropriate thing (rethrow the exception to the
237 // dart invocation sequence above it, print diagnostics and terminate 343 // dart invocation sequence above it, print diagnostics and terminate
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 break; 586 break;
481 } 587 }
482 588
483 return DartLibraryCalls::ExceptionCreate(library, 589 return DartLibraryCalls::ExceptionCreate(library,
484 *class_name, 590 *class_name,
485 *constructor_name, 591 *constructor_name,
486 arguments); 592 arguments);
487 } 593 }
488 594
489 } // namespace dart 595 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | runtime/vm/raw_object_snapshot.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698