By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,948 Members | 1,595 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,948 IT Pros & Developers. It's quick & easy.

Cast object from long in safe manner?

P: n/a
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.

This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was casted into
an object, and this object was accessed, the application would crash hard or
potentially exhibit strangeness from memory corruption.

How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.

Quick example of what I mean:

------------------

class A {
// ...
virtual foo() {}
}

A* a = new A();

long objectID = (long) a;

A* a2 = dynamic_cast<A*>((void *) objectID);

------------------

a2 is always NULL.

Jamie Burns.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #1
Share this Question
Share on Google+
31 Replies


P: n/a
How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.

One idea would be not to use "long integer" but a pointer to a base
class of all your objects. than a dynamic_cast would work pretty well
(although it's quite slow).

Jul 22 '05 #2

P: n/a
"Jamie Burns" schrieb im Newsbeitrag news:bu******************@news.demon.co.uk...
: Hello,
:
: I am writing a client / server application. There is 1 server, and many
: clients. The server processes requests from each client, and typically
: creates and manipulates C++ objects on their behalf.
:
: Now, when a client requests for an object to be created, I pass back a
: pointer to the object (from server memory address scope) as a "long
: integer". To the client, this is just an ID for the object they wish to
: access. From then on, when clients wish an operation to be performed on an
: object, they pass back the appropriate "long integer" and the manipulation
: they wish to perform. The server then casts the "long integer" into the
: object it expects, and performs the manipulation.
:
: This is working quite well, only it is obviously quite dangerous. If a
: client was to pass back a different "long integer", and this was casted into
: an object, and this object was accessed, the application would crash hard or
: potentially exhibit strangeness from memory corruption.
:
: How can I get my "long integer" back into an object in a safe manner? I
: tried dynamic_cast but it wouldn't work.

It's never really safe to cast a pointer to long and back to pointer. A
pointer may be too large to fit into a long or someone might have
modified the long value as you suspect.

I would prefer to have a server app that keeps its objects together with
some id in some collection (probably a map) and only passes the id to the
client. When it recieves an id from the client, the server can easyly
search the map and find the corresponding object (if the id is valid).

Regards
Heinz

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #3

P: n/a
Jamie Burns wrote:
Hello,

I am writing a client / server application. There is 1 server, and
many clients. The server processes requests from each client, and
typically creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish
to access. From then on, when clients wish an operation to be
performed on an object, they pass back the appropriate "long integer"
and the manipulation they wish to perform. The server then casts the
"long integer" into the object it expects, and performs the
manipulation.

This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was
casted into an object, and this object was accessed, the application
would crash hard or potentially exhibit strangeness from memory
corruption.

How can I get my "long integer" back into an object in a safe manner?
I tried dynamic_cast but it wouldn't work.


dynamic_cast only works for casting within a class hierarchy of a
polymorphic class. It needs some information about the type that is
stored in the object. But there is no void object, so you can't
dynamic_cast from a void*.
I would step away from using the pointer itself as ID, and rather
maintain a list (maybe std::vector) of pointers to your objects, and
then provide an index into that as ID for the objects. Then your check
reduces to a simple bounds check.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #4

P: n/a
Hi,

Jamie Burns wrote:
I am writing a client / server application. [...]
How can I get my "long integer" back into an object in a safe manner?


I would certainly recommend that you do not return to the clients a raw
pointer (and this is what you do, even if the clients think it is ID).

It would be better if the server, after creating new object, assigned a
true ID to it and create some mapping from ID to pointer (class std::map
springs to mind). Then, the clients gets the ID, not the pointer.

Of course, the mapping is cleared when the object is destroyed, so that
at any time the map contains only IDs (and pointers) to the living objects.

When the client requests some operation on the object, it gives you the
ID. Instead of just using the pointer (which is unsafe), the server
first has to find the "true" pointer that belongs to the given ID and
then uses the pointer. In this additional step, you may find that there
is no pointer in the map for requested ID, which can mean that the
object was already destroyed or that the client just gives you rubbish.
This is exactly the place where you get the safety, because if there is
no mapping, you can reply to the client that there is "no such object",
instead of naively trying to use it and crashing.

If you think that the mapping would add additional overhead to the
server, it will not. The communication part (networking) is already
heavy enough so that the additional step on the server side is negligible.
You may find the following project interesting:

http://www.msobczak.com/prog/yami/

This is a messaging infrastructure that can be very useful in writing
client/server systems.

--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #5

P: n/a
"Jamie Burns" <se*****@email.com> wrote in message
news:bu******************@news.demon.co.uk...
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.


Set up a mapping in the server of an arbitrary long integer to each object
and pass this integer to the client. When the client calls using the long
integer, the server looks up which object it refers to. You have re-invented
handles. It has some advantage, since if the object is copied or moved in
the course of an operation the handle stays the same for the client. Use a
map to associate the long integer to the object. Forget casting.
--
Gary

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #6

P: n/a

"Jamie Burns" <se*****@email.com> skrev i en meddelelse
news:bu******************@news.demon.co.uk...
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.

This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was casted into an object, and this object was accessed, the application would crash hard or potentially exhibit strangeness from memory corruption.

How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.


You can't. Instead, you could have e.g. a map of < int, class * > and do a
look-up of the pointer. One more example of "an extra indirection solves
everything".

/Peter

[example snipped]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #7

P: n/a
Jamie Burns wrote:
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.
Casting pointers to integers and back is non-portable, though it
generally works with sufficiently large integers. It will probably
be easier to secure the server if you assign IDs that have nothing
to do with object addresses.
This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was casted into
an object, and this object was accessed, the application would crash hard or
potentially exhibit strangeness from memory corruption.

How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.

<snip>

Maintain a std::set of valid object addresses. Or, if you assign
IDs separately from addresses, use a std::map or std::vector to map
IDs to addresses.

You will probably want to prevent clients from interfering with
each other, in which case you will need to maintain one map per
connection.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #8

P: n/a
On Thu, 22 Jan 2004 04:04:42 -0500, Jamie Burns wrote:
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.

This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was casted into
an object, and this object was accessed, the application would crash hard or
potentially exhibit strangeness from memory corruption.

How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.

Quick example of what I mean:

------------------

class A {
// ...
virtual foo() {}
}

A* a = new A();

long objectID = (long) a;

A* a2 = dynamic_cast<A*>((void *) objectID);


I think that dynamic_cast is only for up casting, and that too ONLY in
cases where virtual bases are involved (I might be wrong on that count,
because I haven't really used it ever!).

However, for your purposes, a simple, crude and potentially unsafe
reinterpret_cast would do fine. Just add this statament just before making
the cast:

STATIC_ASSERT (sizeof(long)) == sizeof(A*));

Where STATIC_ASSERT is some static assertion template. You can get it
from boost, or create it yourself like this:

template <bool B>
struct SAssert { };

template <>
struct SAssert<false>;

#define STATIC_ASSERT(EXPR) { SAssert<EXPR> SA_Obj; }

Anyways, why do you want to do such things? Why not just pass the pointer
as a pointer to A?
Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #9

P: n/a

Yes, this is a good idea, but I am concerned about performance. The idea in
sending the pointer was to reduce overhead when a client makes a call on an
object. How fast is performing a lookup using a map in comparison to casting
a pointer? Each process can have a lot of server objects (thus the map would
have to be efficient when has a lot of elements in it).

I have implemented a piece of code now that bascially means I send the
client a pointer to a struct which looks like:

struct ObjectHolder {
unsigned long signature;
MyObject* object;
};

And when they make a call I do this (basically):

ObjectHolder objectHolder = (ObjectHolder*) message.objectId;
if (objectHolder && objectHolder->signature == this->clientSignature) {

MySuperObject* superObject =
dynamic_cast<MySuperObject*>(objectHolder->object);
if (superObject) superObject->doAction(message.data);

}

The struct has an unsigned long in it which is basically a magic string, and
if this checks out it tells me the client owns the object holder, and that
it is indeed an object holder. From there I cast the MyObject into
MySuperObject (which is now allowed whereas I never actually passed this
pointer back and forth).

Of course, there is the very slim chance that if a client passes in a rouge
ObjectHolder pointer (objectId), there could conincedentally be a 4 byte
value matching the "signature" in question at the address of the rogue
pointer, but this has to be millions to one.

Can you see any real problems with this? If a rogue ObjectHolder pointer was
passed, surely the signature should show it to be rogue?

I just think that on a server app which will be processing bucket loads of
these messages, looking up in a map for every message will be a massive
performance drain.

Jamie.

"Heinz Ozwirk" <wa******@gmx.de> wrote in message
news:bu*************@news.t-online.com...

It's never really safe to cast a pointer to long and back to pointer. A
pointer may be too large to fit into a long or someone might have
modified the long value as you suspect.

I would prefer to have a server app that keeps its objects together with
some id in some collection (probably a map) and only passes the id to the
client. When it recieves an id from the client, the server can easyly
search the map and find the corresponding object (if the id is valid).


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #10

P: n/a
On Thu, 22 Jan 2004 04:04:42 -0500, Jamie Burns wrote:
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.

This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was casted into
an object, and this object was accessed, the application would crash hard or
potentially exhibit strangeness from memory corruption.

How can I get my "long integer" back into an object in a safe manner? I
tried dynamic_cast but it wouldn't work.


Yes, this is indeed very dangerous. How to solve it depends a bit on your
needs.

There is no good way to solve this and maintain speed, but you can get
close. I assume you have way of identifying connections, say by a pointer
to a connection object.

When creating the object you want to pass a handle to the client, don't
pass the pointer itself. Instead, create an entry in some array where you
store the connection and the pointer to the object. Return to the client
the index into this array.

When the client wants to refer to an object, it passes back the index. Now
you can easily get back the pointer to the object, but also can you easily
check if the object was indeed one for this connection.

An alternative would be to keep an array of objects passed out for any
connection in the connection object itself. Give the client back the index
into this array. The big advantage of this aproach is that it can also
ease memory management. If the connection dies, you know which related
objects to delete.

HTH,
M4
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #11

P: n/a
"Jamie Burns" <se*****@email.com> wrote in message news:<bu******************@news.demon.co.uk>...
Hello,

I am writing a client / server application. There is 1 server, and many
clients. The server processes requests from each client, and typically
creates and manipulates C++ objects on their behalf.

Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish to
access. From then on, when clients wish an operation to be performed on an
object, they pass back the appropriate "long integer" and the manipulation
they wish to perform. The server then casts the "long integer" into the
object it expects, and performs the manipulation.

This is working quite well, only it is obviously quite dangerous... >
class A {
// ...
virtual foo() {}
} static long next_a_id = 0;
static std::map<long> id_map;

A* a = new A();

// > long objectID = (long) a;
a_map[++next_a_id] = a;
return next_a_id;

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #12

P: n/a
"Jamie Burns" <se*****@email.com> wrote in message
news:<bu******************@news.demon.co.uk>...
I am writing a client / server application. There is 1 server, and
many clients. The server processes requests from each client, and
typically creates and manipulates C++ objects on their behalf. Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer". To the client, this is just an ID for the object they wish
to access. From then on, when clients wish an operation to be
performed on an object, they pass back the appropriate "long integer"
and the manipulation they wish to perform. The server then casts the
"long integer" into the object it expects, and performs the
manipulation.
What happens if the server goes down, then comes back up in the
mean-time (reloading the objects it was managing from persistency)? If
your server doesn't support this now, don't worry. It will have to some
time in the future.

An address is a fugitive thing. Never, never let one escape from a
process.
This is working quite well, only it is obviously quite dangerous. If a
client was to pass back a different "long integer", and this was
casted into an object, and this object was accessed, the application
would crash hard or potentially exhibit strangeness from memory
corruption. How can I get my "long integer" back into an object in a safe manner?


You can't.

The only real solution here is to generate arbitrary identifiers, and
use a map.

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #13

P: n/a


Dhruv schrieb:

A* a2 = dynamic_cast<A*>((void *) objectID);


I think that dynamic_cast is only for up casting, and that too ONLY in
cases where virtual bases are involved (I might be wrong on that count,
because I haven't really used it ever!).


You are wrong.

First, up-casting is implicitly done. What you probably mean is downcasting.

Second, virtual bases have nothing to do with it. What is required is available
RTTI - so at least one virtual function in the class which acts as source for the
cast. That's why a void* can't be the source.

And third, with dynamic_cast you can also cross-cast. For example, try out the
following snippet:
#include <iostream>
#include <ostream>

struct base_a
{
virtual ~base_a(){}
};

struct base_b
{
virtual ~base_b(){}
};

struct derived : public base_a, public base_b
{};

int main(int argc, char* argv[])
{
base_a * b = new derived;

if (base_b * b2 =dynamic_cast<base_b*>(b))
std::cout << "cast successful";

return 0;
}
You will find out that the cast succeeds.
regards,

Thomas

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #14

P: n/a
"Jamie Burns" <se*****@email.com> wrote in message news:<bu*******************@news.demon.co.uk>...
Yes, this is a good idea, but I am concerned about performance. The idea in
sending the pointer was to reduce overhead when a client makes a call on an
object. How fast is performing a lookup using a map in comparison to casting
a pointer? Each process can have a lot of server objects (thus the map would
have to be efficient when has a lot of elements in it).
The map is O(log n) in nature, which is not that bad.

I have implemented a piece of code now that bascially means I send the
client a pointer to a struct which looks like:

struct ObjectHolder {
unsigned long signature;
MyObject* object;
};

And when they make a call I do this (basically):

ObjectHolder objectHolder = (ObjectHolder*) message.objectId;
if (objectHolder && objectHolder->signature == this->clientSignature) {
This will not be good if the client sends a wrong idea. The referenced
object will point at a random location and anything might happen.
MySuperObject* superObject =
dynamic_cast<MySuperObject*>(objectHolder->object);
if (superObject) superObject->doAction(message.data);

}

The struct has an unsigned long in it which is basically a magic string, and
if this checks out it tells me the client owns the object holder, and that
it is indeed an object holder. From there I cast the MyObject into
MySuperObject (which is now allowed whereas I never actually passed this
pointer back and forth).

Of course, there is the very slim chance that if a client passes in a rouge
ObjectHolder pointer (objectId), there could conincedentally be a 4 byte
value matching the "signature" in question at the address of the rogue
pointer, but this has to be millions to one.
But the client could easily send a pointer to some invalid
memory-location or (worse!) to a valid memorylocation allocated by
another client.

Can you see any real problems with this? If a rogue ObjectHolder pointer was
passed, surely the signature should show it to be rogue?

I just think that on a server app which will be processing bucket loads of
these messages, looking up in a map for every message will be a massive
performance drain.

Test it first! Programmers somehow always believe the bottlenecks to
be in the wrong places.

As an alternative, i propose two alternative solutions:

a) use a hash_map. Not standard yet, but it very soon will be. Lookup
is O(1) amortized.
b) use a vector of class* and return the index of that vector. Look-up
will again be O(1). In this case, i would like to verify that the
client is allowed to access that index. This could be done by having
two integers to identify the class... the first being the index, the
second being some magical number which you could produce yourself in
any reasonable way.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #15

