Unidata / netcdf-cxx4

Official GitHub repository for netCDF-C++ libraries and utilities.
Other
124 stars 49 forks source link

test_type addMember()/getMemberNameFromValue() fails on ppc64 (big-endian) #45

Open opoplawski opened 7 years ago

opoplawski commented 7 years ago

This test is failing on Fedora Rawhide ppc64:

    cout <<left<<setw(57)<<"Testing creating new Enum Type";
    NcEnumType enumType1(ncFile.addEnumType("enumType_1",NcEnumType::nc_SHORT));
    cout <<"    -----------   passed\n";

    cout <<left<<setw(57)<<"Testing NcEnumType::addMember()";
    enumType1.addMember("Monday",1);
    enumType1.addMember("Tuesday",7);
    enumType1.addMember("Wednesday",-20);
    cout <<"    -----------   passed\n";

    cout <<left<<setw(57)<<"Testing NcEnumType::getBaseType() == and !=";
    if(enumType1.getBaseType() != ncShort) throw NcException("Error in test 20.1",__FILE__,__LINE__);
    if(!(enumType1.getBaseType() == ncShort)) throw NcException("Error in test 20.2",__FILE__,__LINE__);
    cout <<"    -----------   passed\n";

    cout <<left<<setw(57)<<"Testing NcEnumType::getMemberCount()";
    if(enumType1.getMemberCount() != 3) throw NcException("Error in test 21.1",__FILE__,__LINE__);
    cout <<"    -----------   passed\n";

    cout <<left<<setw(57)<<"Testing NcEnumType::getMemberNameFromIndex(index)";
    if(enumType1.getMemberNameFromIndex(0) != "Monday") throw NcException("Error in test 22.1",__FILE__,__LINE__);
    if(enumType1.getMemberNameFromIndex(1) != "Tuesday") throw NcException("Error in test 22.2",__FILE__,__LINE__);
    if(enumType1.getMemberNameFromIndex(2) != "Wednesday") throw NcException("Error in test 22.3",__FILE__,__LINE__);
    cout <<"    -----------   passed\n";

    cout <<left<<setw(57)<<"Testing NcEnumType::getMemberNameFromValue(index)";
    if(enumType1.getMemberNameFromValue(1) != "Monday") throw NcException("Error in test 23.1",__FILE__,__LINE__);

This is because at the initial setup:

    enumType1.addMember("Monday",1);

addMember() ends up getting called:

netCDF::NcEnumType::addMember<int> (name="Tuesday", memberValue=7, this=<optimized out>, 
    this=<optimized out>) at ../../cxx4/ncEnumType.h:73
73              ncCheck(nc_insert_enum(groupId, myId, name.c_str(), (void*) &memberValue),__FILE__,__LINE__);

But since the enum type was set to NcEnumType::nc_SHORT, only 2 bytes of the value is copied into the member value:

#0  NC4_insert_enum (ncid=<optimized out>, typeid1=35, identifier=0x3fffffffe380 "Tuesday", 
    value=0x3fffffffd938) at ../../libsrc4/nc4type.c:696
(gdb) print *type
$6 = {l = {next = 0x0, prev = 0x20081190}, name = 0x20081680 "enumType_1", nc_typeid = 35, 
  rc = 1, hdf_typeid = 0, native_hdf_typeid = 0, endianness = 0, size = 2, committed = NC_FALSE, 
  nc_type_class = 15, u = {e = {num_members = 1, enum_member = 0x20081160, base_nc_typeid = 3, 
      base_hdf_typeid = 0}, c = {num_fields = 1, field = 0x20081160}, v = {base_nc_typeid = 1, 
      base_hdf_typeid = 0}}}
(gdb) 
903        memcpy(member->value, value, size);
(gdb) print *(int *)value
$8 = 7
(gdb) print *(short *)value
$9 = 0
(gdb) print member->value
$10 = (void *) 0x20081780
(gdb) print *(int *)member->value
$11 = 0
(gdb) print *(short *)member->value
$12 = 0

This truncation works okay on little-endian, but not big-endian. I can fix the test with:

    enumType1.addMember("Monday",(short)1);
    enumType1.addMember("Tuesday",(short)7);
    enumType1.addMember("Wednesday",(short)-20);

But I'm not sure that this is the best way to cast these values or if there is some other expectation that just work without the cast.