john s.
john s.

Reputation: 517

How to isolate a fault on arm device?

I am using rapidjson on an Arm device and get strange behaviour, when running this code.

    #include <document.h>
    using namespace std;

int main()
{
    const char json []="[{\"Type\":\"float\",\"val_param\" : 12.025 }]";

    rapidjson::Document d;

    if( d.Parse<0>( json ).HasParseError() ) {
     //ErrorCase
    }else{
        rapidjson:: Value& val_param    = d[0]["val_param"];
        double tmp_double1  = val_param.GetDouble(); 
        cout << tmp_double1 <<endl; // -9.2559641157289301e+61 instead of 12.025
    }

    return 0;
}

Before down voting this question. What else information do you need? I really don't know how to isolate this fault. If it occurs because of the embedded device, or rapidjson. And how to solve it.

========================== UPDATE ========================================

What is the device? http://www.keith-koep.com/de/produkte/produkte-trizeps/trizeps-iv-m-eigenschaften/

Does it have a hardware FPU? It is ARMv5 so I don't think so.

What compiler and libraries are you using (version numbers/specific builds)? What options are you passing to the compiler and linker?

arm-linux-gnueabi-g++ -march=armv5te -marm -mthumb-interwork --sysroot=/usr/local/oecore-x86_64/sysroots/armv5te-linux-gnueabi

Upvotes: 3

Views: 128

Answers (1)

Notlikethat
Notlikethat

Reputation: 20974

This looks like it might be an undefined-behaviour-type bug in RapidJSON.

Since you're targeting ARMv5, you're probably using a software floating-point library using the legacy ARM FPA format (as opposed to the later VFP, which uses IEEE754 format). Crucially, the FPA stores things in a weird middle-endian format, where 64-bit doubles are stored as two little-endian words, but most-significant word first.

(Yes, big-endian ARM is a whole other complicated issue, but I'm deliberately ignoring it here since I don't see an armeb-* triplet or the -mbig-endian option anywhere)

Consider 12.025 as an IEEE754 double:

64-bit value:             0x40280ccccccccccd.
little-endian byte order: cd cc cc cc cc 0c 28 40
as little-endian words:   0xcccccccd 0x40280ccc

Now in FPA format that would be:

as little-endian words:   0x40280ccc 0xcccccccd
byte order:               cc 0c 28 40 cd cc cc cc

Trying to interpret that as a pure little-endian 64-bit value yields 0xcccccccd40280ccc, which just so happens to be the IEEE754 representation of -9.255965e+61. Fancy that!


From a quick look around the code, it may strictly be more of an incompatibility than a bug, since RapidJSON does seem to explicitly assume IEEE754 format for floating-point values. To its credit, even though the parsing code looks pretty hairy, I do see unions rather than type-punning pointers. However, even if it's not relying on undefined behaviour, it's still relying on implementation-defined behaviour (the format of floating-point types), and unfortunately this compiler's implementation doesn't match that expectation.

Upvotes: 2

Related Questions