P: n/a
Good evening,

not a C++ related answer, but for the questioner a hint nevertheless!

Jamie Burns schrieb:
I am writing a client / server application. [...] Now, when a client requests for an object to be created, I pass back a
pointer to the object (from server memory address scope) as a "long
integer".


Assuming your clients communicates with your server via network:

Aside from the other good advice you got, please keep in mind that the
byteorder of any multibyte entity like a 32bit integer value you send
across the net might be different on the client and server side. For
example an Intel i386 based system has a different byteorder for 32bit
integers as e.g. a MC68000 based system.

However, there is the defined "network byte order", into and out of
which values can be translated for purposes of sending data across
networks in heterogenous environments. The keywords you need to search
for are: htonl and ntohl!

Regards,
Stefan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #16

P: n/a
Please don't top-post. Put your answers below the text you're answering
to, and quote only relevant parts.

[mod note: top posting may be frowned upon, but is not a moderation
consideration.]

Jamie Burns wrote:
It's never really safe to cast a pointer to long and back to pointer.
A pointer may be too large to fit into a long or someone might have
modified the long value as you suspect.

I would prefer to have a server app that keeps its objects together
with some id in some collection (probably a map) and only passes the
id to the client. When it recieves an id from the client, the server
can easyly search the map and find the corresponding object (if the
id is valid).
Yes, this is a good idea, but I am concerned about performance.


