History

Change assert to exception if a dis module contains an invalid magic number. Broken threads now terminate the VM using the default scheduler. Tools can not get a callback for broken threads.

arr committed 10 years ago

Commit 096b0c71 parent 9c1abd69 files · +74 −28Browse files

Unified · Split

9 files
  1. src/exec/debugger.cpp +1 −1
  2. src/include/exceptions.h +12 −0
  3. src/include/runtime.h +7 −2
  4. src/include/vm_tools.h +1 −0
  5. src/vm/module_reader.cpp +5 −3
  6. src/vm/scheduler.cpp +10 −3
  7. src/vm/scheduler.h +0 −2
  8. src/vm/thread.cpp +33 −16
  9. src/vm/tool_dispatch.cpp +5 −1
src/exec/debugger.cpp+1−1
@@ -304,7 +304,7 @@ namespace · 303 unmodified lines
304304
305305 void cmd_term(const std::vector<std::string> &, dbg_cmd_cxt_t &)
306306 {
307− throw vm_user_exception{ "Debugger signaled VM termination" };
307+ throw vm_term_request{};
308308 }
309309
310310 void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
src/include/exceptions.h+12−0
@@ -128,6 +128,18 @@ namespace disvm · 127 unmodified lines
128128 const char *module_name;
129129 const vm_pc_t program_counter;
130130 };
131+
132+ class vm_term_request final : public vm_user_exception
133+ {
134+ public:
135+ explicit vm_term_request()
136+ : vm_user_exception("VM termination requested")
137+ { }
138+
139+ explicit vm_term_request(const char *msg)
140+ : vm_user_exception(msg)
141+ { }
142+ };
131143 }
132144 }
133145
src/include/runtime.h+7−2
@@ -717,7 +717,7 @@ namespace disvm · 716 unmodified lines
717717 exiting, // exit instruction
718718 empty_stack,
719719
720− broken, // thread crashed
720+ broken, // thread crashed - the scheduler is free to terminate the entire VM if any thread enters this state.
721721 };
722722
723723 // Forward declaration
@@ -787,6 +787,10 @@ namespace disvm · 63 unmodified lines
787787
788788 vm_thread_state_t get_state() const;
789789
790+ // This function will only return a non-null
791+ // value if this thread is in the broken state.
792+ const char *get_error_message() const;
793+
790794 uint32_t get_thread_id() const;
791795
792796 uint32_t get_parent_thread_id() const;
@@ -794,9 +798,10 @@ namespace disvm · 1 unmodified line
794798 const vm_registers_t& get_registers() const;
795799
796800 private:
801+ vm_registers_t _registers;
797802 const uint32_t _thread_id;
798803 const uint32_t _parent_thread_id;
799− vm_registers_t _registers;
804+ char *_error_message;
800805 };
801806
802807 //
src/include/vm_tools.h+1−0
@@ -49,6 +49,7 @@ namespace disvm · 48 unmodified lines
4949
5050 thread_begin, // value1: const vm_thread_t
5151 thread_end, // value1: const vm_thread_t
52+ thread_broken, // value1: const vm_thread_t
5253
5354 exception_raised, // value1: vm_registers_t
5455 // value2: const vm_string_t - exception ID
src/vm/module_reader.cpp+5−3
@@ -216,8 +216,6 @@ namespace · 215 unmodified lines
216216 if (!success)
217217 throw module_reader_exception{ "Failed to read magic number" };
218218
219− assert(header.magic_number == magic_number_constants::xmagic || header.magic_number == magic_number_constants::smagic);
220−
221219 // If the object file is signed, read in the signature.
222220 if (header.magic_number == magic_number_constants::smagic)
223221 {
@@ -228,10 +226,14 @@ namespace · 4 unmodified lines
228226 const auto bytesRead = reader.get_next_bytes(header.Signature.length, header.Signature.signature.get());
229227 if (bytesRead != header.Signature.length) throw module_reader_exception{ "Failed to read full signature" };
230228 }
231− else
229+ else if (header.magic_number == magic_number_constants::xmagic)
232230 {
233231 header.Signature.length = word_t{ 0 };
234232 }
233+ else
234+ {
235+ throw module_reader_exception{ "Invalid magic number in module" };
236+ }
235237
236238 auto runtime_flags = operand_t{};
237239 std::tie(success, runtime_flags) = read_next_operand(reader);
src/vm/scheduler.cpp+10−3
@@ -46,6 +46,13 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 45 unmodified lines
4646 current_thread->vm_thread->execute(instance._vm, instance._vm_thread_quanta);
4747 }
4848 }
49+ catch (const vm_term_request &te)
50+ {
51+ std::cerr << te.what() << std::endl;
52+
53+ instance._terminating = true;
54+ instance._worker_event.notify_all();
55+ }
4956 catch (const vm_system_exception &se)
5057 {
5158 std::stringstream err_msg;
@@ -428,12 +435,12 @@ bool default_scheduler_t::enqueue_thread_unsafe(std::shared_ptr<thread_instance_ · 376 unmodified lines
428435
429436 case vm_thread_state_t::broken:
430437 {
431− _non_runnable_vm_thread_ids.push_front(thread_id);
432−
433438 if (debug::is_component_tracing_enabled<debug::component_trace_t::scheduler>())
434439 debug::log_msg(debug::component_trace_t::scheduler, debug::log_level_t::debug, "scheduler: broken: %d\n", thread_id);
435440
436− break;
441+ auto err_msg = thread_instance->vm_thread->get_error_message();
442+ assert(err_msg != nullptr);
443+ throw vm_term_request{ err_msg };
437444 }
438445
439446 case vm_thread_state_t::release:
src/vm/scheduler.h+0−2
@@ -13,7 +13,6 @@ · 12 unmodified lines
1313 #include <condition_variable>
1414 #include <vector>
1515 #include <deque>
16−#include <forward_list>
1716 #include <unordered_set>
1817 #include <unordered_map>
1918 #include <atomic>
@@ -96,7 +95,6 @@ namespace disvm · 76 unmodified lines
9695 std::size_t _gc_counter;
9796
9897 std::unordered_set<uint32_t> _blocked_vm_thread_ids;
99− std::forward_list<uint32_t> _non_runnable_vm_thread_ids;
10098
10199 using all_thread_map_t = std::unordered_map<uint32_t, std::shared_ptr<thread_instance_t>>;
102100 all_thread_map_t _all_vm_threads;
src/vm/thread.cpp+33−16
@@ -111,6 +111,7 @@ vm_thread_t::vm_thread_t( · 110 unmodified lines
111111 vm_module_ref_t &entry,
112112 uint32_t parent_thread_id)
113113 : vm_alloc_t(vm_thread_t::type_desc())
114+ , _error_message{ nullptr }
114115 , _parent_thread_id{ parent_thread_id }
115116 , _registers{ *this, entry }
116117 , _thread_id{ get_unique_thread_id() }
@@ -135,6 +136,7 @@ vm_thread_t::vm_thread_t( · 18 unmodified lines
135136 const vm_frame_t &initial_frame,
136137 vm_pc_t start_pc)
137138 : vm_alloc_t(vm_thread_t::type_desc())
139+ , _error_message{ nullptr }
138140 , _parent_thread_id{ parent_thread_id }
139141 , _registers{ *this, entry }
140142 , _thread_id{ get_unique_thread_id() }
@@ -162,6 +164,9 @@ vm_thread_t::~vm_thread_t() · 21 unmodified lines
162164 {
163165 if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>())
164166 debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);
167+
168+ free_memory(_error_message);
169+ debug::assign_debug_pointer(&_error_message);
165170 }
166171
167172 namespace
@@ -214,6 +219,7 @@ namespace · 46 unmodified lines
214219
215220 vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta)
216221 {
222+ const auto max_error_message = std::size_t{ 1024 };
217223 _registers.current_thread_state = vm_thread_state_t::running;
218224 _registers.current_thread_quanta = quanta;
219225 assert(_registers.pc != runtime_constants::invalid_program_counter);
@@ -226,27 +232,27 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 6 unmodified lines
226232 else
227233 execute_impl<execute_with_tool_t>(_registers, vm);
228234 }
235+ catch (const vm_term_request &)
236+ {
237+ throw;
238+ }
229239 catch (const unhandled_user_exception &uue)
230240 {
231− // [TODO] Store the exception
232− std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);
241+ _error_message = calloc_memory<char>(max_error_message);
242+ std::snprintf(_error_message, max_error_message, "%s - '%s' in %s at instruction %d", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);
233243 _registers.current_thread_state = vm_thread_state_t::broken;
234− if (tool_dispatch != nullptr)
235− tool_dispatch->on_thread_broken(*this);
236244 }
237245 catch (const index_out_of_range_memory &ioor)
238246 {
239− std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);
247+ _error_message = calloc_memory<char>(max_error_message);
248+ std::snprintf(_error_message, max_error_message, "%s - %d [%d,%d]", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);
240249 _registers.current_thread_state = vm_thread_state_t::broken;
241− if (tool_dispatch != nullptr)
242− tool_dispatch->on_thread_broken(*this);
243250 }
244251 catch (const vm_user_exception &ue)
245252 {
246− std::fprintf(stderr, "%s\n", ue.what());
253+ _error_message = calloc_memory<char>(max_error_message);
254+ std::snprintf(_error_message, max_error_message, "%s", ue.what());
247255 _registers.current_thread_state = vm_thread_state_t::broken;
248− if (tool_dispatch != nullptr)
249− tool_dispatch->on_thread_broken(*this);
250256 }
251257
252258 // Log the execution result
@@ -262,16 +268,22 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 9 unmodified lines
262268 _registers.current_thread_state);
263269 }
264270
265− // If the thread is still in the running state transition it back to its entry state.
266− if (_registers.current_thread_state == vm_thread_state_t::running)
271+ switch (_registers.current_thread_state)
267272 {
273+ case vm_thread_state_t::running:
268274 _registers.current_thread_state = (tool_dispatch == nullptr) ? vm_thread_state_t::ready : vm_thread_state_t::debug;
269− }
270− else if (vm_thread_state_t::exiting == _registers.current_thread_state
271− || vm_thread_state_t::empty_stack == _registers.current_thread_state)
272− {
275+ break;
276+
277+ case vm_thread_state_t::empty_stack:
278+ case vm_thread_state_t::exiting:
273279 if (tool_dispatch != nullptr)
274280 tool_dispatch->on_thread_end(*this);
281+ break;
282+
283+ case vm_thread_state_t::broken:
284+ if (tool_dispatch != nullptr)
285+ tool_dispatch->on_thread_broken(*this);
286+ break;
275287 }
276288
277289 return _registers.current_thread_state;
@@ -288,6 +300,11 @@ vm_thread_state_t vm_thread_t::get_state() const · 10 unmodified lines
288300 return _registers.current_thread_state;
289301 }
290302
303+const char *vm_thread_t::get_error_message() const
304+{
305+ return _error_message;
306+}
307+
291308 uint32_t vm_thread_t::get_thread_id() const
292309 {
293310 return _thread_id;
src/vm/tool_dispatch.cpp+5−1
@@ -164,8 +164,12 @@ void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) · 163 unmodified lines
164164 _events.fire_event_callbacks(vm_event_t::thread_end, cxt);
165165 }
166166
167−void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &)
167+void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &t)
168168 {
169+ vm_event_context_t cxt{};
170+ cxt.value1.thread = &t;
171+
172+ _events.fire_event_callbacks(vm_event_t::thread_broken, cxt);
169173 }
170174
171175 void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id)