How embedded Rust would manage this?


Today, I faced a bug in a firmware and I was wondering if it would be avoided in Rust or not.

We have these functions:

void write_to_usb(unsigned char* data, unsigned int data_size)
  // code to setup registers
  // start DMA access
  USB->IN = value;

void send_ack()
  std::vector<unsigned char> v;
  // fill the vector
  write_to_usb(, v.size());

void caller()
   while (true)
      // received usb message

      auto response = process_usb_command();
      // more code

On this homemade device, we receive usb command and acknowledge the reception before processing the command and send the response back.

My bug is that for some commands, the acknowledge message I receive is not properly formatted: I got jumble mumble back.

After investigation and tests, it seems that the vector (not really a vector, but for this example let’s say it is) is cleared too quickly because write_to_usb, provided by the chipset manufacturer, is not blocking. So we leave send_ack and the vector is freed from the stack.

It’s a kind of race condition but as it involved some hardware direct access, I don’t know if Rust would save us from this kind of bugs?

It sounds like Rust’s borrowing and ownership system would’ve prevented this particular bug, yes, if your write_usb function properly integrates with it.

1 Like

Brief, handwavy answer: there’s no single “rust embedded” answer here, but in general (and in at least one of the frameworks under development) this is solved by ownership: the type signatures of DMA functions have to be given ownership of DMA buffers, and they can be handed back by the completion interrupt return.

Edit: intended to come back later and add more when I had the chance, but Vitaly has already linked the main blog post I had in mind

1 Like

You might enjoy this (and others there) blog post by @japaric.


Thank you guys!