Your network may be slower than the lookup in a map.
The idea in sending the pointer was to reduce overhead when a client
makes a call on an object. How fast is performing a lookup using a map
in comparison to casting a pointer?
It certainly is slower, but you might want to benchmark it to see if it
has a relevant impact on performance.
Each process can have a lot of
server objects (thus the map would have to be efficient when has a lot
of elements in it).
Should a client only access its own objects or all? If the former, I'd
do one map per client, which would reduce the number of entries in each
of those maps.
I have implemented a piece of code now that bascially means I send the
client a pointer to a struct
Didn't you get enough answers that told you to _never_ send a pointer?
Instead of your MyObject pointers you now transfer ObjectHolder
pointers, which doesn't really improve the situation.
which looks like:

struct ObjectHolder {
unsigned long signature;
MyObject* object;
};

And when they make a call I do this (basically):

ObjectHolder objectHolder = (ObjectHolder*) message.objectId;
if (objectHolder && objectHolder->signature ==
this->clientSignature) {

MySuperObject* superObject =
dynamic_cast<MySuperObject*>(objectHolder->object);
if (superObject) superObject->doAction(message.data);

}
The above code suffers from the same problem as the orignal code. If the
client sends garbage, your server will crash, because the pointer
points "into outer space". Note that this is not the same as a null
pointer, so your check doesn't grab that situation. Further,
transfering your pointer as a long isn't portable. On many 64 bit
platforms, a long is 32 bit, but a pointer is 64 bit.
The struct has an unsigned long in it which is basically a magic
string, and if this checks out it tells me the client owns the object
holder, and that it is indeed an object holder. From there I cast the
MyObject into MySuperObject (which is now allowed whereas I never
actually passed this pointer back and forth).

