LoadProhibited when calling a lambda function from C

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
User avatar
eydam-prototyping
Posts: 8
Joined: Thu Jan 21, 2021 2:18 pm
Contact:

LoadProhibited when calling a lambda function from C

Post by eydam-prototyping » Tue Jan 04, 2022 9:34 pm

Hello,

Happy new year :)

i am trying to build a tool to analyse my wifi with an ESP32. In ESP-IDF there is an example for that:
https://github.com/espressif/esp-idf/tr ... le_sniffer

For that, you have to define a callback (in C) and pass it to esp_wifi_set_promiscuous_rx_cb. It is always called, when a wifi packet is received.

In this callback I want to call a Python-function and pass all arguments:

Code: Select all

static void wifi_sniffer_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) {
    sniffer_packet_info_t packet_info;
    wifi_promiscuous_pkt_t *sniffer = (wifi_promiscuous_pkt_t *)recv_buf;

    packet_info.seconds = sniffer->rx_ctrl.timestamp / 1000000U;
    packet_info.microseconds = sniffer->rx_ctrl.timestamp % 1000000U;
    packet_info.length = sniffer->rx_ctrl.sig_len;

    if (type != WIFI_PKT_MISC && !sniffer->rx_ctrl.rx_state) {
        packet_info.length -= SNIFFER_PAYLOAD_FCS_LEN;
        
        mp_obj_tuple_t *t = mp_obj_new_tuple(3, NULL);
        t->items[0] = mp_obj_new_int(packet_info.seconds);
        t->items[1] = mp_obj_new_int(packet_info.microseconds);
        t->items[2] = mp_obj_new_bytearray(packet_info.length, sniffer->payload);
        //gc_lock();

        //nlr_buf_t nlr;
        //if (nlr_push(&nlr) == 0) {
            mp_call_function_1(sniffer_handler, t);
        //    nlr_pop();
        //}
        //gc_unlock();
    }
    
}
But when the python function is called (sniffer_handler), Python crashes:

Code: Select all

Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x400de3b0  PS      : 0x00060e30  A0      : 0x800de95c  A1      : 0x3ffd1580  
A2      : 0x00000023  A3      : 0x00000000  A4      : 0x00000002  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x800de3b0  A9      : 0x3ffd1560  
A10     : 0x00000000  A11     : 0x3ffcf6f8  A12     : 0x3ffcfcd8  A13     : 0x3ffcf644  
A14     : 0x00000001  A15     : 0xb33fffff  SAR     : 0x00000000  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000008  LBEG    : 0x40094c88  LEND    : 0x40094ca4  LCOUNT  : 0xffffffff  

Backtrace:0x400de3ad:0x3ffd1580 0x400de959:0x3ffd15a0 0x400e681c:0x3ffd15c0 0x400e6a1f:0x3ffd15e0 0x40100f77:0x3ffd1600 0x401e8aa6:0x3ffd1680 0x401e73ab:0x3ffd16a0


ELF file SHA256: 6473566a0311aeba

Rebooting...
If I only pass an integer to the python function, everything works fine. But with a tuple (or a bytearray) it crashes.
(I found the commented lines in the codebase, but it didn't work.)

Any Idea what I can do to pass a tuple the Python-function?

Best regards,
Tobias

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: LoadProhibited when calling a lambda function from C

Post by stijn » Wed Jan 05, 2022 7:03 am

Insert print statements to figure out where it crashes (the function call, or the allocations) first; it's possible you cannot simply allocate from the MicroPython heap in such callback.

Simplify the code perhaps as well, this is waiting for bugs to happen: you put everything in packet_info for some reason, but then a new bytearray is created with packet_info.length and sniffer->payload as arguments?

User avatar
eydam-prototyping
Posts: 8
Joined: Thu Jan 21, 2021 2:18 pm
Contact:

Re: LoadProhibited when calling a lambda function from C

Post by eydam-prototyping » Wed Jan 05, 2022 5:04 pm

Thank you for your reply.

The part with packet_info is from the example from ESP-IDF. I will change it.

When I run

Code: Select all

ESP_LOGE("wifi", "1");
mp_obj_t b = mp_obj_new_bytearray(packet_info.length, sniffer->payload);
ESP_LOGE("wifi", "2");
mp_call_function_1(sniffer_handler, b);
ESP_LOGE("wifi", "3");
I see only "1" as last output before it crashes. I guess I can't allocate the memory.
Do you know, what I can do in this case?

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: LoadProhibited when calling a lambda function from C

Post by stijn » Thu Jan 06, 2022 7:57 am

Sorry I don't know the ESP-IDF architecture so cannot pinpoint the exact reason (various possibilities include this is another thread, or this is an interrupt, or this runs even before MicroPython had been initialized, etc).

The 'standard' workaround if allocation is not possible, is preallocating (assuming these packets will have a maximum length) then copying packets into preallocated memory then setting a flag which gets polled in Python code. But again: i don't know the architecture so there might be better ways.

User avatar
eydam-prototyping
Posts: 8
Joined: Thu Jan 21, 2021 2:18 pm
Contact:

Re: LoadProhibited when calling a lambda function from C

Post by eydam-prototyping » Fri Jan 07, 2022 10:39 pm

Ok, thank you for this tip. I tried and it works :)
I even can pass it as an argument, when its allocated before.

Here my code, in case someone else needs it:

Code: Select all

static void wifi_sniffer_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) {
    wifi_promiscuous_pkt_t *sniffer = (wifi_promiscuous_pkt_t *)recv_buf;
    uint length = sniffer->rx_ctrl.sig_len;

    if (type != WIFI_PKT_MISC && !sniffer->rx_ctrl.rx_state) {
        length -= SNIFFER_PAYLOAD_FCS_LEN;

        mp_obj_array_t *b = (mp_obj_array_t*)sniffer_arg->items[1];
        memcpy(b->items, sniffer->payload, MIN(length, 1024));
        b->len = length;

        sniffer_arg->items[0] = mp_obj_new_int(sniffer->rx_ctrl.timestamp);
        
        mp_sched_schedule(sniffer_handler, sniffer_arg);   
    }
}

...
// outside of callback
char _buffer[1024] = {0};
sniffer_arg = mp_obj_new_tuple(2, NULL);
sniffer_arg->items[0] = mp_obj_new_int(0);
sniffer_arg->items[1] = mp_obj_new_bytearray(1024, _buffer);
I don't know, if 1024 is really the maximum but for testing it is ok.

Thank you and best regards,
Tobias

Post Reply