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