[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: LuaJIT ffi.copy() bug.
- From: "Robert G. Jakabosky" <bobby@...>
- Date: Sat, 19 Feb 2011 13:49:41 -0800
I might have found a bug with ffi.copy() when used without the third 'len'
parameter. Attached is a simplified version of the ZeroMQ FFI bindings that
shows the bug (see the ffi.copy() call at line 81). If you disable the JIT
then this bug doesn't happen, or if you only send about 50 messages. So it
looks like the JIT is incorrectly optimizing the ffi.copy() call. Also if you
pass "msg_len" as the third parameter to ffi.copy() (see line 83) then it
works.
To run the script you have to start two instances (client & server):
start the server first:
luajit-2 ffi_copy_bug.lua server 20 100000
then the client:
luajit-2 ffi_copy_bug.lua client 20 100000
The server binds to port 5555 on 127.0.0.1.
--
Robert G. Jakabosky
local ffi=require"ffi"
ffi.cdef[[
typedef struct zmq_msg_t
{
void *content;
unsigned char flags;
unsigned char vsm_size;
unsigned char vsm_data [30];
} zmq_msg_t;
int zmq_msg_init (zmq_msg_t *msg);
int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
int zmq_msg_close (zmq_msg_t *msg);
void *zmq_msg_data (zmq_msg_t *msg);
size_t zmq_msg_size (zmq_msg_t *msg);
void *zmq_init (int io_threads);
int zmq_term (void *context);
void *zmq_socket (void *context, int type);
int zmq_close (void *s);
int zmq_bind (void *s, const char *addr);
int zmq_connect (void *s, const char *addr);
int zmq_send (void *s, zmq_msg_t *msg, int flags);
int zmq_recv (void *s, zmq_msg_t *msg, int flags);
]]
local zmq = {
-- socket types
PAIR = 0,
PUB = 1,
SUB = 2,
REQ = 3,
REP = 4,
XREQ = 5,
XREP = 6,
PULL = 7,
PUSH = 8,
-- socket options
HWM = 1,
SWAP = 3,
AFFINITY = 4,
IDENTITY = 5,
SUBSCRIBE = 6,
UNSUBSCRIBE = 7,
RATE = 8,
RECOVERY_IVL = 9,
MCAST_LOOP = 10,
SNDBUF = 11,
RCVBUF = 12,
RCVMORE = 13,
FD = 14,
EVENTS = 15,
TYPE = 16,
LINGER = 17,
RECONNECT_IVL = 18,
BACKLOG = 19,
-- send/recv flags
NOBLOCK = 1,
SNDMORE = 2,
}
local C = ffi.load"zmq"
setmetatable(_G, { __index=C })
local tmp_msg = ffi.new('zmq_msg_t')
local function zmq_send(sock, data, flags)
local msg = tmp_msg
local msg_len = #data + 1
-- initialize message
if C.zmq_msg_init_size(msg, msg_len) < 0 then
return error("some zmq_*() function returned an error")
end
-- copy data into message.
-- BROKEN: ffi.copy
ffi.copy(C.zmq_msg_data(msg), data)
-- WORKING: ffi.copy
--ffi.copy(C.zmq_msg_data(msg), data, msg_len)
-- send message
local ret = C.zmq_send(sock, msg, flags or 0)
-- close message before processing return code
if C.zmq_msg_close(msg) ~= 0 then
return error("some zmq_*() function returned an error")
end
-- now process send return code
if ret ~= 0 then
return error("some zmq_*() function returned an error")
end
return true
end
local function zmq_recv(sock, flags)
local msg = tmp_msg
-- initialize blank message.
if C.zmq_msg_init(msg) < 0 then
return error("some zmq_*() function returned an error")
end
-- receive message
local ret = C.zmq_recv(sock, msg, flags or 0)
if ret ~= 0 then
local data, err = error("some zmq_*() function returned an error")
C.zmq_msg_close(msg)
return data, err
end
local data = ffi.string(C.zmq_msg_data(msg), C.zmq_msg_size(msg))
-- close message
if C.zmq_msg_close(msg) ~= 0 then
return error("some zmq_*() function returned an error")
end
return data
end
local ctx=zmq_init(1)
local is_client = arg[1]
local message_size = tonumber(arg[2])
local roundtrip_count = tonumber(arg[3])
local msg
local sock
if arg[1] == 'client' then
sock = zmq_socket(ctx, zmq.REQ)
zmq_connect(sock, "tcp://localhost:5555")
msg = string.rep('0', message_size)
for i=1,roundtrip_count do
zmq_send(sock, msg, 0)
msg = zmq_recv(sock, 0)
end
else
sock = zmq_socket(ctx, zmq.REP)
zmq_bind(sock, "tcp://lo:5555")
for i=1,roundtrip_count do
msg = zmq_recv(sock, 0)
zmq_send(sock, msg, 0)
end
end
print(is_client, "end")
print('sock close:', zmq_close(sock))
print('zmq_term:',zmq_term(ctx))