summaryrefslogtreecommitdiffstats
path: root/mojo/system
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-24 19:51:27 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-24 19:51:27 +0000
commit0cab1ade2ddf395044c3e4c76c7e51c6a7ff56c6 (patch)
tree2cf15b2f0efa923bc4bac1d5699871a189f69421 /mojo/system
parentdeaf78a624d694fee8a39ffdd478f05194e081c1 (diff)
downloadchromium_src-0cab1ade2ddf395044c3e4c76c7e51c6a7ff56c6.zip
chromium_src-0cab1ade2ddf395044c3e4c76c7e51c6a7ff56c6.tar.gz
chromium_src-0cab1ade2ddf395044c3e4c76c7e51c6a7ff56c6.tar.bz2
Mojo: Change how we handle invalid pointer arguments (at the system layer).
This changes the semantics of the public system API: instead of (attempting) to returning "invalid argument" (e.g., when you pass a null pointer for a required argument), we'll crash/trap/kill you. The reason for this is that it's not really sensible to check pointers up front in the face of threads doing different things (e.g., memory that is valid to read to/write from at the beginning of a call may not be valid later). As such, we wrap "user" pointers in a (new) |UserPointer<>| class, and provide ways of accessing the memory that they refer to. We should never pass around user pointers as plain pointers. (This careful treatment will probably already be needed to properly support NaCl, for example.) Still to do (but this change is already too big): * Update comments (in mojo/public/c/system). * Properly convert the remaining user pointers being passed around as plain pointers. This includes: * Getting rid of |GetPointerUnsafe()| and also the existing |VerifyUserPointer...()| functions. * Changing how we handle the various options structs. * Changing some of the |Dispatcher| interface. * Write tests for |UserPointer<>|, etc. R=darin@chromium.org Review URL: https://codereview.chromium.org/418033005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285350 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/system')
-rw-r--r--mojo/system/core.cc223
-rw-r--r--mojo/system/core.h62
-rw-r--r--mojo/system/core_test_base.cc12
-rw-r--r--mojo/system/core_unittest.cc423
-rw-r--r--mojo/system/entrypoints.cc77
-rw-r--r--mojo/system/mapping_table.cc5
-rw-r--r--mojo/system/mapping_table.h2
-rw-r--r--mojo/system/memory.cc36
-rw-r--r--mojo/system/memory.h270
9 files changed, 790 insertions, 320 deletions
diff --git a/mojo/system/core.cc b/mojo/system/core.cc
index d72198f..49c90db 100644
--- a/mojo/system/core.cc
+++ b/mojo/system/core.cc
@@ -123,34 +123,31 @@ MojoResult Core::Wait(MojoHandle handle,
return WaitManyInternal(&handle, &signals, 1, deadline);
}
-MojoResult Core::WaitMany(const MojoHandle* handles,
- const MojoHandleSignals* signals,
+MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles,
+ UserPointer<const MojoHandleSignals> signals,
uint32_t num_handles,
MojoDeadline deadline) {
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<MojoHandleSignals>(signals, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles < 1)
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxWaitManyNumHandles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
- return WaitManyInternal(handles, signals, num_handles, deadline);
+ UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
+ UserPointer<const MojoHandleSignals>::Reader signals_reader(signals,
+ num_handles);
+ return WaitManyInternal(handles_reader.GetPointer(),
+ signals_reader.GetPointer(), num_handles, deadline);
}
-MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1) {
+MojoResult Core::CreateMessagePipe(
+ UserPointer<const MojoCreateMessagePipeOptions> options,
+ UserPointer<MojoHandle> message_pipe_handle0,
+ UserPointer<MojoHandle> message_pipe_handle1) {
MojoCreateMessagePipeOptions validated_options = {};
// This will verify the |options| pointer.
MojoResult result = MessagePipeDispatcher::ValidateCreateOptions(
- options, &validated_options);
+ options.GetPointerUnsafe(), &validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<MessagePipeDispatcher> dispatcher0(
new MessagePipeDispatcher(validated_options));
@@ -174,8 +171,8 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
dispatcher0->Init(message_pipe, 0);
dispatcher1->Init(message_pipe, 1);
- *message_pipe_handle0 = handle_pair.first;
- *message_pipe_handle1 = handle_pair.second;
+ message_pipe_handle0.Put(handle_pair.first);
+ message_pipe_handle1.Put(handle_pair.second);
return MOJO_RESULT_OK;
}
@@ -187,9 +184,9 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
// after the the message has been received and a new handle created (and
// possibly even after calls have been made on the new handle).
MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
+ UserPointer<const void> bytes,
uint32_t num_bytes,
- const MojoHandle* handles,
+ UserPointer<const MojoHandle> handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
@@ -197,8 +194,10 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
return MOJO_RESULT_INVALID_ARGUMENT;
// Easy case: not sending any handles.
- if (num_handles == 0)
- return dispatcher->WriteMessage(bytes, num_bytes, NULL, flags);
+ if (num_handles == 0) {
+ return dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes, NULL,
+ flags);
+ }
// We have to handle |handles| here, since we have to mark them busy in the
// global handle table. We can't delegate this to the dispatcher, since the
@@ -208,11 +207,11 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
// validity, even for dispatchers that don't support |WriteMessage()| and will
// simply return failure unconditionally. It also breaks the usual
// left-to-right verification order of arguments.)
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxMessageNumHandles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
+ UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
+
// We'll need to hold on to the dispatchers so that we can pass them on to
// |WriteMessage()| and also so that we can unlock their locks afterwards
// without accessing the handle table. These can be dumb pointers, since their
@@ -226,13 +225,14 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
{
base::AutoLock locker(handle_table_lock_);
MojoResult result = handle_table_.MarkBusyAndStartTransport(
- message_pipe_handle, handles, num_handles, &transports);
+ message_pipe_handle, handles_reader.GetPointer(), num_handles,
+ &transports);
if (result != MOJO_RESULT_OK)
return result;
}
- MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports,
- flags);
+ MojoResult rv = dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes,
+ &transports, flags);
// We need to release the dispatcher locks before we take the handle table
// lock.
@@ -241,77 +241,84 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
{
base::AutoLock locker(handle_table_lock_);
- if (rv == MOJO_RESULT_OK)
- handle_table_.RemoveBusyHandles(handles, num_handles);
- else
- handle_table_.RestoreBusyHandles(handles, num_handles);
+ if (rv == MOJO_RESULT_OK) {
+ handle_table_.RemoveBusyHandles(handles_reader.GetPointer(), num_handles);
+ } else {
+ handle_table_.RestoreBusyHandles(handles_reader.GetPointer(),
+ num_handles);
+ }
}
return rv;
}
MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
+ UserPointer<void> bytes,
+ UserPointer<uint32_t> num_bytes,
+ UserPointer<MojoHandle> handles,
+ UserPointer<uint32_t> num_handles,
MojoReadMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- if (num_handles) {
- if (!VerifyUserPointer<uint32_t>(num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, *num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- // Easy case: won't receive any handles.
- if (!num_handles || *num_handles == 0)
- return dispatcher->ReadMessage(bytes, num_bytes, NULL, num_handles, flags);
-
- DispatcherVector dispatchers;
- MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes,
- &dispatchers, num_handles,
- flags);
- if (!dispatchers.empty()) {
- DCHECK_EQ(rv, MOJO_RESULT_OK);
- DCHECK(num_handles);
- DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles));
-
- bool success;
- {
- base::AutoLock locker(handle_table_lock_);
- success = handle_table_.AddDispatcherVector(dispatchers, handles);
- }
- if (!success) {
- LOG(ERROR) << "Received message with " << dispatchers.size()
- << " handles, but handle table full";
- // Close dispatchers (outside the lock).
- for (size_t i = 0; i < dispatchers.size(); i++) {
- if (dispatchers[i])
- dispatchers[i]->Close();
+ uint32_t num_handles_value = num_handles.IsNull() ? 0 : num_handles.Get();
+
+ MojoResult rv;
+ if (num_handles_value == 0) {
+ // Easy case: won't receive any handles.
+ rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), NULL,
+ &num_handles_value, flags);
+ } else {
+ DispatcherVector dispatchers;
+ rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), &dispatchers,
+ &num_handles_value, flags);
+ if (!dispatchers.empty()) {
+ DCHECK_EQ(rv, MOJO_RESULT_OK);
+ DCHECK(!num_handles.IsNull());
+ DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value));
+
+ bool success;
+ UserPointer<MojoHandle>::Writer handles_writer(handles,
+ dispatchers.size());
+ {
+ base::AutoLock locker(handle_table_lock_);
+ success = handle_table_.AddDispatcherVector(
+ dispatchers, handles_writer.GetPointer());
+ }
+ if (success) {
+ handles_writer.Commit();
+ } else {
+ LOG(ERROR) << "Received message with " << dispatchers.size()
+ << " handles, but handle table full";
+ // Close dispatchers (outside the lock).
+ for (size_t i = 0; i < dispatchers.size(); i++) {
+ if (dispatchers[i])
+ dispatchers[i]->Close();
+ }
+ if (rv == MOJO_RESULT_OK)
+ rv = MOJO_RESULT_RESOURCE_EXHAUSTED;
}
}
}
+ if (!num_handles.IsNull())
+ num_handles.Put(num_handles_value);
return rv;
}
-MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle) {
+MojoResult Core::CreateDataPipe(
+ UserPointer<const MojoCreateDataPipeOptions> options,
+ UserPointer<MojoHandle> data_pipe_producer_handle,
+ UserPointer<MojoHandle> data_pipe_consumer_handle) {
MojoCreateDataPipeOptions validated_options = {};
// This will verify the |options| pointer.
- MojoResult result = DataPipe::ValidateCreateOptions(options,
- &validated_options);
+ MojoResult result = DataPipe::ValidateCreateOptions(
+ options.GetPointerUnsafe(), &validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(data_pipe_producer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointer<MojoHandle>(data_pipe_consumer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher(
new DataPipeProducerDispatcher());
@@ -337,33 +344,35 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
producer_dispatcher->Init(data_pipe);
consumer_dispatcher->Init(data_pipe);
- *data_pipe_producer_handle = handle_pair.first;
- *data_pipe_consumer_handle = handle_pair.second;
+ data_pipe_producer_handle.Put(handle_pair.first);
+ data_pipe_consumer_handle.Put(handle_pair.second);
return MOJO_RESULT_OK;
}
MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
+ UserPointer<const void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->WriteData(elements, num_bytes, flags);
+ return dispatcher->WriteData(elements.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
+ return dispatcher->BeginWriteData(buffer.GetPointerUnsafe(),
+ buffer_num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
@@ -377,27 +386,29 @@ MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
}
MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
+ UserPointer<void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->ReadData(elements, num_bytes, flags);
+ return dispatcher->ReadData(elements.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<const void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
+ return dispatcher->BeginReadData(buffer.GetPointerUnsafe(),
+ buffer_num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
@@ -411,18 +422,16 @@ MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
}
MojoResult Core::CreateSharedBuffer(
- const MojoCreateSharedBufferOptions* options,
+ UserPointer<const MojoCreateSharedBufferOptions> options,
uint64_t num_bytes,
- MojoHandle* shared_buffer_handle) {
+ UserPointer<MojoHandle> shared_buffer_handle) {
MojoCreateSharedBufferOptions validated_options = {};
// This will verify the |options| pointer.
MojoResult result =
- SharedBufferDispatcher::ValidateCreateOptions(options,
+ SharedBufferDispatcher::ValidateCreateOptions(options.GetPointerUnsafe(),
&validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(shared_buffer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<SharedBufferDispatcher> dispatcher;
result = SharedBufferDispatcher::Create(validated_options, num_bytes,
@@ -439,25 +448,22 @@ MojoResult Core::CreateSharedBuffer(
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
- *shared_buffer_handle = h;
+ shared_buffer_handle.Put(h);
return MOJO_RESULT_OK;
}
MojoResult Core::DuplicateBufferHandle(
MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle) {
+ UserPointer<const MojoDuplicateBufferHandleOptions> options,
+ UserPointer<MojoHandle> new_buffer_handle) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
// Don't verify |options| here; that's the dispatcher's job.
- if (!VerifyUserPointer<MojoHandle>(new_buffer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
scoped_refptr<Dispatcher> new_dispatcher;
- MojoResult result = dispatcher->DuplicateBufferHandle(options,
- &new_dispatcher);
+ MojoResult result = dispatcher->DuplicateBufferHandle(
+ options.GetPointerUnsafe(), &new_dispatcher);
if (result != MOJO_RESULT_OK)
return result;
@@ -468,22 +474,19 @@ MojoResult Core::DuplicateBufferHandle(
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
- *new_buffer_handle = new_handle;
+ new_buffer_handle.Put(new_handle);
return MOJO_RESULT_OK;
}
MojoResult Core::MapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
- void** buffer,
+ UserPointer<void*> buffer,
MojoMapBufferFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<void*>(buffer, 1))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
scoped_ptr<RawSharedBufferMapping> mapping;
MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
if (result != MOJO_RESULT_OK)
@@ -498,13 +501,13 @@ MojoResult Core::MapBuffer(MojoHandle buffer_handle,
if (result != MOJO_RESULT_OK)
return result;
- *buffer = address;
+ buffer.Put(address);
return MOJO_RESULT_OK;
}
-MojoResult Core::UnmapBuffer(void* buffer) {
+MojoResult Core::UnmapBuffer(UserPointerValue<void> buffer) {
base::AutoLock locker(mapping_table_lock_);
- return mapping_table_.RemoveMapping(buffer);
+ return mapping_table_.RemoveMapping(buffer.GetValue());
}
// Note: We allow |handles| to repeat the same handle multiple times, since
diff --git a/mojo/system/core.h b/mojo/system/core.h
index a0bc293..ba811f8 100644
--- a/mojo/system/core.h
+++ b/mojo/system/core.h
@@ -15,6 +15,7 @@
#include "mojo/public/c/system/types.h"
#include "mojo/system/handle_table.h"
#include "mojo/system/mapping_table.h"
+#include "mojo/system/memory.h"
#include "mojo/system/system_impl_export.h"
namespace mojo {
@@ -44,61 +45,64 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
MojoResult Wait(MojoHandle handle,
MojoHandleSignals signals,
MojoDeadline deadline);
- MojoResult WaitMany(const MojoHandle* handles,
- const MojoHandleSignals* signals,
+ MojoResult WaitMany(UserPointer<const MojoHandle> handles,
+ UserPointer<const MojoHandleSignals> signals,
uint32_t num_handles,
MojoDeadline deadline);
- MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1);
+ MojoResult CreateMessagePipe(
+ UserPointer<const MojoCreateMessagePipeOptions> options,
+ UserPointer<MojoHandle> message_pipe_handle0,
+ UserPointer<MojoHandle> message_pipe_handle1);
MojoResult WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
+ UserPointer<const void> bytes,
uint32_t num_bytes,
- const MojoHandle* handles,
+ UserPointer<const MojoHandle> handles,
uint32_t num_handles,
MojoWriteMessageFlags flags);
MojoResult ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
+ UserPointer<void> bytes,
+ UserPointer<uint32_t> num_bytes,
+ UserPointer<MojoHandle> handles,
+ UserPointer<uint32_t> num_handles,
MojoReadMessageFlags flags);
- MojoResult CreateDataPipe(const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle);
+ MojoResult CreateDataPipe(
+ UserPointer<const MojoCreateDataPipeOptions> options,
+ UserPointer<MojoHandle> data_pipe_producer_handle,
+ UserPointer<MojoHandle> data_pipe_consumer_handle);
MojoResult WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
+ UserPointer<const void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoWriteDataFlags flags);
MojoResult BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoWriteDataFlags flags);
MojoResult EndWriteData(MojoHandle data_pipe_producer_handle,
uint32_t num_bytes_written);
MojoResult ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
+ UserPointer<void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoReadDataFlags flags);
MojoResult BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<const void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoReadDataFlags flags);
MojoResult EndReadData(MojoHandle data_pipe_consumer_handle,
uint32_t num_bytes_read);
- MojoResult CreateSharedBuffer(const MojoCreateSharedBufferOptions* options,
- uint64_t num_bytes,
- MojoHandle* shared_buffer_handle);
+ MojoResult CreateSharedBuffer(
+ UserPointer<const MojoCreateSharedBufferOptions> options,
+ uint64_t num_bytes,
+ UserPointer<MojoHandle> shared_buffer_handle);
MojoResult DuplicateBufferHandle(
MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle);
+ UserPointer<const MojoDuplicateBufferHandleOptions> options,
+ UserPointer<MojoHandle> new_buffer_handle);
MojoResult MapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
- void** buffer,
+ UserPointer<void*> buffer,
MojoMapBufferFlags flags);
- MojoResult UnmapBuffer(void* buffer);
+ MojoResult UnmapBuffer(UserPointerValue<void> buffer);
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
diff --git a/mojo/system/core_test_base.cc b/mojo/system/core_test_base.cc
index c91437c..c02b118 100644
--- a/mojo/system/core_test_base.cc
+++ b/mojo/system/core_test_base.cc
@@ -68,8 +68,8 @@ class MockDispatcher : public Dispatcher {
virtual MojoResult ReadMessageImplNoLock(
void* bytes,
uint32_t* num_bytes,
- DispatcherVector* /*dispatchers*/,
- uint32_t* /*num_dispatchers*/,
+ DispatcherVector* dispatchers,
+ uint32_t* num_dispatchers,
MojoReadMessageFlags /*flags*/) OVERRIDE {
info_->IncrementReadMessageCallCount();
lock().AssertAcquired();
@@ -77,6 +77,14 @@ class MockDispatcher : public Dispatcher {
if (num_bytes && !VerifyUserPointerWithSize<1>(bytes, *num_bytes))
return MOJO_RESULT_INVALID_ARGUMENT;
+ if (num_dispatchers) {
+ *num_dispatchers = 1;
+ if (dispatchers) {
+ // Okay to leave an invalid dispatcher.
+ dispatchers->resize(1);
+ }
+ }
+
return MOJO_RESULT_OK;
}
diff --git a/mojo/system/core_unittest.cc b/mojo/system/core_unittest.cc
index af3d0c1..59ff1c8 100644
--- a/mojo/system/core_unittest.cc
+++ b/mojo/system/core_unittest.cc
@@ -38,38 +38,45 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h, NULL, 0, NULL, 0,
+ core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 1, NULL, 0,
+ core()->WriteMessage(h, NullUserPointer(), 1, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(2u, info.GetWriteMessageCallCount());
EXPECT_EQ(0u, info.GetReadMessageCallCount());
uint32_t num_bytes = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(),
+ MakeUserPointer(&num_bytes), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetReadMessageCallCount());
num_bytes = 1;
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(),
+ MakeUserPointer(&num_bytes), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(2u, info.GetReadMessageCallCount());
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, NULL, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(3u, info.GetReadMessageCallCount());
EXPECT_EQ(0u, info.GetWriteDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ core()->WriteData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteDataCallCount());
EXPECT_EQ(0u, info.GetBeginWriteDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginWriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ core()->BeginWriteData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetBeginWriteDataCallCount());
EXPECT_EQ(0u, info.GetEndWriteDataCallCount());
@@ -79,12 +86,14 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(0u, info.GetReadDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->ReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ core()->ReadData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetReadDataCallCount());
EXPECT_EQ(0u, info.GetBeginReadDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ core()->BeginReadData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetBeginReadDataCallCount());
EXPECT_EQ(0u, info.GetEndReadDataCallCount());
@@ -105,7 +114,9 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(3u, info.GetAddWaiterCallCount());
MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE;
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(&h, &handle_signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(&h),
+ MakeUserPointer(&handle_signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(4u, info.GetAddWaiterCallCount());
EXPECT_EQ(0u, info.GetDtorCallCount());
@@ -152,81 +163,78 @@ TEST_F(CoreTest, InvalidArguments) {
MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
~MOJO_HANDLE_SIGNAL_NONE};
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 0, MOJO_DEADLINE_INDEFINITE));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(NULL, signals, 0, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, NULL, 0, MOJO_DEADLINE_INDEFINITE));
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(NULL, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, NULL, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
MockHandleInfo info[2];
handles[0] = CreateMockHandle(&info[0]);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
handles[1] = handles[0] + 1; // Invalid handle.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
handles[1] = CreateMockHandle(&info[1]);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0]));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1]));
}
- // |CreateMessagePipe()|:
- {
- MojoHandle h;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, NULL, NULL));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, &h, NULL));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, NULL, &h));
- }
+ // |CreateMessagePipe()|: Nothing to check (apart from things that cause
+ // death).
// |WriteMessage()|:
// Only check arguments checked by |Core|, namely |handle|, |handles|, and
// |num_handles|.
{
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(MOJO_HANDLE_INVALID, NULL, 0, NULL, 0,
+ core()->WriteMessage(MOJO_HANDLE_INVALID, NullUserPointer(), 0,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MockHandleInfo info;
MojoHandle h = CreateMockHandle(&info);
MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
- // Null |handles| with nonzero |num_handles|.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, NULL, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- // Checked by |Core|, shouldn't go through to the dispatcher.
- EXPECT_EQ(0u, info.GetWriteMessageCallCount());
-
// Huge handle count (implausibly big on some systems -- more than can be
// stored in a 32-bit address space).
// Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or
// |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or
// not.
EXPECT_NE(MOJO_RESULT_OK,
- core()->WriteMessage(h, NULL, 0, handles,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles),
std::numeric_limits<uint32_t>::max(),
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Huge handle count (plausibly big).
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->WriteMessage(h, NULL, 0, handles,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles),
std::numeric_limits<uint32_t>::max() /
sizeof(handles[0]),
MOJO_WRITE_MESSAGE_FLAG_NONE));
@@ -234,20 +242,23 @@ TEST_F(CoreTest, InvalidArguments) {
// Invalid handle in |handles|.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Two invalid handles in |handles|.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Can't send a handle over itself.
handles[0] = h;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
@@ -257,27 +268,31 @@ TEST_F(CoreTest, InvalidArguments) {
// This is "okay", but |MockDispatcher| doesn't implement it.
handles[0] = h2;
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// One of the |handles| is still invalid.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// One of the |handles| is the same as |handle|.
handles[1] = h;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// Can't send a handle twice in the same message.
handles[1] = h2;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
@@ -293,23 +308,20 @@ TEST_F(CoreTest, InvalidArguments) {
// |num_handles|.
{
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(MOJO_HANDLE_INVALID, NULL, NULL, NULL, NULL,
+ core()->ReadMessage(MOJO_HANDLE_INVALID, NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
MockHandleInfo info;
MojoHandle h = CreateMockHandle(&info);
- uint32_t handle_count = 1;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
- MOJO_READ_MESSAGE_FLAG_NONE));
- // Checked by |Core|, shouldn't go through to the dispatcher.
- EXPECT_EQ(0u, info.GetReadMessageCallCount());
-
// Okay.
- handle_count = 0;
+ uint32_t handle_count = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
+ MakeUserPointer(&handle_count),
MOJO_READ_MESSAGE_FLAG_NONE));
// Checked by |Core|, shouldn't go through to the dispatcher.
EXPECT_EQ(1u, info.GetReadMessageCallCount());
@@ -318,6 +330,82 @@ TEST_F(CoreTest, InvalidArguments) {
}
}
+// These test invalid arguments that should cause death if we're being paranoid
+// about checking arguments (which we would want to do if, e.g., we were in a
+// true "kernel" situation, but we might not want to do otherwise for
+// performance reasons). Probably blatant errors like passing in null pointers
+// (for required pointer arguments) will still cause death, but perhaps not
+// predictably.
+TEST_F(CoreTest, InvalidArgumentsDeath) {
+ const char kMemoryCheckFailedRegex[] = "Check failed";
+
+ // |WaitMany()|:
+ {
+ MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
+ MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
+ ~MOJO_HANDLE_SIGNAL_NONE};
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 1,
+ MOJO_DEADLINE_INDEFINITE),
+ kMemoryCheckFailedRegex);
+ }
+
+ // |CreateMessagePipe()|:
+ {
+ MojoHandle h;
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(),
+ NullUserPointer()),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h),
+ NullUserPointer()),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(),
+ MakeUserPointer(&h)),
+ kMemoryCheckFailedRegex);
+ }
+
+ // |WriteMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+
+ // Null |handles| with nonzero |num_handles|.
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(),
+ 1, MOJO_WRITE_MESSAGE_FLAG_NONE),
+ kMemoryCheckFailedRegex);
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+
+ // |ReadMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+
+ uint32_t handle_count = 1;
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
+ MakeUserPointer(&handle_count),
+ MOJO_READ_MESSAGE_FLAG_NONE),
+ kMemoryCheckFailedRegex);
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+}
+
// TODO(vtl): test |Wait()| and |WaitMany()| properly
// - including |WaitMany()| with the same handle more than once (with
// same/different signals)
@@ -325,7 +413,9 @@ TEST_F(CoreTest, InvalidArguments) {
TEST_F(CoreTest, MessagePipe) {
MojoHandle h[2];
- EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NULL, &h[0], &h[1]));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h[0]),
+ MakeUserPointer(&h[1])));
// Should get two distinct, valid handles.
EXPECT_NE(h[0], MOJO_HANDLE_INVALID);
EXPECT_NE(h[1], MOJO_HANDLE_INVALID);
@@ -335,13 +425,16 @@ TEST_F(CoreTest, MessagePipe) {
MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
MOJO_HANDLE_SIGNAL_READABLE};
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
- core()->WaitMany(h, signals, 2, 0));
+ core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ 0));
// Try to read anyway.
char buffer[1] = {'a'};
uint32_t buffer_size = 1;
EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
- core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], UserPointer<void>(buffer),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
// Check that it left its inputs alone.
EXPECT_EQ('a', buffer[0]);
@@ -356,31 +449,38 @@ TEST_F(CoreTest, MessagePipe) {
// Also check that |h[1]| is writable using |WaitMany()|.
signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE;
- EXPECT_EQ(1, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(1, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
// Write to |h[1]|.
buffer[0] = 'b';
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// Check that |h[0]| is now readable.
signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
signals[1] = MOJO_HANDLE_SIGNAL_READABLE;
- EXPECT_EQ(0, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(0, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
// Read from |h[0]|.
// First, get only the size.
buffer_size = 0;
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[0], NULL, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], NullUserPointer(),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, buffer_size);
// Then actually read it.
buffer[0] = 'c';
buffer_size = 1;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], UserPointer<void>(buffer),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ('b', buffer[0]);
EXPECT_EQ(1u, buffer_size);
@@ -392,7 +492,8 @@ TEST_F(CoreTest, MessagePipe) {
// Write to |h[0]|.
buffer[0] = 'd';
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h[0], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[0], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// Close |h[0]|.
@@ -408,7 +509,8 @@ TEST_F(CoreTest, MessagePipe) {
// Discard a message from |h[1]|.
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[1], NULL, NULL, NULL, NULL,
+ core()->ReadMessage(h[1], NullUserPointer(), NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_MAY_DISCARD));
// |h[1]| is no longer readable (and will never be).
@@ -418,7 +520,8 @@ TEST_F(CoreTest, MessagePipe) {
// Try writing to |h[1]|.
buffer[0] = 'e';
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
@@ -439,13 +542,14 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
MojoHandle h_passing[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passing[0]),
+ MakeUserPointer(&h_passing[1])));
// Make sure that |h_passing[]| work properly.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -453,9 +557,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -464,34 +569,34 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Make sure that you can't pass either of the message pipe's handles over
// itself.
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &h_passing[0], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&h_passing[0]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &h_passing[1], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&h_passing[1]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoHandle h_passed[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passed[0], &h_passed[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passed[0]),
+ MakeUserPointer(&h_passed[1])));
// Make sure that |h_passed[]| work properly.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passed[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passed[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passed[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -499,9 +604,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &h_passed[1], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize,
+ MakeUserPointer(&h_passed[1]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -509,9 +614,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
@@ -531,18 +637,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Write to |h_passed[0]|. Should receive on |h_received|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_received,
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -557,7 +663,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
TEST_F(CoreTest, DataPipe) {
MojoHandle ph, ch; // p is for producer and c is for consumer.
- EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NULL, &ph, &ch));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph),
+ MakeUserPointer(&ch)));
// Should get two distinct, valid handles.
EXPECT_NE(ph, MOJO_HANDLE_INVALID);
EXPECT_NE(ch, MOJO_HANDLE_INVALID);
@@ -579,7 +687,8 @@ TEST_F(CoreTest, DataPipe) {
char elements[2] = {'A', 'B'};
uint32_t num_bytes = 2u;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, elements, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(2u, num_bytes);
@@ -592,7 +701,8 @@ TEST_F(CoreTest, DataPipe) {
elements[1] = -1;
num_bytes = 1u;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, elements, &num_bytes,
+ core()->ReadData(ch, UserPointer<void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ('A', elements[0]);
EXPECT_EQ(-1, elements[1]);
@@ -601,7 +711,8 @@ TEST_F(CoreTest, DataPipe) {
void* write_ptr = NULL;
num_bytes = 0u;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ core()->BeginWriteData(ph, MakeUserPointer(&write_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
// We count on the default options providing a decent buffer size.
ASSERT_GE(num_bytes, 3u);
@@ -610,7 +721,8 @@ TEST_F(CoreTest, DataPipe) {
elements[0] = 'X';
num_bytes = 1u;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteData(ph, elements, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
// Actually write the data, and complete it now.
@@ -622,20 +734,21 @@ TEST_F(CoreTest, DataPipe) {
// Query how much data we have.
num_bytes = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY));
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
+ MOJO_READ_DATA_FLAG_QUERY));
EXPECT_EQ(4u, num_bytes);
// Try to discard ten characters, in all-or-none mode. Should fail.
num_bytes = 10;
EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD |
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
// Discard two characters.
num_bytes = 2;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD |
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
@@ -643,7 +756,8 @@ TEST_F(CoreTest, DataPipe) {
const void* read_ptr = NULL;
num_bytes = 2;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ core()->BeginReadData(ch, MakeUserPointer(&read_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
// Note: Count on still being able to do the contiguous read here.
ASSERT_EQ(2u, num_bytes);
@@ -651,7 +765,7 @@ TEST_F(CoreTest, DataPipe) {
// Discarding right now should fail.
num_bytes = 1;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD));
// Actually check our data and end the two-phase read.
@@ -689,17 +803,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
MojoHandle h_passing[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passing[0]),
+ MakeUserPointer(&h_passing[1])));
MojoHandle ph, ch;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateDataPipe(NULL, &ph, &ch));
+ core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph),
+ MakeUserPointer(&ch)));
// Send |ch| from |h_passing[0]| to |h_passing[1]|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -707,9 +823,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -730,22 +847,23 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
// Write to |ph|. Should receive on |ch_received|.
num_bytes = kWorldSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, kWorld, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(kWorld),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
+ core()->ReadData(ch_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
// Now pass |ph| in the same direction.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -753,9 +871,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
@@ -776,13 +895,15 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
// Write to |ph_received|. Should receive on |ch_received|.
num_bytes = kHelloSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph_received, kHello, &num_bytes,
+ core()->WriteData(ph_received, UserPointer<const void>(kHello),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
+ core()->ReadData(ch_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -796,20 +917,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
void* write_ptr = NULL;
num_bytes = 0;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ core()->BeginWriteData(ph, MakeUserPointer(&write_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
ASSERT_GE(num_bytes, 1u);
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// But |ch| can, even if |ph| is in a two-phase write.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
ch = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK,
@@ -818,9 +938,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -840,19 +961,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
const void* read_ptr = NULL;
num_bytes = 1;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ core()->BeginReadData(ch, MakeUserPointer(&read_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// But |ph| can, even if |ch| is in a two-phase read.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
ph = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK,
@@ -861,9 +981,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
diff --git a/mojo/system/entrypoints.cc b/mojo/system/entrypoints.cc
index b70fcad..2ee2c3e 100644
--- a/mojo/system/entrypoints.cc
+++ b/mojo/system/entrypoints.cc
@@ -12,6 +12,9 @@
static mojo::system::Core* g_core = NULL;
+using mojo::system::MakeUserPointer;
+using mojo::system::MakeUserPointerValue;
+
namespace mojo {
namespace system {
namespace entrypoints {
@@ -49,14 +52,18 @@ MojoResult MojoWaitMany(const MojoHandle* handles,
const MojoHandleSignals* signals,
uint32_t num_handles,
MojoDeadline deadline) {
- return g_core->WaitMany(handles, signals, num_handles, deadline);
+ return g_core->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals),
+ num_handles,
+ deadline);
}
MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options,
MojoHandle* message_pipe_handle0,
MojoHandle* message_pipe_handle1) {
- return g_core->CreateMessagePipe(
- options, message_pipe_handle0, message_pipe_handle1);
+ return g_core->CreateMessagePipe(MakeUserPointer(options),
+ MakeUserPointer(message_pipe_handle0),
+ MakeUserPointer(message_pipe_handle1));
}
MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
@@ -65,41 +72,54 @@ MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
const MojoHandle* handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
- return g_core->WriteMessage(
- message_pipe_handle, bytes, num_bytes, handles, num_handles, flags);
+ return g_core->WriteMessage(message_pipe_handle,
+ MakeUserPointer(bytes),
+ num_bytes,
+ MakeUserPointer(handles),
+ num_handles,
+ flags);
}
MojoResult MojoReadMessage(MojoHandle message_pipe_handle,
void* bytes,
uint32_t* num_bytes,
MojoHandle* handles,
- uint32_t* num_handles,
+ uint32_t* num_handles,
MojoReadMessageFlags flags) {
- return g_core->ReadMessage(
- message_pipe_handle, bytes, num_bytes, handles, num_handles, flags);
+ return g_core->ReadMessage(message_pipe_handle,
+ MakeUserPointer(bytes),
+ MakeUserPointer(num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(num_handles),
+ flags);
}
MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options,
MojoHandle* data_pipe_producer_handle,
MojoHandle* data_pipe_consumer_handle) {
- return g_core->CreateDataPipe(
- options, data_pipe_producer_handle, data_pipe_consumer_handle);
+ return g_core->CreateDataPipe(MakeUserPointer(options),
+ MakeUserPointer(data_pipe_producer_handle),
+ MakeUserPointer(data_pipe_consumer_handle));
}
MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_elements,
MojoWriteDataFlags flags) {
- return g_core->WriteData(
- data_pipe_producer_handle, elements, num_elements, flags);
+ return g_core->WriteData(data_pipe_producer_handle,
+ MakeUserPointer(elements),
+ MakeUserPointer(num_elements),
+ flags);
}
MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
void** buffer,
uint32_t* buffer_num_elements,
MojoWriteDataFlags flags) {
- return g_core->BeginWriteData(
- data_pipe_producer_handle, buffer, buffer_num_elements, flags);
+ return g_core->BeginWriteData(data_pipe_producer_handle,
+ MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements),
+ flags);
}
MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle,
@@ -111,16 +131,20 @@ MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
void* elements,
uint32_t* num_elements,
MojoReadDataFlags flags) {
- return g_core->ReadData(
- data_pipe_consumer_handle, elements, num_elements, flags);
+ return g_core->ReadData(data_pipe_consumer_handle,
+ MakeUserPointer(elements),
+ MakeUserPointer(num_elements),
+ flags);
}
MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
const void** buffer,
uint32_t* buffer_num_elements,
MojoReadDataFlags flags) {
- return g_core->BeginReadData(
- data_pipe_consumer_handle, buffer, buffer_num_elements, flags);
+ return g_core->BeginReadData(data_pipe_consumer_handle,
+ MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements),
+ flags);
}
MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle,
@@ -132,15 +156,18 @@ MojoResult MojoCreateSharedBuffer(
const struct MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
MojoHandle* shared_buffer_handle) {
- return g_core->CreateSharedBuffer(options, num_bytes, shared_buffer_handle);
+ return g_core->CreateSharedBuffer(MakeUserPointer(options),
+ num_bytes,
+ MakeUserPointer(shared_buffer_handle));
}
MojoResult MojoDuplicateBufferHandle(
MojoHandle buffer_handle,
const struct MojoDuplicateBufferHandleOptions* options,
MojoHandle* new_buffer_handle) {
- return g_core->DuplicateBufferHandle(
- buffer_handle, options, new_buffer_handle);
+ return g_core->DuplicateBufferHandle(buffer_handle,
+ MakeUserPointer(options),
+ MakeUserPointer(new_buffer_handle));
}
MojoResult MojoMapBuffer(MojoHandle buffer_handle,
@@ -148,11 +175,15 @@ MojoResult MojoMapBuffer(MojoHandle buffer_handle,
uint64_t num_bytes,
void** buffer,
MojoMapBufferFlags flags) {
- return g_core->MapBuffer(buffer_handle, offset, num_bytes, buffer, flags);
+ return g_core->MapBuffer(buffer_handle,
+ offset,
+ num_bytes,
+ MakeUserPointer(buffer),
+ flags);
}
MojoResult MojoUnmapBuffer(void* buffer) {
- return g_core->UnmapBuffer(buffer);
+ return g_core->UnmapBuffer(MakeUserPointerValue(buffer));
}
} // extern "C"
diff --git a/mojo/system/mapping_table.cc b/mojo/system/mapping_table.cc
index a6e5bb3..6170679 100644
--- a/mojo/system/mapping_table.cc
+++ b/mojo/system/mapping_table.cc
@@ -33,9 +33,8 @@ MojoResult MappingTable::AddMapping(
return MOJO_RESULT_OK;
}
-MojoResult MappingTable::RemoveMapping(void* address) {
- AddressToMappingMap::iterator it =
- address_to_mapping_map_.find(reinterpret_cast<uintptr_t>(address));
+MojoResult MappingTable::RemoveMapping(uintptr_t address) {
+ AddressToMappingMap::iterator it = address_to_mapping_map_.find(address);
if (it == address_to_mapping_map_.end())
return MOJO_RESULT_INVALID_ARGUMENT;
RawSharedBufferMapping* mapping_to_delete = it->second;
diff --git a/mojo/system/mapping_table.h b/mojo/system/mapping_table.h
index 5268234..e21d685 100644
--- a/mojo/system/mapping_table.h
+++ b/mojo/system/mapping_table.h
@@ -39,7 +39,7 @@ class MOJO_SYSTEM_IMPL_EXPORT MappingTable {
// Tries to add a mapping. (Takes ownership of the mapping in all cases; on
// failure, it will be destroyed.)
MojoResult AddMapping(scoped_ptr<RawSharedBufferMapping> mapping);
- MojoResult RemoveMapping(void* address);
+ MojoResult RemoveMapping(uintptr_t address);
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
diff --git a/mojo/system/memory.cc b/mojo/system/memory.cc
index cee7e05..160e1e5 100644
--- a/mojo/system/memory.cc
+++ b/mojo/system/memory.cc
@@ -29,6 +29,11 @@ bool IsAligned<8>(const void* pointer) {
#endif
template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer) {
+ CHECK(pointer && IsAligned<alignment>(pointer));
+}
+
+template <size_t size, size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) {
// TODO(vtl): If running in kernel mode, do a full verification. For now, just
// check that it's non-null and aligned. (A faster user mode implementation is
@@ -37,6 +42,12 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) {
}
// Explicitly instantiate the sizes we need. Add instantiations as needed.
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<1, 1>(
+ const void*);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 4>(
+ const void*);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<8, 8>(
+ const void*);
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<1, 1>(
const void*);
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 4>(
@@ -49,16 +60,39 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<8, 8>(
// this in particular to check that various Options structs are aligned.
#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
template <>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 8>(
+ const void* pointer) {
+ CHECK(pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0);
+}
+template <>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 8>(
const void* pointer) {
return !!pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0;
}
#else
+template MOJO_SYSTEM_IMPL_EXPORT void CheckUserPointerHelper<4, 8>(
+ const void*);
template MOJO_SYSTEM_IMPL_EXPORT bool VerifyUserPointerHelper<4, 8>(
const void*);
#endif
template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper(
+ const void* pointer,
+ size_t count) {
+ CHECK_LE(count, std::numeric_limits<size_t>::max() / size);
+ CHECK(count == 0 || (pointer && IsAligned<alignment>(pointer)));
+}
+
+// Explicitly instantiate the sizes we need. Add instantiations as needed.
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<1, 1>(
+ const void*, size_t);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<4, 4>(
+ const void*, size_t);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<8, 8>(
+ const void*, size_t);
+
+template <size_t size, size_t alignment>
bool VerifyUserPointerWithCountHelper(const void* pointer, size_t count) {
if (count > std::numeric_limits<size_t>::max() / size)
return false;
@@ -77,7 +111,7 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<4, 4>(
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<8, 8>(
const void*, size_t);
-} // nameespace internal
+} // namespace internal
template <size_t alignment>
bool VerifyUserPointerWithSize(const void* pointer, size_t size) {
diff --git a/mojo/system/memory.h b/mojo/system/memory.h
index 96f800e..e19bfa8 100644
--- a/mojo/system/memory.h
+++ b/mojo/system/memory.h
@@ -6,7 +6,11 @@
#define MOJO_SYSTEM_MEMORY_H_
#include <stddef.h>
+#include <stdint.h>
+#include <string.h> // For |memcpy()|.
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "mojo/public/c/system/macros.h"
#include "mojo/system/system_impl_export.h"
@@ -15,6 +19,26 @@ namespace system {
namespace internal {
+// Removes |const| from |T| (available as |remove_const<T>::type|):
+// TODO(vtl): Remove these once we have the C++11 |remove_const|.
+template <typename T> struct remove_const { typedef T type; };
+template <typename T> struct remove_const<const T> { typedef T type; };
+
+// Yields |(const) char| if |T| is |(const) void|, else |T|:
+template <typename T> struct VoidToChar { typedef T type; };
+template <> struct VoidToChar<void> { typedef char type; };
+template <> struct VoidToChar<const void> { typedef const char type; };
+
+template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer);
+
+template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper(
+ const void* pointer,
+ size_t count);
+
+// TODO(vtl): Delete all the |Verify...()| things (and replace them with
+// |Check...()|.
template <size_t size, size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer);
@@ -26,6 +50,11 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper(
} // namespace internal
+// Forward declarations so that they can be friended.
+template <typename Type> class UserPointerReader;
+template <typename Type> class UserPointerWriter;
+template <typename Type> class UserPointerReaderWriter;
+
// Verify (insofar as possible/necessary) that a |T| can be read from the user
// |pointer|.
template <typename T>
@@ -50,6 +79,247 @@ template <size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer,
size_t size);
+// Provides a convenient way to implicitly get null |UserPointer<Type>|s.
+struct NullUserPointer {};
+
+// Represents a user pointer to a single |Type| (which must be POD), for Mojo
+// primitive parameters.
+//
+// Use a const |Type| for in parameters, and non-const |Type|s for out and
+// in-out parameters (in which case the |Put()| method is available).
+template <typename Type>
+class UserPointer {
+ public:
+ // Instead of explicitly using these constructors, you can often use
+ // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common
+ // exception is when you have, e.g., a |char*| and want to get a
+ // |UserPointer<void>|.)
+ UserPointer() : pointer_(NULL) {}
+ explicit UserPointer(Type* pointer) : pointer_(pointer) {}
+ // Allow implicit conversion from the "null user pointer".
+ UserPointer(NullUserPointer) : pointer_(NULL) {}
+ ~UserPointer() {}
+
+ // Allow assignment from the "null user pointer".
+ UserPointer<Type>& operator=(NullUserPointer) {
+ pointer_ = NULL;
+ return *this;
+ }
+
+ // Allow conversion to a "non-const" |UserPointer|.
+ operator UserPointer<const Type>() const {
+ return UserPointer<const Type>(pointer_);
+ }
+
+ bool IsNull() const {
+ return !pointer_;
+ }
+
+ // We want to force a copy here, so return |Type| not |const Type&|.
+ Type Get() const {
+ internal::CheckUserPointerHelper<sizeof(Type),
+ MOJO_ALIGNOF(Type)>(pointer_);
+ return *pointer_;
+ }
+
+ // Note: This |Put()| method is not valid when |T| is const, e.g., |const
+ // uint32_t|, but it's okay to include them so long as this template is only
+ // implicitly instantiated (see 14.7.1 of the C++11 standard) and not
+ // explicitly instantiated. (On implicit instantiation, only the declarations
+ // need be valid, not the definitions.)
+ //
+ // If |Type| is |void|, we "convert" it to |char|, so that it makes sense.
+ // (Otherwise, we'd need a suitable specialization to exclude |Put()|.)
+ //
+ // In C++11, we could do something like:
+ // template <typename _Type = Type>
+ // typename enable_if<!is_const<_Type>::value &&
+ // !is_void<_Type>::value>::type Put(
+ // const _Type& value) { ... }
+ // (which obviously be correct), but C++03 doesn't allow default function
+ // template arguments.
+ void Put(const typename internal::VoidToChar<Type>::type& value) {
+ internal::CheckUserPointerHelper<sizeof(Type),
+ MOJO_ALIGNOF(Type)>(pointer_);
+ *pointer_ = value;
+ }
+
+ UserPointer At(size_t i) const {
+ return UserPointer(pointer_ + i);
+ }
+
+ // TODO(vtl): This is temporary. Get rid of this. (We should pass
+ // |UserPointer<>|s along appropriately, or access data in a safe way
+ // everywhere.)
+ Type* GetPointerUnsafe() const {
+ return pointer_;
+ }
+
+ // These provides safe (read-only/write-only/read-and-write) access to a
+ // |UserPointer<Type>| (probably pointing to an array) using just an ordinary
+ // pointer (obtained via |GetPointer()|).
+ //
+ // The memory returned by |GetPointer()| may be a copy of the original user
+ // memory, but should be modified only if the user is intended to eventually
+ // see the change.) If any changes are made, |Commit()| should be called to
+ // guarantee that the changes are written back to user memory (it may be
+ // called multiple times).
+ //
+ // Note: These classes are designed to allow fast, unsafe implementations (in
+ // which |GetPointer()| just returns the user pointer) if desired. Thus if
+ // |Commit()| is *not* called, changes may or may not be made visible to the
+ // user.
+ //
+ // Use these classes in the following way:
+ //
+ // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos,
+ // uint32_t num_foos) {
+ // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos);
+ // return PutFoosImpl(foos_reader.GetPointer(), num_foos);
+ // }
+ //
+ // MojoResult Core::GetFoos(UserPointer<uint32_t> foos,
+ // uint32_t num_foos) {
+ // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos);
+ // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos);
+ // foos_writer.Commit();
+ // return rv;
+ // }
+ //
+ // TODO(vtl): Possibly, since we're not really being safe, we should just not
+ // copy for Release builds.
+ typedef UserPointerReader<Type> Reader;
+ typedef UserPointerWriter<Type> Writer;
+ typedef UserPointerReaderWriter<Type> ReaderWriter;
+
+ private:
+ friend class UserPointerReader<Type>;
+ friend class UserPointerWriter<Type>;
+ friend class UserPointerReaderWriter<Type>;
+
+ Type* pointer_;
+ // Allow copy and assignment.
+};
+
+// Provides a convenient way to make a |UserPointer<Type>|.
+template <typename Type>
+inline UserPointer<Type> MakeUserPointer(Type* pointer) {
+ return UserPointer<Type>(pointer);
+}
+
+// Implementation of |UserPointer<Type>::Reader|.
+template <typename Type>
+class UserPointerReader {
+ private:
+ typedef typename internal::remove_const<Type>::type TypeNoConst;
+
+ public:
+ UserPointerReader(UserPointer<const Type> user_pointer, size_t count) {
+ Init(user_pointer.pointer_, count);
+ }
+ UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) {
+ Init(user_pointer.pointer_, count);
+ }
+
+ const Type* GetPointer() const { return buffer_.get(); }
+
+ private:
+ void Init(const Type* user_pointer, size_t count) {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer, count);
+ buffer_.reset(new TypeNoConst[count]);
+ memcpy(buffer_.get(), user_pointer, count * sizeof(Type));
+ }
+
+ scoped_ptr<TypeNoConst[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerReader);
+};
+
+// Implementation of |UserPointer<Type>::Writer|.
+template <typename Type>
+class UserPointerWriter {
+ public:
+ UserPointerWriter(UserPointer<Type> user_pointer, size_t count)
+ : user_pointer_(user_pointer),
+ count_(count) {
+ buffer_.reset(new Type[count_]);
+ memset(buffer_.get(), 0, count_ * sizeof(Type));
+ }
+
+ Type* GetPointer() const { return buffer_.get(); }
+
+ void Commit() {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type));
+ }
+
+ private:
+ UserPointer<Type> user_pointer_;
+ size_t count_;
+ scoped_ptr<Type[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerWriter);
+};
+
+// Implementation of |UserPointer<Type>::ReaderWriter|.
+template <typename Type>
+class UserPointerReaderWriter {
+ public:
+ UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count)
+ : user_pointer_(user_pointer),
+ count_(count) {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ buffer_.reset(new Type[count]);
+ memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type));
+ }
+
+ Type* GetPointer() const { return buffer_.get(); }
+ size_t GetCount() const { return count_; }
+
+ void Commit() {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type));
+ }
+
+ private:
+ UserPointer<Type> user_pointer_;
+ size_t count_;
+ scoped_ptr<Type[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter);
+};
+
+// Represents a user pointer that will never be dereferenced by the system. The
+// pointer value (i.e., the address) may be as a key for lookup, or may be a
+// value that is only passed to the user at some point.
+template <typename Type>
+class UserPointerValue {
+ public:
+ UserPointerValue() : pointer_() {}
+ explicit UserPointerValue(Type* pointer) : pointer_(pointer) {}
+ ~UserPointerValue() {}
+
+ // Returns the *value* of the pointer, which shouldn't be cast back to a
+ // pointer and dereferenced.
+ uintptr_t GetValue() const {
+ return reinterpret_cast<uintptr_t>(pointer_);
+ }
+
+ private:
+ Type* pointer_;
+ // Allow copy and assignment.
+};
+
+// Provides a convenient way to make a |UserPointerValue<Type>|.
+template <typename Type>
+inline UserPointerValue<Type> MakeUserPointerValue(Type* pointer) {
+ return UserPointerValue<Type>(pointer);
+}
+
} // namespace system
} // namespace mojo