waba has asked for the wisdom of the Perl Monks concerning the following question:
A co-worker came to me today with an interesting problem: he could not msgget the msqid of a message queue created by an external program. He was trying something like perl -e 'print msgget 0xdeadbeef, 0', with 0xdeadbeef being whatever ipcs -q displayed and he kept getting undef.
After trying it out myself, I finally resorted to strace and was quite puzzled by the following:
As a matter of fact, on Linux x86 all keys greater than than 0x80000000 are rounded down to that value !strace perl -e 'msgget( 0xdeadbeef, 0 );' ... msgget(0x80000000, 0) = 655361
RTFSing, the first argument to the *get IPC functions (doio.c:1961 for perl 5.10.0) is extracted as a double and then compiler-casted into a key_t, whatever that is. As it happens to be a signed 32b integer on Linux x86 (and x86_64, as I just tested), we get this behaviour. In order to access keys which have their most significant bit set (in a unsigned integer representation), one has to reverse-engineer the system and provide a repacked, negative value.
Is this a bug or a feature? Clearly, the core issue is that the standard does not specify what a key_t is. I can quite follow the Perl implementors' logic of extracting the largest possible value and letting the compiler figure out how to convert it into a key_t. However, it is also quite confusing for users who expect to be able to use whatever ipcs -q tells them.
Replacing the SvNVx (extract a double) macro by SvIVx (extract an integer) in the Perl source code does the Right Thing on my system (both large positive and negative key values work). However, is it portable and/or a good idea enough than to warrant a post on perlbug?
# A testcase exhibiting the issue use IPC::SysV qw( IPC_CREAT IPC_RMID ); use Test::More tests => 1; use strict; use warnings; my $last_key = 0x80000000; my $i32b_key = 0xdeadbeef; # Anything > $last_key cleanup(); test(); cleanup(); sub cleanup { my $queue_id = msgget $last_key, 0; msgctl $queue_id, IPC_RMID, 0 if defined $queue_id; $queue_id = msgget $i32b_key, 0; msgctl $queue_id, IPC_RMID, 0 if defined $queue_id; return; } sub test { my $queue1_id = msgget $i32b_key, IPC_CREAT; my $queue2_id = msgget $last_key, IPC_CREAT; my $msg = sprintf "Queues 0x%x and 0x%x have the same ID 0x%x", $l +ast_key, $i32b_key, $queue1_id; isnt( $queue1_id, $queue2_id, $msg ); return; } 1;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: SysV IPC key_t handling in Perl
by zentara (Cardinal) on May 14, 2008 at 16:10 UTC | |
by waba (Monk) on May 14, 2008 at 20:52 UTC | |
by Anonymous Monk on May 29, 2008 at 11:12 UTC |