Of course, there is the very slim chance that if a client passes in a
rouge ObjectHolder pointer (objectId), there could conincedentally be
a 4 byte value matching the "signature" in question at the address of
the rogue pointer, but this has to be millions to one.
There is a much bigger chance that your client passes an invalid pointer
value that makes your program try to access memory that doesn't belong
to it. And on most modern OSs, this results in the kernel terminating
your program immediately.
Can you see any real problems with this? If a rogue ObjectHolder
pointer was passed, surely the signature should show it to be rogue?

I just think that on a server app which will be processing bucket
loads of these messages, looking up in a map for every message will be
a massive performance drain.


As I have pointed out, you could use a vector instead, which means using
the id as index. This should not be noticably slower than directly
using the pointer. Removing objects could be a bit tricky, though, but
there is a variety of different possible solutions to that.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #17

P: n/a
Stefan Rupp wrote:
Good evening,

not a C++ related answer, but for the questioner a hint nevertheless!

Jamie Burns schrieb:
> I am writing a client / server application.

[...]
> Now, when a client requests for an object to be created, I pass
> back a pointer to the object (from server memory address scope) as
> a "long integer".


Assuming your clients communicates with your server via network:

Aside from the other good advice you got, please keep in mind that the
byteorder of any multibyte entity like a 32bit integer value you send
across the net might be different on the client and server side. For
example an Intel i386 based system has a different byteorder for 32bit
integers as e.g. a MC68000 based system.

