Hello Johannes,

Johannes Brunen wrote:
after spending some time I have found the problematic code. Actually, I still do not know what is the real problem but let me explain first.

ah, I was writing a mail to you with some updates, but I had not been able to find the problem.

I have learned that the '.osb' file format involves the following kind of code:

1. On writing: OSGExceptionBinaryDataHandler.inl, function void putValue(const Real32& value)
Real32 v = osgHostToNet<Real32>(value);

which melts down to (OSGBaseFunctions.inl)

template <> inline
OSG::Real32 osgSwapBytes<Real32>(OSG::Real32 src)
{
    UInt8* pStart = reinterpret_cast<UInt8*>(&src);
    UInt8* pEnd   = reinterpret_cast<UInt8*>(&src) + sizeof(Real32);

    std::reverse(pStart, pEnd);

    return src;
}

I could verify that everything is fine to the point of the return call. However, variable v is not correctly intialized afterwards.

oh, my favourite C++ programming rules, aliasing ;) My hope in writing the above had been that due to the special casing of 'char' in the aliasing rules the conversion would be safe :-/

2. On reading the function getValues(Real32* value, UInt32 size) throw (ReadError) is called in the same source file as above. A similar function call takes place in this file which is also unsecure (with respect to my platform):

value[i] = osgNetToHost<Real32>(value[i])

In order to check it more thoroughly, I modified the code in OSGExceptionBinaryDataHandler in the following way:

Wrpt. to 1)
// Real32 v = osgHostToNet<Real32>(value);
UInt8 buffer[sizeof(Real32)];
memcpy(buffer, reintepret_cast<const void*>(&value), sizeof(Real32));
std::reverse(buffer, buffer+sizeof(Real32));
put(buffer, sizeof(Real32));

Wrpt. 2)
//value[i] = osgNetToHost<Real32>(value[i]);
std::reverse(reinterpret_cast<UInt8*>(&value[i]), reinterpret_cast<UInt8*>(&value[i])+sizeof(Real32));

With these small modifications, I'm not facing any of the reported problems anymore.


Unfortunately, I'm not an expert in these matters and can't tell what the real reason for the problem is. Interestingly, I added the following code for testing:

Wrpt 1.
if (::boost::math::isnan(v))
    __asm int 3;

Wrpt 2.
if (::boost::mathisnan(value[i])
    __asm int 3;

These interrupts get be called in the original code. As I have told, I do not know the exact rules about copying float (doubles) numbers in case of leaving the valid range of numbers. What I know is that the math coprocessor is always good for surprises especilly folded by the optimization flags of the compiler.

hm, the tests are done after the swap, right? In that case it is ok that the numbers are NaNs since they are only stored/send over the network in this format. Before any computation is done on them they are converted back. The whole conversion of floating point numbers to "network format" is a bit dubious anyway, since there is not really a "network format" for them in the first place, unlike for integers. But OpenSG has done these conversions forever and changing it now would probably introduce breakage of the .OSB format, which I'd rather avoid.

So, what to do. I would recommend to go for a little more secure way for the osgHostToNet and osgNetToHost functions. At least on my platform (win32, win64) I'm expecting more trouble in this area, so.

What do you think? Gerry, in case you are listening, do you know the background for this stuff? What is your opinion?

I'll change the functions to use type punning through unions (AFAIK this is also not allowed by the C++ standard, but a supported extensions on GCC and MS VS) - patch attached. Unless someone has a better idea?

Sorry for the trouble and many thanks for tracking down the problem!

        Cheers,
                Carsten

diff --git a/Source/Base/Base/OSGBaseFunctions.inl b/Source/Base/Base/OSGBaseFunctions.inl
index c73f8ec..87ab6f0 100644
--- a/Source/Base/Base/OSGBaseFunctions.inl
+++ b/Source/Base/Base/OSGBaseFunctions.inl
@@ -2939,12 +2939,16 @@ OSG::Int64 osgSwapBytes<Int64>(OSG::Int64 src)
 template <> inline 
 OSG::Real32 osgSwapBytes<Real32>(OSG::Real32 src)
 {
-    UInt8* pStart = reinterpret_cast<UInt8*>(&src);
-    UInt8* pEnd   = reinterpret_cast<UInt8*>(&src) + sizeof(Real32);
+    union
+    {
+        OSG::Real32 floatVal;
+        OSG::UInt32 intVal;
+    } unionVal;
 
-    std::reverse(pStart, pEnd);
+    unionVal.floatVal = src;
+    unionVal.intVal   = osgSwapBytes(unionVal.intVal);
 
-    return src;
+    return unionVal.floatVal;
 }
 
 /*! \ingroup GrpBaseBaseMiscFn
@@ -2952,12 +2956,16 @@ OSG::Real32 osgSwapBytes<Real32>(OSG::Real32 src)
 template <> inline 
 OSG::Real64 osgSwapBytes<Real64>(OSG::Real64 src)
 {
-    UInt8* pStart = reinterpret_cast<UInt8*>(&src);
-    UInt8* pEnd   = reinterpret_cast<UInt8*>(&src) + sizeof(Real64);
+    union
+    {
+        OSG::Real64 floatVal;
+        OSG::UInt64 intVal;
+    } unionVal;
 
-    std::reverse(pStart, pEnd);
+    unionVal.floatVal = src;
+    unionVal.intVal   = osgSwapBytes(unionVal.intVal);
 
-    return src;
+    return unionVal.floatVal;
 }
 
 /*! Convert a value from host byte order to big endian byte order.
------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share 
of $1 Million in cash or HP Products. Visit us here for more details:
http://ad.doubleclick.net/clk;226879339;13503038;l?
http://clk.atdmt.com/CRS/go/247765532/direct/01/
_______________________________________________
Opensg-users mailing list
Opensg-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensg-users

Reply via email to