|
15 | 15 | #include "vm/dart_api_message.h"
|
16 | 16 | #include "vm/dart_entry.h"
|
17 | 17 | #include "vm/exceptions.h"
|
| 18 | +#include "vm/hash_table.h" |
18 | 19 | #include "vm/lockers.h"
|
19 | 20 | #include "vm/longjump.h"
|
20 | 21 | #include "vm/message_handler.h"
|
@@ -108,6 +109,153 @@ DEFINE_NATIVE_ENTRY(SendPortImpl_sendInternal_, 0, 2) {
|
108 | 109 | return Object::null();
|
109 | 110 | }
|
110 | 111 |
|
| 112 | +class RawObjectPtrSetTraits { |
| 113 | + public: |
| 114 | + static bool ReportStats() { return false; } |
| 115 | + static const char* Name() { return "RawObjectPtrSetTraits"; } |
| 116 | + |
| 117 | + static bool IsMatch(const RawObject* a, const RawObject* b) { return a == b; } |
| 118 | + |
| 119 | + static uword Hash(const RawObject* obj) { |
| 120 | + return reinterpret_cast<uword>(obj); |
| 121 | + } |
| 122 | +}; |
| 123 | + |
| 124 | +static RawObject* ValidateMessageObject(Zone* zone, |
| 125 | + Isolate* isolate, |
| 126 | + const Object& obj) { |
| 127 | + TIMELINE_DURATION(Thread::Current(), Isolate, "ValidateMessageObject"); |
| 128 | + |
| 129 | + class SendMessageValidator : public ObjectPointerVisitor { |
| 130 | + public: |
| 131 | + SendMessageValidator(IsolateGroup* isolate_group, |
| 132 | + WeakTable* visited, |
| 133 | + MallocGrowableArray<RawObject*>* const working_set) |
| 134 | + : ObjectPointerVisitor(isolate_group), |
| 135 | + visited_(visited), |
| 136 | + working_set_(working_set) {} |
| 137 | + |
| 138 | + private: |
| 139 | + void VisitPointers(RawObject** from, RawObject** to) { |
| 140 | + for (RawObject** raw = from; raw <= to; raw++) { |
| 141 | + if (!(*raw)->IsHeapObject() || (*raw)->IsCanonical()) { |
| 142 | + continue; |
| 143 | + } |
| 144 | + if (visited_->GetValueExclusive(*raw) == 1) { |
| 145 | + continue; |
| 146 | + } |
| 147 | + visited_->SetValueExclusive(*raw, 1); |
| 148 | + working_set_->Add(*raw); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + WeakTable* visited_; |
| 153 | + MallocGrowableArray<RawObject*>* const working_set_; |
| 154 | + }; |
| 155 | + if (!obj.raw()->IsHeapObject() || obj.raw()->IsCanonical()) { |
| 156 | + return obj.raw(); |
| 157 | + } |
| 158 | + ClassTable* class_table = isolate->class_table(); |
| 159 | + |
| 160 | + Class& klass = Class::Handle(zone); |
| 161 | + Closure& closure = Closure::Handle(zone); |
| 162 | + |
| 163 | + MallocGrowableArray<RawObject*> working_set; |
| 164 | + std::unique_ptr<WeakTable> visited(new WeakTable()); |
| 165 | + |
| 166 | + NoSafepointScope no_safepoint; |
| 167 | + SendMessageValidator visitor(isolate->group(), visited.get(), &working_set); |
| 168 | + |
| 169 | + visited->SetValueExclusive(obj.raw(), 1); |
| 170 | + working_set.Add(obj.raw()); |
| 171 | + |
| 172 | + while (!working_set.is_empty()) { |
| 173 | + RawObject* raw = working_set.RemoveLast(); |
| 174 | + |
| 175 | + if (visited->GetValueExclusive(raw) > 0) { |
| 176 | + continue; |
| 177 | + } |
| 178 | + visited->SetValueExclusive(raw, 1); |
| 179 | + |
| 180 | + const intptr_t cid = raw->GetClassId(); |
| 181 | + switch (cid) { |
| 182 | + // List below matches the one in raw_object_snapshot.cc |
| 183 | +#define MESSAGE_SNAPSHOT_ILLEGAL(type) \ |
| 184 | + return Exceptions::CreateUnhandledException( \ |
| 185 | + zone, Exceptions::kArgumentValue, \ |
| 186 | + "Illegal argument in isolate message : (object is a " #type ")"); \ |
| 187 | + break; |
| 188 | + |
| 189 | + MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary); |
| 190 | + MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference); |
| 191 | + MESSAGE_SNAPSHOT_ILLEGAL(Pointer); |
| 192 | + MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort); |
| 193 | + MESSAGE_SNAPSHOT_ILLEGAL(RegExp); |
| 194 | + MESSAGE_SNAPSHOT_ILLEGAL(StackTrace); |
| 195 | + MESSAGE_SNAPSHOT_ILLEGAL(UserTag); |
| 196 | + |
| 197 | + case kClosureCid: { |
| 198 | + closure = Closure::RawCast(raw); |
| 199 | + RawFunction* func = closure.function(); |
| 200 | + // We only allow closure of top level methods or static functions in a |
| 201 | + // class to be sent in isolate messages. |
| 202 | + if (!Function::IsImplicitStaticClosureFunction(func)) { |
| 203 | + return Exceptions::CreateUnhandledException( |
| 204 | + zone, Exceptions::kArgumentValue, "Closures are not allowed"); |
| 205 | + } |
| 206 | + break; |
| 207 | + } |
| 208 | + default: |
| 209 | + if (cid >= kNumPredefinedCids) { |
| 210 | + klass = class_table->At(cid); |
| 211 | + if (klass.num_native_fields() != 0) { |
| 212 | + return Exceptions::CreateUnhandledException( |
| 213 | + zone, Exceptions::kArgumentValue, |
| 214 | + "Objects that extend NativeWrapper are not allowed"); |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | + raw->VisitPointers(&visitor); |
| 219 | + } |
| 220 | + isolate->set_forward_table_new(nullptr); |
| 221 | + return obj.raw(); |
| 222 | +} |
| 223 | + |
| 224 | +DEFINE_NATIVE_ENTRY(SendPortImpl_sendAndExitInternal_, 0, 2) { |
| 225 | + GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0)); |
| 226 | + if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) { |
| 227 | + const auto& error = |
| 228 | + String::Handle(String::New("sendAndExit is only supported across " |
| 229 | + "isolates spawned via spawnFunction.")); |
| 230 | + Exceptions::ThrowArgumentError(error); |
| 231 | + UNREACHABLE(); |
| 232 | + } |
| 233 | + |
| 234 | + GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1)); |
| 235 | + |
| 236 | + Object& validated_result = Object::Handle(zone); |
| 237 | + Object& msg_obj = Object::Handle(zone, obj.raw()); |
| 238 | + validated_result = ValidateMessageObject(zone, isolate, msg_obj); |
| 239 | + if (validated_result.IsUnhandledException()) { |
| 240 | + Exceptions::PropagateError(Error::Cast(validated_result)); |
| 241 | + UNREACHABLE(); |
| 242 | + } |
| 243 | + PersistentHandle* handle = |
| 244 | + isolate->group()->api_state()->AllocatePersistentHandle(); |
| 245 | + handle->set_raw(msg_obj); |
| 246 | + isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id()))); |
| 247 | + // TODO(aam): Ensure there are no dart api calls after this point as we want |
| 248 | + // to ensure that validated message won't get tampered with. |
| 249 | + Isolate::KillIfExists(isolate, Isolate::LibMsgId::kKillMsg); |
| 250 | + // Drain interrupts before running so any IMMEDIATE operations on the current |
| 251 | + // isolate happen synchronously. |
| 252 | + const Error& error = Error::Handle(thread->HandleInterrupts()); |
| 253 | + RELEASE_ASSERT(error.IsUnwindError()); |
| 254 | + Exceptions::PropagateError(error); |
| 255 | + // We will never execute dart code again in this isolate. |
| 256 | + return Object::null(); |
| 257 | +} |
| 258 | + |
111 | 259 | static void ThrowIsolateSpawnException(const String& message) {
|
112 | 260 | const Array& args = Array::Handle(Array::New(1));
|
113 | 261 | args.SetAt(0, message);
|
|
0 commit comments