1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ppapi/proxy/serialized_var.h" 6 7#include "base/logging.h" 8#include "ipc/ipc_message_utils.h" 9#include "ppapi/c/pp_instance.h" 10#include "ppapi/proxy/dispatcher.h" 11#include "ppapi/proxy/interface_proxy.h" 12#include "ppapi/proxy/ppapi_param_traits.h" 13#include "ppapi/proxy/ppb_buffer_proxy.h" 14#include "ppapi/shared_impl/ppapi_globals.h" 15#include "ppapi/shared_impl/var.h" 16#include "ppapi/thunk/enter.h" 17 18namespace ppapi { 19namespace proxy { 20 21namespace { 22void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { 23 IPC::ParamTraits<SerializedHandle>::Write(m, handle); 24} 25} // namespace 26 27// SerializedVar::Inner -------------------------------------------------------- 28 29SerializedVar::Inner::Inner() 30 : serialization_rules_(NULL), 31 var_(PP_MakeUndefined()), 32 instance_(0), 33 cleanup_mode_(CLEANUP_NONE), 34 is_valid_var_(true) { 35#ifndef NDEBUG 36 has_been_serialized_ = false; 37 has_been_deserialized_ = false; 38#endif 39} 40 41SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) 42 : serialization_rules_(serialization_rules), 43 var_(PP_MakeUndefined()), 44 instance_(0), 45 cleanup_mode_(CLEANUP_NONE) { 46#ifndef NDEBUG 47 has_been_serialized_ = false; 48 has_been_deserialized_ = false; 49#endif 50} 51 52SerializedVar::Inner::~Inner() { 53 switch (cleanup_mode_) { 54 case END_SEND_PASS_REF: 55 serialization_rules_->EndSendPassRef(var_); 56 break; 57 case END_RECEIVE_CALLER_OWNED: 58 serialization_rules_->EndReceiveCallerOwned(var_); 59 break; 60 default: 61 break; 62 } 63} 64 65PP_Var SerializedVar::Inner::GetVar() { 66 DCHECK(serialization_rules_.get()); 67 68#if defined(NACL_WIN64) 69 NOTREACHED(); 70 return PP_MakeUndefined(); 71#else 72 if (raw_var_data_.get()) { 73 var_ = raw_var_data_->CreatePPVar(instance_); 74 raw_var_data_.reset(NULL); 75 } 76 77 return var_; 78#endif 79} 80 81void SerializedVar::Inner::SetVar(PP_Var var) { 82 // Sanity check, when updating the var we should have received a 83 // serialization rules pointer already. 84 DCHECK(serialization_rules_.get()); 85 var_ = var; 86 raw_var_data_.reset(NULL); 87} 88 89void SerializedVar::Inner::SetInstance(PP_Instance instance) { 90 instance_ = instance; 91} 92 93void SerializedVar::Inner::ForceSetVarValueForTest(PP_Var value) { 94 var_ = value; 95 raw_var_data_.reset(NULL); 96} 97 98void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { 99 // When writing to the IPC messages, a serialization rules handler should 100 // always have been set. 101 // 102 // When sending a message, it should be difficult to trigger this if you're 103 // using the SerializedVarSendInput class and giving a non-NULL dispatcher. 104 // Make sure you're using the proper "Send" helper class. 105 // 106 // It should be more common to see this when handling an incoming message 107 // that returns a var. This means the message handler didn't write to the 108 // output parameter, or possibly you used the wrong helper class 109 // (normally SerializedVarReturnValue). 110 DCHECK(serialization_rules_.get()); 111 112#ifndef NDEBUG 113 // We should only be serializing something once. 114 DCHECK(!has_been_serialized_); 115 has_been_serialized_ = true; 116#endif 117 scoped_ptr<RawVarDataGraph> data = RawVarDataGraph::Create(var_, instance_); 118 if (data) { 119 m->WriteBool(true); // Success. 120 data->Write(m, base::Bind(&DefaultHandleWriter)); 121 } else { 122 m->WriteBool(false); // Failure. 123 } 124} 125 126void SerializedVar::Inner::WriteDataToMessage( 127 IPC::Message* m, 128 const HandleWriter& handle_writer) const { 129 if (raw_var_data_) { 130 m->WriteBool(true); // Success. 131 raw_var_data_->Write(m, handle_writer); 132 } else { 133 m->WriteBool(false); // Failure. 134 } 135} 136 137bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, 138 PickleIterator* iter) { 139#ifndef NDEBUG 140 // We should only deserialize something once or will end up with leaked 141 // references. 142 // 143 // One place this has happened in the past is using 144 // std::vector<SerializedVar>.resize(). If you're doing this manually instead 145 // of using the helper classes for handling in/out vectors of vars, be 146 // sure you use the same pattern as the SerializedVarVector classes. 147 DCHECK(!has_been_deserialized_); 148 has_been_deserialized_ = true; 149#endif 150 // When reading, the dispatcher should be set when we get a Deserialize 151 // call (which will supply a dispatcher). 152 if (!m->ReadBool(iter, &is_valid_var_)) 153 return false; 154 if (is_valid_var_) { 155 raw_var_data_ = RawVarDataGraph::Read(m, iter); 156 if (!raw_var_data_) 157 return false; 158 } 159 160 return true; 161} 162 163void SerializedVar::Inner::SetCleanupModeToEndSendPassRef() { 164 cleanup_mode_ = END_SEND_PASS_REF; 165} 166 167void SerializedVar::Inner::SetCleanupModeToEndReceiveCallerOwned() { 168 cleanup_mode_ = END_RECEIVE_CALLER_OWNED; 169} 170 171// SerializedVar --------------------------------------------------------------- 172 173SerializedVar::SerializedVar() : inner_(new Inner) { 174} 175 176SerializedVar::SerializedVar(VarSerializationRules* serialization_rules) 177 : inner_(new Inner(serialization_rules)) { 178} 179 180SerializedVar::~SerializedVar() { 181} 182 183// SerializedVarSendInput ------------------------------------------------------ 184 185SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher, 186 const PP_Var& var) 187 : SerializedVar(dispatcher->serialization_rules()) { 188 inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned(var)); 189} 190 191// static 192void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, 193 const PP_Var* input, 194 size_t input_count, 195 std::vector<SerializedVar>* output) { 196 output->reserve(input_count); 197 for (size_t i = 0; i < input_count; i++) 198 output->push_back(SerializedVarSendInput(dispatcher, input[i])); 199} 200 201// SerializedVarSendInputShmem ------------------------------------------------- 202 203SerializedVarSendInputShmem::SerializedVarSendInputShmem( 204 Dispatcher* dispatcher, 205 const PP_Var& var, 206 const PP_Instance& instance) 207 : SerializedVar(dispatcher->serialization_rules()) { 208 inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned(var)); 209 inner_->SetInstance(instance); 210} 211 212// ReceiveSerializedVarReturnValue --------------------------------------------- 213 214ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { 215} 216 217ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue( 218 const SerializedVar& serialized) 219 : SerializedVar(serialized) { 220} 221 222PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { 223 inner_->set_serialization_rules(dispatcher->serialization_rules()); 224 inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( 225 inner_->GetVar())); 226 return inner_->GetVar(); 227} 228 229// ReceiveSerializedException -------------------------------------------------- 230 231ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, 232 PP_Var* exception) 233 : SerializedVar(dispatcher->serialization_rules()), 234 exception_(exception) { 235} 236 237ReceiveSerializedException::~ReceiveSerializedException() { 238 if (exception_) { 239 // When an output exception is specified, it will take ownership of the 240 // reference. 241 inner_->SetVar( 242 inner_->serialization_rules()->ReceivePassRef(inner_->GetVar())); 243 *exception_ = inner_->GetVar(); 244 } else { 245 // When no output exception is specified, the browser thinks we have a ref 246 // to an object that we don't want (this will happen only in the plugin 247 // since the browser will always specify an out exception for the plugin to 248 // write into). 249 // 250 // Strings don't need this handling since we can just avoid creating a 251 // Var from the std::string in the first place. 252 if (inner_->GetVar().type == PP_VARTYPE_OBJECT) 253 inner_->serialization_rules()->ReleaseObjectRef(inner_->GetVar()); 254 } 255} 256 257bool ReceiveSerializedException::IsThrown() const { 258 return exception_ && exception_->type != PP_VARTYPE_UNDEFINED; 259} 260 261// ReceiveSerializedVarVectorOutParam ------------------------------------------ 262 263ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam( 264 Dispatcher* dispatcher, 265 uint32_t* output_count, 266 PP_Var** output) 267 : dispatcher_(dispatcher), 268 output_count_(output_count), 269 output_(output) { 270} 271 272ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() { 273 *output_count_ = static_cast<uint32_t>(vector_.size()); 274 if (!vector_.size()) { 275 *output_ = NULL; 276 return; 277 } 278 279 *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var))); 280 for (size_t i = 0; i < vector_.size(); i++) { 281 // Here we just mimic what happens when returning a value. 282 ReceiveSerializedVarReturnValue converted; 283 SerializedVar* serialized = &converted; 284 *serialized = vector_[i]; 285 (*output_)[i] = converted.Return(dispatcher_); 286 } 287} 288 289std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() { 290 return &vector_; 291} 292 293// SerializedVarReceiveInput --------------------------------------------------- 294 295SerializedVarReceiveInput::SerializedVarReceiveInput( 296 const SerializedVar& serialized) 297 : serialized_(serialized) { 298} 299 300SerializedVarReceiveInput::~SerializedVarReceiveInput() { 301} 302 303PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { 304 serialized_.inner_->set_serialization_rules( 305 dispatcher->serialization_rules()); 306 307 // Ensure that when the serialized var goes out of scope it cleans up the 308 // stuff we're making in BeginReceiveCallerOwned. 309 serialized_.inner_->SetCleanupModeToEndReceiveCallerOwned(); 310 311 serialized_.inner_->SetVar( 312 serialized_.inner_->serialization_rules()->BeginReceiveCallerOwned( 313 serialized_.inner_->GetVar())); 314 return serialized_.inner_->GetVar(); 315} 316 317 318PP_Var SerializedVarReceiveInput::GetForInstance(Dispatcher* dispatcher, 319 PP_Instance instance) { 320 serialized_.inner_->SetInstance(instance); 321 return Get(dispatcher); 322} 323 324// SerializedVarVectorReceiveInput --------------------------------------------- 325 326SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( 327 const std::vector<SerializedVar>& serialized) 328 : serialized_(serialized) { 329} 330 331SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { 332 for (size_t i = 0; i < deserialized_.size(); i++) { 333 serialized_[i].inner_->serialization_rules()->EndReceiveCallerOwned( 334 deserialized_[i]); 335 } 336} 337 338PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, 339 uint32_t* array_size) { 340 deserialized_.resize(serialized_.size()); 341 for (size_t i = 0; i < serialized_.size(); i++) { 342 // The vectors must be able to clean themselves up after this call is 343 // torn down. 344 serialized_[i].inner_->set_serialization_rules( 345 dispatcher->serialization_rules()); 346 347 serialized_[i].inner_->SetVar( 348 serialized_[i].inner_->serialization_rules()->BeginReceiveCallerOwned( 349 serialized_[i].inner_->GetVar())); 350 deserialized_[i] = serialized_[i].inner_->GetVar(); 351 } 352 353 *array_size = static_cast<uint32_t>(serialized_.size()); 354 return deserialized_.empty() ? NULL : &deserialized_[0]; 355} 356 357// SerializedVarReturnValue ---------------------------------------------------- 358 359SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) 360 : serialized_(serialized) { 361} 362 363void SerializedVarReturnValue::Return(Dispatcher* dispatcher, 364 const PP_Var& var) { 365 serialized_->inner_->set_serialization_rules( 366 dispatcher->serialization_rules()); 367 368 // Var must clean up after our BeginSendPassRef call. 369 serialized_->inner_->SetCleanupModeToEndSendPassRef(); 370 371 serialized_->inner_->SetVar( 372 dispatcher->serialization_rules()->BeginSendPassRef(var)); 373} 374 375// static 376SerializedVar SerializedVarReturnValue::Convert(Dispatcher* dispatcher, 377 const PP_Var& var) { 378 // Mimic what happens in the normal case. 379 SerializedVar result; 380 SerializedVarReturnValue retvalue(&result); 381 retvalue.Return(dispatcher, var); 382 return result; 383} 384 385// SerializedVarOutParam ------------------------------------------------------- 386 387SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) 388 : serialized_(serialized), 389 writable_var_(PP_MakeUndefined()), 390 dispatcher_(NULL) { 391} 392 393SerializedVarOutParam::~SerializedVarOutParam() { 394 if (serialized_->inner_->serialization_rules()) { 395 // When unset, OutParam wasn't called. We'll just leave the var untouched 396 // in that case. 397 serialized_->inner_->SetVar( 398 serialized_->inner_->serialization_rules()->BeginSendPassRef( 399 writable_var_)); 400 401 // Normally the current object will be created on the stack to wrap a 402 // SerializedVar and won't have a scope around the actual IPC send. So we 403 // need to tell the SerializedVar to do the begin/end send pass ref calls. 404 serialized_->inner_->SetCleanupModeToEndSendPassRef(); 405 } 406} 407 408PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { 409 dispatcher_ = dispatcher; 410 serialized_->inner_->set_serialization_rules( 411 dispatcher->serialization_rules()); 412 return &writable_var_; 413} 414 415// SerializedVarVectorOutParam ------------------------------------------------- 416 417SerializedVarVectorOutParam::SerializedVarVectorOutParam( 418 std::vector<SerializedVar>* serialized) 419 : dispatcher_(NULL), 420 serialized_(serialized), 421 count_(0), 422 array_(NULL) { 423} 424 425SerializedVarVectorOutParam::~SerializedVarVectorOutParam() { 426 DCHECK(dispatcher_); 427 428 // Convert the array written by the pepper code to the serialized structure. 429 // Note we can't use resize here, we have to allocate a new SerializedVar 430 // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read. 431 serialized_->reserve(count_); 432 for (uint32_t i = 0; i < count_; i++) { 433 // Just mimic what we do for regular OutParams. 434 SerializedVar var; 435 SerializedVarOutParam out(&var); 436 *out.OutParam(dispatcher_) = array_[i]; 437 serialized_->push_back(var); 438 } 439 440 // When returning arrays, the pepper code expects the caller to take 441 // ownership of the array. 442 free(array_); 443} 444 445PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) { 446 DCHECK(!dispatcher_); // Should only be called once. 447 dispatcher_ = dispatcher; 448 return &array_; 449} 450 451SerializedVarTestConstructor::SerializedVarTestConstructor( 452 const PP_Var& pod_var) { 453 DCHECK(pod_var.type != PP_VARTYPE_STRING); 454 inner_->ForceSetVarValueForTest(pod_var); 455} 456 457SerializedVarTestConstructor::SerializedVarTestConstructor( 458 const std::string& str) { 459 inner_->ForceSetVarValueForTest(StringVar::StringToPPVar(str)); 460} 461 462SerializedVarTestReader::SerializedVarTestReader(const SerializedVar& var) 463 : SerializedVar(var) { 464} 465 466} // namespace proxy 467} // namespace ppapi 468