4

I'm trying to unpack an unsigned long value that is passed from a C program to a Perl script via SysV::IPC.

It is known that the value is correct (I made a test which sends the same value into two queues, one read by Perl and the second by the C application), and all predecessing values are read correctly (used q instead of i! to work with 64-bit integers).

It is also known that PHP had something similar in bugs (search for "unsigned long on 64 bit machines") (seems to be similar: Pack / unpack a 64-bit int on 64-bit architecture in PHP)

Arguments tested so far:

  • ..Q ( = some value that is larger than expected)
  • ..L ( = 0)
  • ..L! ( = large value)
  • ..l ( = 0)
  • ..l! ( = large value)
  • ..lN! ( = 0)
  • ..N, ..N! ( = 0)

use bigint; use bignum; -- no effect.

Details:

  • sizeof(unsigned long) = 8;
  • Data::Dumper->new([$thatstring])->Useqq(1)->Dump(); a lot of null bytes along some meaningful..
  • byteorder='12345678';

Solution: - x4Q with padding four bytes.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kagali-san
  • 2,964
  • 7
  • 48
  • 87
  • Show output of `Data::Dumper->new($string)->Useqq(1)->Dump` on your packed string and what number you are expecting. And maybe output of perl -V:byteorder – ysth Mar 30 '11 at 15:44
  • sorry, I mean output of `print Data::Dumper...` – ysth Mar 30 '11 at 16:04
  • @ysth, VAR1 = "\210\23\0\0\0\0\0\0\210\23\0\0\0\0\0\0\177\0\0\1\0\0\0\0\177\0\0\1\0\0\0\0W\273\@\37\0\0\0\0}^\330u\0\0\0\0\264\13\340u\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\16T\223M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - wow, too much \0's, checking. Maybe `my $string` declaration doesn't fits return type somewhere. – kagali-san Mar 30 '11 at 16:11
  • Have your tried just unpacking a scalar constant coded in the script? Once you get that working, try the pipe... – dawg Mar 30 '11 at 16:30
  • @drewk, nope, I just can run all three programs simultaneously, (Perl version currently does no work unless I can get away this unpack trouble) and it can be restarted quickly.. not a time for unit test :) – kagali-san Mar 30 '11 at 17:58
  • What is "predecessing values"? Do you mean "preceding values"? – Peter Mortensen Jun 18 '17 at 20:17

2 Answers2

3

Unpacking using Q in the template works out of the box if you have 64-bit Perl:

The TEMPLATE is a sequence of characters that give the order
and type of values, as follows:

 ...

 q   A signed quad (64-bit) value.
 Q   An unsigned quad value.
       (Quads are available only if your system supports 64-bit
        integer values _and_ if Perl has been compiled to support those.
        Causes a fatal error otherwise.)

For a more robust solution, unpack the value into an 8-byte string and use the Math::Int64 module to convert it to an integer:

use Math::Int64 qw( :native_if_available int64 );

...

$string_value = unpack("A8", $longint_from_the_C_program);

# one of these two functions will work, depending on your system's endian-ness
$int_value = Math::Int64::native_to_int64($string_value);
$int_value = Math::Int64::net_to_int64($string_value);
mob
  • 117,087
  • 18
  • 149
  • 283
  • Neither works correctly; source value = 563026057, same unpacked in secondary C app, native_to_int64 = 2418178501610831872, net_to_int64 = 2300088097 – kagali-san Mar 30 '11 at 16:04
1

The solution was simple: added x4Q to skip four bytes before actual value; need to more visually think of padding/alignment..

kagali-san
  • 2,964
  • 7
  • 48
  • 87