However, there is the defined "network byte order", into and out of
which values can be translated for purposes of sending data across
networks in heterogenous environments. The keywords you need to search
for are: htonl and ntohl!


Though what you say is correct, it doesn't seem very relevant for the
question, since the client is not doing anything with the received
value other than sending it back to the server it came from.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #18

P: n/a
Good afternoon,

Rolf Magnus schrieb:
Though what you say is correct, it doesn't seem very relevant for the
question, since the client is not doing anything with the received
value other than sending it back to the server it came from.


If the pointer is the only data sent between Server and Client, yes.
But I assume there is other data to be sent across the network where the
pointer serves only as the ID (where a logical ID would certainly server
better as all posters agree). For the other data the byte order may
play an important role, except if the data is sent as a byte stream like
strings. Any kind of numerical value with more than 8 bits needs to be
converted into and out of network byte order before sending through the
network (or after receiving it, respectilvely).

Regards,
Stefan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #19

P: n/a
"Jamie Burns" <se*****@email.com> writes:

|> Yes, this is a good idea, but I am concerned about performance. The
|> idea in sending the pointer was to reduce overhead when a client
|> makes a call on an object. How fast is performing a lookup using a
|> map in comparison to casting a pointer? Each process can have a lot
|> of server objects (thus the map would have to be efficient when has
|> a lot of elements in it).

|> I have implemented a piece of code now that bascially means I send
|> the client a pointer to a struct which looks like:

|> struct ObjectHolder {
|> unsigned long signature;
|> MyObject* object;
|> };

|> And when they make a call I do this (basically):

