New submission from Thomas Chiroux: This bug bellow occurs only on my crosscompiled environment on arm (marvell armada 166): arm-pxa168-linux-gnueabi It does not seems to be a cross-compile issue: python compiles without problem and all unittests pass on the target device.
description and first clues --------------------------- The problem is easyly reproducted using this script: #!/usr/bin/python import socket sock = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) sock.bind((0,)) which raises the following exception when run on the target device: Traceback (most recent call last): File "./test_bt.py", line 4, in <module> sock.bind((0,)) OSError: [Errno 22] Invalid argument This does not give much clues, but strace does (i've filtered to display the two significant parts of strace) socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3 bind(3, {sa_family=AF_UNSPEC, sa_data="\0\0\360\35\251\266s\316(U\3\0\0\0"}, 6) = -1 EINVAL (Invalid argument) (on a working environment, including arm, like a raspberry pi, strace gives the following result (and no traceback of course): socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3 bind(3, {sa_family=AF_BLUETOOTH, sa_data="\0\0\0\0\0\0X\352\243\266\0\24\265\266"}, 6) = 0 So, on the armada166, between the socket creation and the bind we lost the socket family (AF_UNSPEC instead of AF_BLUETOOTH). And That's why bind returns invalid argument. socketmodule and PyArg_ParseTuple --------------------------------- Now let's look at Modules/socketmodule.c: After some digging, i've found that the problem is in getsockaddrarg, in the AF_BLUETOOTH / BTPROTO_HCI case and more precisely on this line: https://hg.python.org/cpython/file/ab2c023a9432/Modules/socketmodule.c#l1449 reproducted here: if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) { When we execute the PyArg_ParseTuple, the addr->hci_family is crunched (by zeros with my previous python sample). At this same place, i've done the following test: char buffer[8]; memset(buffer, 0x55, 8); if (!PyArg_ParseTuple(args, "i", buffer) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xAA, 8); if (!PyArg_ParseTuple(args, "i", buffer+1) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+1: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xBB, 8); if (!PyArg_ParseTuple(args, "i", buffer+2) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+2: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); memset(buffer, 0xcc, 8); if (!PyArg_ParseTuple(args, "i", buffer+3) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } printf("CL+3: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); and the result is: CL: 0 0 0 0 85 85 85 85 CL+1: 0 0 0 0 170 170 170 170 CL+2: 0 0 0 0 187 187 187 187 CL+3: 0 0 0 0 204 204 204 204 (WTF ??) in a working environnement (tested on raspberry B+ / python 3.4.2 locally compiled) result is what we should expect: CL: 0 0 0 0 85 85 85 85 CL+1: 170 0 0 0 0 170 170 170 CL+2: 187 187 0 0 0 0 187 187 CL+3: 204 204 204 0 0 0 0 204 So on my box if PyArg_ParseTuple write on &addr->hci_dev if write 4 bytes from &addr->hci_family which is 2 bytes BEFORE &addr->hci_dev At this time I can not understand how it's possible. Remarks and patch ----------------- Now I have several remarks and a working patch. * remark/question 1: why does PyArg_ParseTuple parse an int when addr->hci_dev is an unsigned short ? even in normal situation, when it works, writing on &addr->hci_dev overflow on the next two bytes which are btw addr->channel (more on that later) * remark/question 2: i've tried to dig more deeply inside PyArg_ParseTuple and found another odd thing, but I did not try to change it without knowing what I do: in Python/getargs.c, in convertsimple, int parsing result is not casted before returned: here: https://hg.python.org/cpython/file/ab2c023a9432/Python/getargs.c#l690 (ival is a long). In all other cases (short, unsigned short, char, usigned char), they are casted before return. [disclosure: i've tested to add the cast and relaunched my bind test, it did not change anything, but it's still strange for me] * Now a working patch: here below and attached a working patch which results on a good socket bind, but now completely satisfiying: --- Python-3.4.2/Modules/socketmodule.c 2014-10-08 10:18:15.000000000 +0200 +++ CC_PYTHON/Python-3.4.2/Modules/socketmodule.c 2015-02-11 15:42:35.173455634 +0100 @@ -1446,11 +1446,12 @@ getsockaddrarg(PySocketSockObject *s, Py return 0; #else _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; - if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) { + if (!PyArg_ParseTuple(args, "H", &_BT_HCI_MEMB(addr, dev))) { PyErr_SetString(PyExc_OSError, "getsockaddrarg: " "wrong format"); return 0; } + _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW; #endif *len_ret = sizeof *addr; return 1; in short: I parse now an unsigned short instead of parsing an int which gives me a two bytes long elements which is stored well on addr->hci_dev without overloading addr->hci_family. But this modification alone is not enough: addr->hci_channel needed a good value. that's why i added _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW; which sets addr->hci_channel to zero. (without this line, any value could be here) And that led me to another question/problem: how is hci_channel normally handled ? It does not seems to be a valid parameter of bind; behaviour without the patch will erase hci_channel while storing int value in hci_dev, so theorically we can assign a well defined int value in our bind method to both assign the wanted value in hci_dev and hci_channel, but it does not seems to be a proper way to do it. ---------- components: Extension Modules files: bluetooth_bind_arm.patch keywords: patch messages: 235751 nosy: Thomas.Chiroux priority: normal severity: normal status: open title: HCI Bluetooth socket bind error on an arm crosscompiler environment type: behavior versions: Python 3.4 Added file: http://bugs.python.org/file38097/bluetooth_bind_arm.patch _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue23444> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com