Share pointer between subprocesses - c++

I have a 64 bit application that creates 2 subprocesses (32 bit) via a popen2 implementation. Everything is written in C++.
I need the 2 subprocesses to access the same object in memory and I don't have a good idea about how to do this.
If I understand correctly, each subprocess will have a different memory map and therefore I can't just pass a memory address between the two.
Additional information: The target platform is Mac but I'm looking for an answer that is as platform independent as possible Mac specific answers are fine, I probably won't use this approach on other platforms. I simply don't know enough about using threads; I came down this route because the subprocesses must be 32 bit.

You can use shared memory concept. It means, that you allocate (using OS services) a memory, that will be visible by both subprocesses.
As wiki recoomends, you can use boost.interprocess to use shared memory on platform-independent level.

It's a difficult problem.
You are correct that each process has its own address space. Objects created by one process can't be accessed by another process.
It is possible to use shared memory, and place the objects there. One complication is that in general the shared memory segment will be mapped at different addresses into each process's address space. This means that you can't use pointers inside those object. This can be alleviated by working with indices instead of pointers.
Furthermore, if process A is 32-bit and process B is 64-bit, primitive types such as long can have different width. Thus when sharing data in such a scenario you need to use fixed-width types such as int32_t.
One final complication is synchronization: if a process can modify an object while another process is reading or modifying it, you'll need to introduces inter-process synchronization.

Related

Interprocess communication heap memory

Can heap memory be shared between 2 different processes? In boost interprocess documentation,there is a statement that managed heap memory does not create system wide resources
Nothing is foreseen in the C++ standard for shared memory between processes. In fact, each process runs in its own address space and manages its dynamic memory in that address space, so there is no way to share the "heap".
However, operating systems give you some means to share memory between processes. The best known way is the use of memory mapped files, which are supported across a wide range of OS, but in an OS specific way, so non portable. boost proposes a portable implementation which hides the OS specific part.
You may very well use the memory area obtained in this way for your objects. You could use placement new to instantiate objects. You could even create a custom allocator to create dynamic objects in this memory area.
However, this requires extra care, since you have to take into consideration IPC synchronisation to avoid races, and you need to remember that any pointer created by one process is garbage for the other process (since it runs in antoher, independent address space).

Sharing pointer across programs in C++

This is related to a previous post:
Allocating a large memory block in C++
I would like a single C++ server running that generates a giant matrix M. Then, on the same machine I would like to run other programs that can contact this server, and get the memory address for M. M is read only, and the server creates it once. I should be able to spawn a client ./test and this programs should be able to make read only access to M. The server should always be running, but I can run other programs like ./test at anytime.
I don't know much about C++ or OS, what is the best way to do this? Should I use POSIX threads? The matrix is a primitive type (double, float etc), and all programs know its dimensions. The client programs require the entire matrix, so I don't want latency from mem copy from the server to the client, I just want to share that pointer directly. What are my best options?
One mechanism of inter-process communication you could definitely use for sharing direct access to you matrix M is shared memory. It means that the OS lets multiple processes access a shared segment in the memory, as if it was in their address space, by mapping it for each one requesting. A solution that answers all your requirements, and is also cross-platform is boost::interprocess. It is a thin portable layer that wraps all of the necessary OS calls. See a working example right here in the docs.
Essentially, your server process just needs to create an object of type boost::interprocess::shared_memory_object, providing the constructor with a name for the shared segment. When calling its truncate() method, the OS will look for a large enough segement in the address space of this server process. From this moment, any other process can create an object of the same type and provide the same name. Now it too has access to the exact same memory. No copies involved.
If for some reason you are unable to use the portable Boost libraries, or for other reason want to restrict the supported platform to Linux, use the POSIX API around the mmap() function. Here's the Linux man page. Usage is basically not far from the Boost pipeline described above. you create the named segment with shm_open() and truncate with ftruncate(). From there onwards you receive the mapped pointer to this allocated space by calling mmap(). In simpler cases where you'll only be sharing between parent and child processes, you can use this code example from this very website.
Of course, no matter what approach you take, when using a shared resource, make sure to synchronize read/writes properly so to avoid any race condition -- as you would have done in the scenario of multiple threads of the same process.
Of course other programs cannot access the matrix as long as it is in the "normal" process memory.
Without questioning the design approach: Yes, you have to use shared memory. Lookup functions like shmget(), shmat() etc. Then you don't need to pass the pointer to another program (which would not work, actually), you simply use the same file in ftok() everywhere to get access to the shared memory.

Is shared virtual memory used when multiple processes read a file using file pointer in Linux?

I wrote a C++ program which read a file using file pointer. And I need to run multiple process at the same time. Since the size of file can be huge (100MB~), to reduce memory usage in multiple processes, I think I need use shared memory. (For example IPC library like boost::interprocess::shared_memory_object)
But does it really need? Because I think if multiple processes read same file, then virtual memory of each processes mapped to same physical memory of file thru page table.
I read a Linux doc and they said,
Shared Virtual Memory
Although virtual memory allows processes to have separate (virtual)
address spaces, there are times when you need processes to share
memory. For example there could be several processes in the system
running the bash command shell. Rather than have several copies of
bash, one in each processes virtual address space, it is better to
have only one copy in physical memory and all of the processes running
bash share it. Dynamic libraries are another common example of
executing code shared between several processes. Shared memory can
also be used as an Inter Process Communication (IPC) mechanism, with
two or more processes exchanging information via memory common to all
of them. Linux supports the Unix TM System V shared memory IPC.
Also, wiki said,
In computer software, shared memory is either
a method of inter-process communication (IPC), i.e. a way of exchanging data between programs running at the same time. One process
will create an area in RAM which other processes can access, or
a method of conserving memory space by directing accesses to what would ordinarily be copies of a piece of data to a single instance
instead, by using virtual memory mappings or with explicit support of
the program in question. This is most often used for shared libraries
and for XIP.
Therefore, what I really curious is that does shared virtual memory supported by OS level or not?
Thanks in advance.
Regarding your first question - if you want your data to be accessible by multiple processes without duplication you'll definitely need some kind of a shared storage.
In C++ I'd surely use boost's shared_memory_object. That's a valid option to share (large) data among processes and it has good documentation with examples (http://www.boost.org/doc/libs/1_55_0/doc/html/interprocess/sharedmemorybetweenprocesses.html).
Using mmap() is a more low-level approach usually used in C. To use it as an IPC you'll have to make the mapped region shared. From http://man7.org/linux/man-pages/man2/mmap.2.html:
MAP_SHARED
Share this mapping. Updates to the mapping are visible to
other processes that map this file, and are carried
through to the underlying file. The file may not actually
be updated until msync(2) or munmap() is called.
Also on that page there's an example of mapping a file to shared memory.
In either case there are at least two things to remember:
You need synchronization if there are multiple processes that modify the shared data.
You can't use pointers, only offsets from the beginning of the mapped region.
Here's an explanation from the boost docs:
If several processes map the same file/shared memory, the mapping address will be surely different in each process. Since each process might have used its address space in a different way (allocation of more or less dynamic memory, for example), there is no guarantee that the file/shared memory is going to be mapped in the same address.
If two processes map the same object in different addresses, this invalidates the use of pointers in that memory, since the pointer (which is an absolute address) would only make sense for the process that wrote it. The solution for this is to use offsets (distance) between objects instead of pointers: If two objects are placed in the same shared memory segment by one process, the address of each object will be different in another process but the distance between them (in bytes) will be the same.
Regarding the OS support - yes, shred memory is an OS specific feature.
In Linux mmap() is actually implemented in kernel and modules and can be used to transfer data between user and kernel-space.
Windows also has it's specifics:
Windows shared memory creation is a bit different from portable shared memory creation: the size of the segment must be specified when creating the object and can't be specified through truncate like with the shared memory object. Take in care that when the last process attached to a shared memory is destroyed the shared memory is destroyed so there is no persistency with native windows shared memory.
Your question doesn't make sense.
I think I need use shared memory. (For example IPC library like boost::interprocess::shared_memory_object).
If you use shared memroy, the memory is shared.
I think if multiple processes read same file, then virtual memory of each processes mapped to same physical memory of file thru page table.
Now you're talking about memory-mapped I/O. It isn't the same thing. However more probably it is what you need in this situation.

How to choose a fixed address for shared memory mapping

I would like to use shared memory between several processes, and would like to be able to keep using raw pointers (and stl containers).
For this purpose, I am using shared memory mapped at a fixed address:
segment = new boost::interprocess::managed_shared_memory(
boost::interprocess::open_or_create,
"MySegmentName",
1048576, // alloc size
(void *)0x400000000LL // fixed address
);
What is a good strategy for choosing this fixed address? For example, should I just use a pretty high number to reduce the chance that I run out of heap space?
This is a hard problem. If you are forking a single program to create children, and only the parent and the children will use the memory segment, just be sure to map it before you fork. The children will automatically inherit the mapping from their parent and there's no need to use a fixed address.
If you aren't, then the first thing to consider is whether you really need to use raw STL containers instead of the boost interprocess containers. That you're already using boost interprocess to allocate the shared memory segment suggests you don't have any problem using boost, so the only advantage I can think of to using STL containers would be so you don't have to port existing code. Keep in mind that for it to work with fixed addresses, the containers and what they contain pointers to (assuming you're working with containers of pointers) will need to be kept in the shared memory space.
If you're certain that it's what you want, you'll have to figure out some method for them to negotiate an address. Keep in mind that the OS is allowed to reject your desired fixed memory address. It will reject an address if the page at that address has already been mapped into memory or allocated. Because different programs will have allocated different amounts of memory at different times, which pages are available and which are unavailable will vary across your programs.
So you need for the programs to gain consensus on a memory address. This means that several addresses might have to be tried and rejected. If it's possible that sometime after startup a new program will become interested, the search for consensus will have to start over again. The algorithm would look something like this:
Program A proposes memory address X to all other programs.
The other programs respond with true or false to indicate whether the memory mapping at address X succeeded.
If program A receives any false responses, goto #1.
Program A sends a message to the other programs letting them know the address has been validated and maybe used.
If a new app becomes interested in the data, it must notify program A it would like an address.
Program A then has to tell all the other programs to stop using the data and goto #1.
To come up with what addresses A should propose, you could have A map a non-fixed memory segment, see what address it's mapped at, and propose that address. If it's unsatisfactory, map another segment and propose it instead. You will need to unmap the segments at some point, but you can't unmap them right away because if you unmap then remap a segment of the same size chances are the OS will give you the same address back over and over. Keep in mind that you may never reach consensus; there's no guarantee that there's a large enough segment at a common location across all the processes. This could happen if your programs all independently use almost all memory, say if they are backed up by a ton of swap (though if you care enough about performance to use shared memory hopefully you are avoiding swap).
All of the above assumes you're in a relatively constrained address space. If you're on 64-bit, this could work. Most computers' RAM + swap will be far less than what's allowed by 64-bits, so you could put map the memory at a very far out fixed address that all processes are unlikely to have mapped already. I suggest at least 2^48, since current 64-bit x86 processors don't each beyond that range (despite pointers being 64-bits, you can only plug in as much RAM as allowed by 48-bits, still a ton at the time of this writing). Although there's no reason a smart heap allocator couldn't take advantage of the vastness of the address space to reduce its bookkeeping work, so to be truly robust you would still need to build consensus. Keep in mind that you will at least want the address to be configurable -- even if we don't have that much memory anytime soon, between now and then someone else might have the same idea and pick your address.
To do the bidirectional communication you could use any of sockets, pipes, or another shared memory segment. Your OS may provide other forms of IPC. But strongly consider that you are probably now introducing more complexity than you would have to deal with if you just used the boost interprocess containers ;)
Read the address from a configuration file. That will allow easy experimentation, and make it easy to change the address as the circumstances change.
Don't use hard-coded absolute addresses as shared memory area for security reasons, even when you don't uses forks or threads. This bypasses all ASLR protections. It enables any attacker predictable locations in the process' address space. It is pretty easy to search for such hard-coded pointers in a binary.
You've been choosen by http://reversingonwindows.blogspot.sg/2013/12/hardcoded-pointers.html as example how to make software less secure, bypassing ASLR.
The 2nd bad example is in the boost library.
The address space needs to be negotiated between the communicating parties at run-time.
My solution:
The initialising program allows the system to select an appropriate segment address. This address is written to disc and retrieved for use by subsequent programs as required.
Caveats:
I am using 64 bit fedora 21 with Kdevelop 4.7 and find that 'void*' is 64 bits long. Writing to disc of the segment head address involves
sprintf(bu, "%p", pointer); and writing a text file:
Recovery reads this file and decodes the hex number as a 'long long' value. This is returned to the caller where it is cast as (void*)
I have also found that grouping all the access routines into a single folder
above the level of the individual processes (each as a project in its own right) has helped save my sanity at the expense of a single aberrant '#include' in the process files
David N Laine

How to retrieving variable value in C++ if you know the variable address

Greetings,
I have recently started to code in C++ and have come across a problem to which I was unable to find the answer, so I thought maybe somebody else might know the answer.
Is it possible to retrieve a variable value from another program if you know a variable address? Imagine that I have a memory address displayed in a program, something like: 0x7fff5fbff758 and I would like (in my own program which is not related to the first one) to get the value stored in that memory address.
Is that possible? If so, could somebody please explain me how.
Thank you in advance.
On today operating systems, the programs handle virtual addresses, not physical ones. Shortly, a specific address for one programs will not point to the same physical location for other programs.
To do what you want on modern operating systems, you can, for instance, set up a shared memory location.
But there is a lot of easier way to pass a value from one program to another.
If you are just wondering that out of curiosity, that's a good question, you can look at what "virtual memory" is.
C++ has no comment on this, one way or the other. It depends entirely on the platform on which your program is running. If you're using Windows, for example, you can use the ReadProcessMemory() function to read the memory of another process (assuming you have adequate permissions).
Note that modern operating systems are designed to protect processes from interfering with each other. One of the ways they do this is by giving each process its own address space. Processes can't access memory outside this space without using special APIs.
It is possible, but it is OS-specific (there is no common C support for it). In general, your second program needs to have the permission that debugger has, and use the same kind of OS calls that a debugger uses.
On most modern general-purpose OSes (Windows, Linux, etc), you cannot do that. Different programs run in different processes, and each process has its very own memory space. Address 0x7fff5fbff758 in one probably points to a very different place in RAM than address 0x7fff5fbff758 in another (if that address even exists in the other).
This is why modern OSes have interprocess communications mechanisims, like pipes, shared memory, COM, etc.
Edit: This obsolete, because the question has changed.
If you know the type of the variable, its possible.
For an int variable, you need to insert lines like
int* addr = (int*)0x7fff5fbff758;
std::cout << *addr << std::endl;
somewhere in the affected program.
Accessing the variable from a different program is generally not easily done in a modern operating system, each process has it's own address space so the same address in different processes may map to different physical memory location.
It depends on the OS, for example in linux you need to trace a process if you want to do it from a different process, see man ptrace. You can read the data in this case with PTRACE_PEEKDATA.