|> ObjectHolder objectHolder = (ObjectHolder*) message.objectId;
|> if (objectHolder && objectHolder->signature == this->clientSignature) {

|> MySuperObject* superObject =
|> dynamic_cast<MySuperObject*>(objectHolder->object);
|> if (superObject) superObject->doAction(message.data);
|>
|> }

|> The struct has an unsigned long in it which is basically a magic
|> string, and if this checks out it tells me the client owns the
|> object holder, and that it is indeed an object holder. From there I
|> cast the MyObject into MySuperObject (which is now allowed whereas I
|> never actually passed this pointer back and forth).

Who cares? If the client sends an invalid pointer, you might very well
get a core dump.

Letting pointers escape from a process, and hoping to use them later,
simply doesn't work. Period. It's a bad idea, and you don't want to do
it.

|> Of course, there is the very slim chance that if a client passes in
|> a rouge ObjectHolder pointer (objectId), there could conincedentally
|> be a 4 byte value matching the "signature" in question at the
|> address of the rogue pointer, but this has to be millions to one.

And there is an almost certainty that the client will, at one point or
another, return something which doesn't point to valid memory, and
causes your server to crash. Immediately invalidating all of the
pointers in all of the clients, so that further client requests will
cause the restarted server to crash, ad infinitum.

|> Can you see any real problems with this? If a rogue ObjectHolder
|> pointer was passed, surely the signature should show it to be rogue?

Just that it doesn't work.

|> I just think that on a server app which will be processing bucket
|> loads of these messages, looking up in a map for every message will
|> be a massive performance drain.

And marshalling and demarshalling won't. And the network itself won't.

Who are you kidding?

--
James Kanze mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #20

P: n/a
Peter Koch Larsen wrote:
<snip>
a) use a hash_map. Not standard yet, but it very soon will be. Lookup
is O(1) amortized.

<snip>

Big-O notation is supposed to tell you the worst case. (Big-omega is
used for the best case.) The worst case is, unfortunately, that all
the entries fall into the same hash bucket and lookup is O(n).
Amortisation makes no difference.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #21

P: n/a
Stefan Rupp wrote:
<snip>
However, there is the defined "network byte order", into and out of
which values can be translated for purposes of sending data across
networks in heterogenous environments. The keywords you need to search
for are: htonl and ntohl!


The design of htonl and ntohl is thoroughly wrong-headed. First, the
names suggest that they work on longs when actually they must work on
32-bit integers (similarly htons and ntohs work on 16-bit integers,
not short). Second, they can't be implemented on architectures that
have trap values for integers. Third, they require the caller to
read and write the network-ordered integers into and out of buffers
as 32-bit values, which is impossible if the value is not properly
aligned. (This last is not an issue in TCP/IP, which is what they
were designed for, since all TCP/IP header fields are aligned.)

Portable conversion functions that deal with binary formats should
read and write arrays of bytes. (Even that is problematic if you're
aiming for complete portability, since a byte may have more than 8
bits.)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #22

P: n/a
Ben Hutchings <do**************@bwsint.com> writes:
Big-O notation is supposed to tell you the worst case. (Big-omega is
used for the best case.)
Not so. To say 'f is O(g)' means that for large enough n, f(n) <=
g(n). (And when giving the name of an algorithm we normally mean the
time taken by that algorithm.) You can say

In the best case, quicksort is O(n log n) in the num. of elements

In the best case, quicksort is O(n ** 2) (also true)

In the worst case, quicksort is O(n ** 2)

In the worst case, quicksort is O(n ** n ** n ** 99)

To say 'f is Omega(g)' means that g is O(f), in other words for large
enough n, f(n) >= g(n). So

Quicksort is Omega(1) (yes, it takes constant time or worse)

Quicksort is Omega(n log n) (also true)

In the worst case, quicksort is Omega(n ** 2).

However there is an informal convention that when quoting big-Os you
quote the best one you can, so saying

Algorithm X takes time O(g(n)) where n is the input size

is, by reading between the lines, saying that it is both O(g(n)) and
Omega(g(n)), because you wouldn't bother to give a worse big-O than is
possible. Otherwise people would go around saying 'quicksort is
O(n**99)' and it would all get a bit silly.
The worst case is, unfortunately, that all the entries fall into the
same hash bucket and lookup is O(n).


Indeed. For such a degenerate hash lookup is O(n) - so it's no worse
than linear in the number of elements - but it is also Omega(n) - so
no better.

