 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Jamie Burns Guest
|
Posted: Thu Jan 22, 2004 9:04 am Post subject: Cast object from long in safe manner? |
|
|
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! ]
|
|
| Back to top |
|
 |
Patrik Stellmann Guest
|
Posted: Thu Jan 22, 2004 9:34 am Post subject: Re: Cast object from long in safe manner? |
|
|
| Quote: | 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).
|
|
| Back to top |
|
 |
Heinz Ozwirk Guest
|
Posted: Thu Jan 22, 2004 2:50 pm Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" schrieb im Newsbeitrag news:bunnoq$ba$1$8302bc10 (AT) news (DOT) 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! ]
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Fri Jan 23, 2004 9:47 am Post subject: Re: Cast object from long in safe manner? |
|
|
Jamie Burns wrote:
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Maciej Sobczak Guest
|
Posted: Fri Jan 23, 2004 9:50 am Post subject: Re: Cast object from long in safe manner? |
|
|
Hi,
Jamie Burns wrote:
| Quote: | I am writing a client / server application.
[...] |
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Gary Guest
|
Posted: Fri Jan 23, 2004 9:52 am Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" <sephana (AT) email (DOT) com> wrote
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Peter Koch Larsen Guest
|
Posted: Fri Jan 23, 2004 9:54 am Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" <sephana (AT) email (DOT) com> skrev i en meddelelse
news:bunnoq$ba$1$8302bc10 (AT) news (DOT) demon.co.uk...
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Fri Jan 23, 2004 10:01 am Post subject: Re: Cast object from long in safe manner? |
|
|
Jamie Burns wrote:
| Quote: | 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.
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Dhruv Guest
|
Posted: Fri Jan 23, 2004 10:16 am Post subject: Re: Cast object from long in safe manner? |
|
|
On Thu, 22 Jan 2004 04:04:42 -0500, Jamie Burns wrote:
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Jamie Burns Guest
|
Posted: Fri Jan 23, 2004 10:25 am Post subject: Re: Cast object from long in safe manner? |
|
|
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" <wansor42 (AT) gmx (DOT) de> wrote
| Quote: |
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! ]
|
|
| Back to top |
|
 |
Martijn Lievaart Guest
|
Posted: Fri Jan 23, 2004 10:27 am Post subject: Re: Cast object from long in safe manner? |
|
|
On Thu, 22 Jan 2004 04:04:42 -0500, Jamie Burns wrote:
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Kevin Cline Guest
|
Posted: Fri Jan 23, 2004 2:50 pm Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" <sephana (AT) email (DOT) com> wrote
| Quote: | 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;
| Quote: |
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! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Jan 23, 2004 9:05 pm Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" <sephana (AT) email (DOT) com> wrote
| Quote: | 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.
| Quote: | 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:kanze (AT) gabi-soft (DOT) 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! ]
|
|
| Back to top |
|
 |
Thomas Mang Guest
|
Posted: Fri Jan 23, 2004 9:08 pm Post subject: Re: Cast object from long in safe manner? |
|
|
Dhruv schrieb:
| Quote: |
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! ]
|
|
| Back to top |
|
 |
Peter Koch Larsen Guest
|
Posted: Sat Jan 24, 2004 1:03 pm Post subject: Re: Cast object from long in safe manner? |
|
|
"Jamie Burns" <sephana (AT) email (DOT) com> wrote
| Quote: | 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.
| Quote: |
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.
| Quote: |
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.
| Quote: |
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! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|