ccgcube has asked for the wisdom of the Perl Monks concerning the following question:

Hi All,

I'm working on a set of tools that must run on both solaris and linux. I've written a set of packages using Inline::C, primarily to manipulate large arrays. The code compiles and runs correctly on linux.

It compiles and runs on solaris too, but I'm not getting the results I'm looking for.

The code below is the smallest version of the code I can come up with to demonstrate the problem. The newthing() function is intended to return a pointer to a blessed object, in this case our small struct Thing. In the interest of full disclosure, newthing() was stolen almost verbatim from Inline::C-Cookbook (thanks!).

That reference may be used from the perl side to call $thingref->bump() from the perl side. The bump function should increment thing->index, and assign the simtime parameter to thing->simtime.

The problem is that the solaris version does not increment the index, and does not appear to handle the simtime parameter correctly. Both values stay at zero when they should be non-zero (recall that this runs correctly on linux). A sample of the output follows the code.

My first quess was that I've got a type mismatch somewhere. Changing the type of the obj parameter to bump() from SV * to UV * or IV * compiles, but produces this message at runtime:

Can't locate object method "bump" via package "Short" at ./p_passi +ng_blessed line 58.

... and I am obviously guessing.

The version of perl on both systems is 5.18.4.

perl -V on solaris returns this (among other things):

intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=87654321 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=1 +6 ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='of +f_t', lseeksize=8

I suspect that somewhere along the line, my object has been misallocated, and it is the difference between ivsize and ptrsize that is the source of the issue... but again, I'm guessing.

package Short; use Inline C; use strict; # no strict 'refs'; 1; ## # __DATA__ __C__ #ifndef Newx # define Newx(v,n,t) New(0,v,n,t) #endif typedef struct { UV index; UV simtime; } Thing; // -------------------------------------------------------- // shamelessly stolen from Inline::C-Cookbook // SV* newthing( const char * classname ) { Thing * thing; SV * obj; SV * obj_ref; Newx( thing, 1, Thing ); thing->index = 0; thing->simtime = 0; obj = newSViv( (IV)thing ); obj_ref = newRV_noinc(obj); sv_bless( obj_ref, gv_stashpv( classname, GV_ADD ) ); SvREADONLY_on( obj ); return obj_ref; } // -------------------------------------------------------- // void DESTROY(SV* obj) { Thing* thing = (Thing*)SvIV(SvRV(obj)); printf("FREE thing size : %d\n", sizeof( thing ) ); Safefree( thing ); } // -------------------------------------------------------- // void bump( SV* obj, UV simtime ) { Thing* thing = (Thing*)SvIV(SvRV(obj)); printf("obj size : %lu\n", sizeof( obj ) ); printf("obj val : %lx\n", (unsigned long)obj ); printf("thing size : %d\n", sizeof( thing ) ); printf("thing val : %lu\n", (unsigned long)thing ); printf("thing simtime p : %lu\n", simtime ); printf("thing simtime A : %lu\n", thing->simtime ); printf("thing index A : %lu\n", thing->index ); thing->simtime = simtime; thing->index += 1; printf("thing simtime B : %lu\n", thing->simtime ); printf("thing index B : %lu\n", thing->index ); }

Sample Output

# --------------------- Devel::Peek::Dump output so we can compare values: SV = IV(0x2bf2d8) at 0x2bf2d8 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x2216b0 SV = PVMG(0x4372c8) at 0x2216b0 REFCNT = 1 FLAGS = (OBJECT,IOK,READONLY,pIOK) IV = 7888424 NV = 0 PV = 0 STASH = 0x30a5e8 "Short" # --------------------- perl passing simtime: 20 obj size : 4 obj val : 2bf2d8 thing size : 4 thing val : 7888424 thing simtime p : 0 << should be 20 thing simtime A : 0 thing index A : 0 thing simtime B : 0 << should be 20 thing index B : 0 << should be 1 perl passing simtime: 40 obj size : 4 obj val : 2bf2d8 thing size : 4 thing val : 7888424 thing simtime p : 0 << should be 40 thing simtime A : 0 thing index A : 0 thing simtime B : 0 << should be 40 thing index B : 0 << should be 2 FREE thing size : 4

Thanks in advance,

Replies are listed 'Best First'.
Re: Inline C solaris vs linux
by syphilis (Archbishop) on Feb 09, 2016 at 00:08 UTC
    byteorder=87654321

    Is that the same on both machines ?
    If not, then the 2 machines have different endianness, and that is more likely the source of your problems.

    I've been bitten by this in the past with long long values - though I'm not sure it was precisely the same as your case.
    On a little-endian machine, the "%u" format run on a long long value will work fine iff the "long long" value fits into a "long". But that doesn't hold on a big-endian machine, and that's where my code was coming unstuck.

    The ivsize-ptrsize difference you noticed is normal for a 64-bit integer perl on a 32-bit architecture and should not be the source of the problem.

    What is the ivtype on the other machine ?

    Cheers,
    Rob
      I've been bitten by this in the past with long long values - though I'm not sure it was precisely the same as your case.
      I think it is. To the OP: what happens when you use printf format llu instead of lu?
Re: Inline C solaris vs linux
by Anonymous Monk on Feb 09, 2016 at 06:42 UTC

    What is the gcc version on the solaris machine? (Assuming it is gcc; you have omitted this detail.)

    It would be best to give BUILD_NOISY => 1 option to Inline::C, and show us the line of compiler invocation. (Might it be gcc-4.4 without the -fno-strict-aliasing? Hmm.)

Re: Inline C solaris vs linux
by ccgcube (Initiate) on Feb 09, 2016 at 21:03 UTC

    Hello All,

    Oh. That.

    From what I've been told, the groan that came out of my office was heard in the next building. Then, because of the alternating chuckles and muttered curses, it took 30 minutes to convince the paramedics that I was ok. I had to sign a waiver.

    "that doesn't hold on a big-endian machine" pointed me in the right direction. Using %llu instead of %lu in printf shows the code actually working. Thank you.

    For the record, perl Config datatypes from linux:

    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=1 +6 ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', + lseeksize=8 alignbytes=8, prototype=define

    The compiler on solaris is Solaris Studio CC. The compiling host is running solaris 5.10, and is the same host used to compile perl. The cc commandline below was taken from the output of Inline C with BUILD_NOISY enabled.

    cc -V says: cc: Sun C 5.12 SunOS_sparc Spica 2011/08/03 /import/tools/vendor/sun/solaris-sparc/studio13b26/solstudiodev/bin/cc + -c -I"/import/coverage5/ccg/qot/vx/inline-dev/test" -D_REENTRANT -K +PIC -DUSE_HASH_SEED_EXPLICIT -DPERL_USE_SAFE_PUTENV -D_LARGEFILE_SOUR +CE -D_FILE_OFFSET_BITS=64 -DPERL_USE_SAFE_PUTENV -O -DVERSION=\"0.0 +0\" -DXS_VERSION=\"0.00\" -KPIC "-I/import/tools/local/perl/perl-5.18 +.4/lib/5.18.4/sun4-solaris-thread-multi-64int/CORE" Short_00d0.c

    Snip of output from working code:

    obj size : 4 obj val : 2bf2d8 thing size : 4 thing val : 7895864 thing simtime p : 40 thing simtime A : 20 thing index A : 1 thing simtime B : 40 << this is what I was looking for thing index B : 2 << this is what I was looking for

    Thanks to everyone. If not for you, I'd probably still be crawling all over perlapi.