Skip to content

Instantly share code, notes, and snippets.

@schkovich
Created April 19, 2025 16:49
Show Gist options
  • Save schkovich/e6554deb8675ff9e2ada2aa27509f5fe to your computer and use it in GitHub Desktop.
Save schkovich/e6554deb8675ff9e2ada2aa27509f5fe to your computer and use it in GitHub Desktop.
async_context_threadsafe_background: race in handle_sync_func_call() causes use‑after‑free on multicore
#include <Arduino.h>
#include <array>
#include <memory>
#include "pico/async_context_threadsafe_background.h"
bool core1_separate_stack = true;
volatile bool operational = false;
static constexpr int BLUE_LED = D7;
static constexpr int RED_LED = D8;
static constexpr int YELLOW_LED = D9;
static constexpr int GREEN_LED = D10;
static async_context_threadsafe_background_t asyncCtx;
uint32_t doSomeWork(void* param) {
digitalWrite(YELLOW_LED, HIGH);
auto* ptr = static_cast<uint32_t*>(param);
(*ptr) += 1; // Simple operation to demonstrate synchronous call
digitalWrite(YELLOW_LED, LOW);
return *ptr;
}
uint32_t sync_call(uint32_t& myNumber) {
return async_context_execute_sync(&asyncCtx.core, doSomeWork, &myNumber);
}
uint32_t green_call(uint32_t& myNumber) {
static constexpr size_t BIGNUMBER = 4096;
std::array<uint8_t, BIGNUMBER> arr;
const uint32_t rc = sync_call(myNumber);
std::uninitialized_fill_n(arr.begin(), BIGNUMBER, 1);
return rc;
}
void setup() {
Serial.begin(115200);
while (!Serial) {
delay(10);
}
delay(5000);
Serial.printf("C0: Left leader standing by...\n");
RP2040::enableDoubleResetBootloader();
pinMode(BLUE_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(YELLOW_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
async_context_threadsafe_background_config_t cfg = async_context_threadsafe_background_default_config();
operational = async_context_threadsafe_background_init(&asyncCtx, &cfg);
assert(operational);
Serial.printf("C0 ready...\n");
}
void setup1() {
while (!operational) {
delay(10);
}
Serial.printf("C1 ready...\n");
}
void loop() {
delay(1);
static unsigned long c0_counter = 0;
digitalWrite(BLUE_LED, HIGH);
c0_counter++;
if (c0_counter % 1000 == 0) {
digitalWrite(LED_BUILTIN, HIGH);
delay(5);
digitalWrite(LED_BUILTIN, LOW);
} else if (c0_counter % 7070 == 0) {
Serial.printf("Core %d: Free stack %d bytes\n", get_core_num(), rp2040.getFreeStack());
}
digitalWrite(BLUE_LED, LOW);
delay(1);
}
void loop1() {
delay(2);
digitalWrite(GREEN_LED, HIGH);
static unsigned long c1_counter = 0;
static uint32_t myNumber = 0;
c1_counter++;
if ((c1_counter % 100) == 0) {
digitalWrite(RED_LED, HIGH);
delay(5);
digitalWrite(RED_LED, LOW);
} else if (c1_counter % 333 == 0) {
const auto rc = green_call(myNumber);
Serial.printf("Core 1: doSomeWork() returned %d\n", rc);
} else if (c1_counter % 5050 == 0) {
Serial.printf("Core %d: Free stack %d bytes\n", get_core_num(), rp2040.getFreeStack());
} else if (c1_counter % 9090 == 0) {
Serial.printf("Free heap: %d bytes\n", rp2040.getFreeHeap());
}
digitalWrite(GREEN_LED, LOW);
delay(2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment