[Interprocess] Possible bug in shared memory on FreeBSD 8.0

I've been happily using Boost.Interprocess to create shared memory regions under FreeBSD 7.2, however, I am having issues on FreeBSD 8.0 pre-release. I can reproduce the problem with Boost 1.39.0 and the svn trunk. The source of the problem appears to be that Boost.Interprocess calls lseek on a file descriptor returned by shm_open, but the results of such an lseek are undefined. Below, I explain further how I came to this conclusion. If you run the program I've appended to the end of this email, the constructor for managed_shared_memory throws an interprocess_exception with error code 29 which is Illegal Seek on FreeBSD. A little bit of system call tracing and debugging reveals that the offending seek is in mapped_region.h:447 (in svn revision 55512). However, digging around, it appears that lseek's behavior on file descriptors for shared memory regions is undefined (See http://www.opengroup.org/onlinepubs/000095399/functions/lseek.html for what IEEE 1003.1 standard has to say about this.) I've confirmed that FreeBSD 7.2 allowed such seeks but 8.0 does not by looking at the kernel source code. For what it's worth AIX 6.1 does not allow such seeks either (see http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.ai...). Could someone advise me on what the correct fix for this bug is? I'd be glad to implement it, but I'm not sure what the right fix ought to be. #include <iostream> #include <string> #include <exception> #include <boost/interprocess/managed_shared_memory.hpp> namespace bip = boost::interprocess; int main(const int argc, const char *argv[]) { bool error = true; std::string shmName("testShmRegion"); bip::shared_memory_object::remove(shmName.c_str()); try { std::auto_ptr<bip::managed_shared_memory> segment(new bip::managed_shared_memory(bip::create_only, shmName.c_str(), 12345)); error = false; } catch(const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } if(!error) { std::cout << "Shm allocated successfully." << std::endl; } return 0; } Manish

Manish Vachharajani escribió:
I've been happily using Boost.Interprocess to create shared memory regions under FreeBSD 7.2, however, I am having issues on FreeBSD 8.0 pre-release. I can reproduce the problem with Boost 1.39.0 and the svn trunk. The source of the problem appears to be that Boost.Interprocess calls lseek on a file descriptor returned by shm_open, but the results of such an lseek are undefined. Below, I explain further how I came to this conclusion.
You are right, it's undefined, but it usually works. However, I can't find a way to obtain the size of a shared memory segment using POSIX, if you could fin a way to do it it would be really nice.
I've confirmed that FreeBSD 7.2 allowed such seeks but 8.0 does not by looking at the kernel source code. For what it's worth AIX 6.1 does not allow such seeks either (see http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.ai...).
Interesting, maybe that's the reason this has not appeared sooner.
Could someone advise me on what the correct fix for this bug is? I'd be glad to implement it, but I'm not sure what the right fix ought to be.
No idea at all, maybe the fix is particular to each system, maybe we could open the segment as a normal file in the filesystem (if shared memory is mounted somewhere, I don't know if that's the case) and try to obtain its size. "ls" command displays the size, so there must be a why to obtain the size of a segment. Best, Ion

Ion Gaztañaga wrote:
Manish Vachharajani escribió:
I've been happily using Boost.Interprocess to create shared memory regions under FreeBSD 7.2, however, I am having issues on FreeBSD 8.0 pre-release. I can reproduce the problem with Boost 1.39.0 and the svn trunk. The source of the problem appears to be that Boost.Interprocess calls lseek on a file descriptor returned by shm_open, but the results of such an lseek are undefined. Below, I explain further how I came to this conclusion.
You are right, it's undefined, but it usually works. However, I can't find a way to obtain the size of a shared memory segment using POSIX, if you could fin a way to do it it would be really nice.
fstat() ? Cheers, Ian McCulloch

Ian McCulloch escribió:
Ion Gaztañaga wrote:
Manish Vachharajani escribió:
I've been happily using Boost.Interprocess to create shared memory regions under FreeBSD 7.2, however, I am having issues on FreeBSD 8.0 pre-release. I can reproduce the problem with Boost 1.39.0 and the svn trunk. The source of the problem appears to be that Boost.Interprocess calls lseek on a file descriptor returned by shm_open, but the results of such an lseek are undefined. Below, I explain further how I came to this conclusion. You are right, it's undefined, but it usually works. However, I can't find a way to obtain the size of a shared memory segment using POSIX, if you could fin a way to do it it would be really nice.
fstat() ?
I should have read this before, I've lost some precious time searching until I've found fstat ;-) It's required to work with shared memory: http://www.opengroup.org/onlinepubs/000095399/functions/fstat.html I'll fix it ASAP, Ion

Wow, thanks for the quick fix! However, there seems to still be a problem in write_whole_device in detail/managed_open_or_create_impl.hpp. The function is using ::lseek and ::write to clear the file to all zeros. However, according to IEEE 1003.1 read and write are also not defined for shared memory regions (see http://www.opengroup.org/onlinepubs/000095399/functions/write.html) and are indeed not supported in FreeBSD 8.0 (e.g., read/write will return EOPNOTSUPP). Is there a good reason why Interprocess doesn't grab a mapped_region and clear the shared memory contents this way? Do some systems require one to write the file for things to work? Also, while we are discussing FreeBSD 8.0 and shared memory, it appears that in 8.0 shared memory objects are no longer required to appear on the filesystem (or at least they don't appear there for me and removing the BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES define on FreeBSD 8.0 doesn't break anything, still successfully allocates the shared memory region, and leaves no trace in /tmp after shm_open). So, the question is, for FreeBSD 8.0 would it be worth disabling this define? It would prevent Boost.Interprocess from unnecessarily creating directories in /tmp only not to use them. It only leads to one complication which I describe below. Otherwise the fix is simple, see the attached patch which appears to work correctly for me under 7.2 and, neglecting the problem described in the first paragraph, seems ok on 8.0 as well. The one complication relates to binary compatibility between FreeBSD 8 and prior FreeBSDs. With the patch, if a binary, call it A, is compiled on FreeBSD 8.0 it will not be able to find any shared memory regions allocated by a binary, call it B, compiled on an earlier FreeBSD but running on FreeBSD 8.0. This is because the name boost computes for the memory region will be different, i.e., /foobar in the 8.0 case and /tmp/boost_interproces/.../foobar in the other. Does this matter? Seems to be an extreme corner case. Manish 2009/8/11 Ion Gaztañaga <igaztanaga@gmail.com>:
Ian McCulloch escribió:
Ion Gaztañaga wrote:
Manish Vachharajani escribió:
I've been happily using Boost.Interprocess to create shared memory regions under FreeBSD 7.2, however, I am having issues on FreeBSD 8.0 pre-release. I can reproduce the problem with Boost 1.39.0 and the svn trunk. The source of the problem appears to be that Boost.Interprocess calls lseek on a file descriptor returned by shm_open, but the results of such an lseek are undefined. Below, I explain further how I came to this conclusion.
You are right, it's undefined, but it usually works. However, I can't find a way to obtain the size of a shared memory segment using POSIX, if you could fin a way to do it it would be really nice.
fstat() ?
I should have read this before, I've lost some precious time searching until I've found fstat ;-)
It's required to work with shared memory:
http://www.opengroup.org/onlinepubs/000095399/functions/fstat.html
I'll fix it ASAP,
Ion _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Manish Vachharajani escribió:
Wow, thanks for the quick fix! However, there seems to still be a problem in write_whole_device in detail/managed_open_or_create_impl.hpp. The function is using ::lseek and ::write to clear the file to all zeros. However, according to IEEE 1003.1 read and write are also not defined for shared memory regions (see http://www.opengroup.org/onlinepubs/000095399/functions/write.html) and are indeed not supported in FreeBSD 8.0 (e.g., read/write will return EOPNOTSUPP). Is there a good reason why Interprocess doesn't grab a mapped_region and clear the shared memory contents this way? Do some systems require one to write the file for things to work?
You are lucky because right now I'm working on Interprocess, that's why changes are happening so fast. This will change tomorrow, because I have other pending tasks, so let's do the work ;-) I've uploaded to trunk a change I've done to remove the call to write_whole_device, which called ::lseek and ::write and it's only needed in windows, since truncation in windows does not zero fill the memory if the new size is bigger. Can you test it?
Also, while we are discussing FreeBSD 8.0 and shared memory, it appears that in 8.0 shared memory objects are no longer required to appear on the filesystem (or at least they don't appear there for me and removing the BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES define on FreeBSD 8.0 doesn't break anything, still successfully allocates the shared memory region, and leaves no trace in /tmp after shm_open). So, the question is, for FreeBSD 8.0 would it be worth disabling this define? It would prevent Boost.Interprocess from unnecessarily creating directories in /tmp only not to use them. It only leads to one complication which I describe below. Otherwise the fix is simple, see the attached patch which appears to work correctly for me under 7.2 and, neglecting the problem described in the first paragraph, seems ok on 8.0 as well.
I've just seen this: http://www.freebsd.org/cgi/query-pr.cgi?pr=115619 It seems that POSIX shared memory is now more similar to linux, so I've just changed workaround.hpp to avoid filesystem-based shm flag.
The one complication relates to binary compatibility between FreeBSD 8 and prior FreeBSDs. With the patch, if a binary, call it A, is compiled on FreeBSD 8.0 it will not be able to find any shared memory regions allocated by a binary, call it B, compiled on an earlier FreeBSD but running on FreeBSD 8.0. This is because the name boost computes for the memory region will be different, i.e., /foobar in the 8.0 case and /tmp/boost_interproces/.../foobar in the other. Does this matter? Seems to be an extreme corner case.
Yes, there is so ABI problem there but that will affect also programs not using interprocess. Older FreeBSD using hard-coded filesystem won't work on FreeBSD 8. Best, Ion

You are lucky because right now I'm working on Interprocess, that's why changes are happening so fast. This will change tomorrow, because I have other pending tasks, so let's do the work ;-)
Ok, sounds good to me :)
I've uploaded to trunk a change I've done to remove the call to write_whole_device, which called ::lseek and ::write and it's only needed in windows, since truncation in windows does not zero fill the memory if the new size is bigger. Can you test it?
Works for me under 8.0 on my small test code. Minor bug on 7.2, the test in workaround.hpp should be (__FreeBSD__ < 8), not >=8. Otherwise, on 7.2 we don't use the filesystem based naming and things break. It seems we'd want the opposite, filesystem naming on anything less than 8, no filesystem naming on anything greater. I'll let you know if it works in the main code in which I use this stuff later today, after I patch the changes you've made into our production version of boost. Do you know if this stuff will make it into boost 1.40.0 or is it too late for that?
I've just seen this:
http://www.freebsd.org/cgi/query-pr.cgi?pr=115619
It seems that POSIX shared memory is now more similar to linux, so I've just changed workaround.hpp to avoid filesystem-based shm flag.
Yep, good catch on that post. Fortunately, the "implementation defined" behavior on 7.2 was sane, but indeed required non-portable use of names. Note that I think there is a minor typo in the #if test, see my comment above. And again, thanks for the help. You've certainly fixed the bugs faster *much* than I could have myself since I'm not very familiar with all the interactions in the Boost.Interprocess library, nor am I familiar with the portability issues on non-FreeBSD and non-Linux platforms. Manish

Manish Vachharajani escribió:
You are lucky because right now I'm working on Interprocess, that's why changes are happening so fast. This will change tomorrow, because I have other pending tasks, so let's do the work ;-)
Ok, sounds good to me :)
I've uploaded to trunk a change I've done to remove the call to write_whole_device, which called ::lseek and ::write and it's only needed in windows, since truncation in windows does not zero fill the memory if the new size is bigger. Can you test it?
Works for me under 8.0 on my small test code. Minor bug on 7.2, the test in workaround.hpp should be (__FreeBSD__ < 8), not >=8. Otherwise, on 7.2 we don't use the filesystem based naming and things break. It seems we'd want the opposite, filesystem naming on anything less than 8, no filesystem naming on anything greater.
Yes, I realized after committing ;-) changed now in trunk.
I'll let you know if it works in the main code in which I use this stuff later today, after I patch the changes you've made into our production version of boost. Do you know if this stuff will make it into boost 1.40.0 or is it too late for that?
If you reply ASAP (tomorrow?) and trunk test are ok, I'll commit it for 1.40 if the release manager agrees. Best, Ion

Yes, I realized after committing ;-) changed now in trunk.
Yep saw that after the code mysteriously went away on my 8.0 box after I accidentally did another svn up. :)
I'll let you know if it works in the main code in which I use this stuff later today, after I patch the changes you've made into our production version of boost. Do you know if this stuff will make it into boost 1.40.0 or is it too late for that?
If you reply ASAP (tomorrow?) and trunk test are ok, I'll commit it for 1.40 if the release manager agrees.
I'll have the test run in a couple of hours. I just have to take care of one other thing first. Manish
Best,
Ion _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Ok, I've patched in the relevant changes to our production boost and all looks good, even in our full system code. I hope these changes make it to boost 1.40.0. And once again, thank you for the help. Manish On Tue, Aug 11, 2009 at 11:44 AM, Manish Vachharajani<manishv@lineratesystems.com> wrote:
Yes, I realized after committing ;-) changed now in trunk.
Yep saw that after the code mysteriously went away on my 8.0 box after I accidentally did another svn up. :)
I'll let you know if it works in the main code in which I use this stuff later today, after I patch the changes you've made into our production version of boost. Do you know if this stuff will make it into boost 1.40.0 or is it too late for that?
If you reply ASAP (tomorrow?) and trunk test are ok, I'll commit it for 1.40 if the release manager agrees.
I'll have the test run in a couple of hours. I just have to take care of one other thing first.
Manish
Best,
Ion _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (3)
-
Ian McCulloch
-
Ion Gaztañaga
-
Manish Vachharajani