--
Ed Avis <ed@membled.com>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #23

P: n/a
Ed Avis wrote:
Ben Hutchings <do**************@bwsint.com> writes:
Big-O notation is supposed to tell you the worst case. (Big-omega is
used for the best case.)
Not so.


My wording was sloppy; I really meant "upper bound" and "lower bound"
which might not actually be reached. However, I realise that even that
is not quite right since they are asymptotic bounds.
To say 'f is O(g)' means that for large enough n, f(n) <= g(n).
That should be f(n) <= k.g(n) for some constant k.
(And when giving the name of an algorithm we normally mean the
time taken by that algorithm.) You can say

In the best case, quicksort is O(n log n) in the num. of elements

In the best case, quicksort is O(n ** 2) (also true)

In the worst case, quicksort is O(n ** 2)

In the worst case, quicksort is O(n ** n ** n ** 99)

<snip>

I see what you mean and I accept that you're right, but it seems
misleading to me to give an asymptotic upper bound that's based to the
best case. It doesn't seem to represent any kind of upper bound at
all.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #24

P: n/a
On Tue, 27 Jan 2004 06:00:24 -0500, Ed Avis wrote:
However there is an informal convention that when quoting big-Os you
quote the best one you can, so saying

Algorithm X takes time O(g(n)) where n is the input size

is, by reading between the lines, saying that it is both O(g(n)) and
Omega(g(n)), because you wouldn't bother to give a worse big-O than is
possible. Otherwise people would go around saying 'quicksort is
O(n**99)' and it would all get a bit silly.


Why not say that the quoted complexity is asymptotically tight bound or
not?
Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #25

P: n/a
Ed Avis wrote:
To say 'f is O(g)' means that for large enough n, f(n) <= g(n).


No, this is wrong. To say 'f is O(g)' means that there exist
constants N and C such that for all n > N, |f(n)| <= C * |g(n)|.

You can see that your definition is trivially wrong because it
claims that (n + 1) is not O(n).
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #26

P: n/a
Errr, guy's, I appreciate the thoughts on this, but look, what does all that
math mean to mere mortals like myself?!

:o)

I realise that a hashmap is the more elegant solution, but compared to
simply casting a memory address it is still going to be really slow right
(is that what the math proved)? And I think I have solved the dangers of
passing pointers around by using the magic string lookup.

Interestingly, I just did a quick test to see which is faster (given I am
simply casting now, not using hashmaps):

for (xx=0;xx<100000;xx++) {
rDerived* derived = dynamic_cast<rDerived*>(remoteObject->object);
if (derived) derived->setValue(message.data.messageSetInt.value);
}

against:

for (xx=0;xx<100000;xx++) {
if (typeid(remoteObject->object) == typeid(rDerived*)) ((rDerived*)
remoteObject->object)->setValue(message.data.messageSetInt.value);
}

And the latter blew the former out of the wayer (typeid() with a C style
cast was 94 times faster in my test than dynamic_cast).

Whoa.

Jamie.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #27

P: n/a
Jamie Burns wrote:

Interestingly, I just did a quick test to see which is faster (given I am
simply casting now, not using hashmaps):

for (xx=0;xx<100000;xx++) {
rDerived* derived = dynamic_cast<rDerived*>(remoteObject->object);
if (derived) derived->setValue(message.data.messageSetInt.value);
}

against:

for (xx=0;xx<100000;xx++) {
if (typeid(remoteObject->object) == typeid(rDerived*)) ((rDerived*)
remoteObject->object)->setValue(message.data.messageSetInt.value);
}

And the latter blew the former out of the wayer (typeid() with a C style
cast was 94 times faster in my test than dynamic_cast).


IMHO that number (94) is still too high. Are you sure you didn't measure
how well the optimizer can optimize version 1 against optimizing
version 2.
--
Karl Heinz Buchegger
kb******@gascad.at

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #28

P: n/a
Ben Hutchings <do**************@bwsint.com> wrote in message
news:<sl*****************************@tin.bwsint.c om>...
Ed Avis wrote:
(And when giving the name of an algorithm we normally mean the time
taken by that algorithm.) You can say In the best case, quicksort is O(n log n) in the num. of elements In the best case, quicksort is O(n ** 2) (also true) In the worst case, quicksort is O(n ** 2) In the worst case, quicksort is O(n ** n ** n ** 99) <snip>

I see what you mean and I accept that you're right, but it seems
misleading to me to give an asymptotic upper bound that's based to the
best case. It doesn't seem to represent any kind of upper bound at
all.


Yes and no. Normally, the two interesting values are typical or
average, and worse case. But what do you say about quicksort. The
worst case is O(n^2). The best case is O(n ln n). I don't think that
we know how to calculate the typical or average, but empirically, I
think it has been established that quicksort usually performs fairly
close to its best case. No guarantees, but useful information anyway.

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #29

P: n/a
Jamie Burns wrote:
Errr, guy's, I appreciate the thoughts on this, but look, what does all that
math mean to mere mortals like myself?!

:o)

I realise that a hashmap is the more elegant solution, but compared to
simply casting a memory address it is still going to be really slow right
(is that what the math proved)?
It didn't *prove* anything, but the point of all that was that a hash
table lookup can be slow, taking time proportional to the number of
entries.

However, provided that the hash table implementation increases the
number of buckets in proportion to the number of entries, which I think
all hash_map implementations do, and ignoring cache effects which may
come into play if the table grows very large, the *average* time taken
for a hash lookup will be about the same time no matter how many
entries are in the table, and not very long at all.
And I think I have solved the dangers of passing pointers around by
using the magic string lookup.
What does that mean?
Interestingly, I just did a quick test to see which is faster (given I am
simply casting now, not using hashmaps):

for (xx=0;xx<100000;xx++) {
rDerived* derived = dynamic_cast<rDerived*>(remoteObject->object);
if (derived) derived->setValue(message.data.messageSetInt.value);
}

against:

for (xx=0;xx<100000;xx++) {
if (typeid(remoteObject->object) == typeid(rDerived*)) ((rDerived*)
remoteObject->object)->setValue(message.data.messageSetInt.value);
}

And the latter blew the former out of the wayer (typeid() with a C style
cast was 94 times faster in my test than dynamic_cast).


The latter doesn't do what you think it does. The typeid() of a
pointer doesn't depend on what it's pointing to. The condition in the
if statement should be:

typeid(*remoteObject->object) == typeid(rDerived)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #30

P: n/a
"Jamie Burns" <se*****@email.com> wrote in message
news:<bv*******************@news.demon.co.uk>...
Errr, guy's, I appreciate the thoughts on this, but look, what does
all that math mean to mere mortals like myself?!
It means that you have to know what you are trying to do before you try
to do it.
:o) I realise that a hashmap is the more elegant solution, but compared to
simply casting a memory address it is still going to be really slow
right (is that what the math proved)? And I think I have solved the
dangers of passing pointers around by using the magic string lookup.


The difference is that the hashmap will work. Passing a long around,
and casting it to a pointer whenever you feel like accessing memory,
won't. After that, of course, the quality of the hash function will
affect performance. As others have mentionned, however, if only one
process is doing all of the object creation (and id assignment), there
are fairly simple solutions which will allow using an std::vector (which
is nothing other than a very efficient map size_t->T, for a restricted
range of values on the size_t side).

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #31

P: n/a
Hello Jamie,

This problem is common and you can find literature discussing various
solutions in the client server community.

All of the viable solutions so far have discussed creating a mapping
function :

f(g(object) -> object

where g(object) is often called a "handle". This handle body idiom is
well established and you should consider using one of the solutions
already outline. Yes, you do incur a performance penalty for the added
safety. That is a tradeoff you need evaluate for your application;
but, that is the bottom line.

I just wanted to point you to one interesting alternative to the
mapping functions discussed for far : encryption. The general idiom is
:

encrypt ( this-is-a-valid-pointer + pointer ) -> handle
decrypt ( handle ) -> this-is-a-valid-pointer + pointer

If you don't recover this-is-a-valid-pointer then you don't use the
pointer.

Using this idiom you adjust the safety-vs-performance tradeoff quite
easily by choosing an appropriate encryption algorithm. One advantage
of this approach is that it doesn't require linear space overhead as
do the other handle-body approaches discussed so far. One disadvantage
is that it doesn't allow you to easily correct for server-side memory
management of the objects ( moving them around, etc) since you can't
readily adjust the mapping of handles you have already distributed.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jul 22 '05 #32

This discussion thread is closed

Replies have been disabled for this discussion.