Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cranelift/runtime/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ fn pith_store_process_handle(mut child: Child) -> i64 {
}

fn pith_strdup_string(text: &str) -> *mut i8 {
let owned = format!("{}\0", text);
unsafe { crate::pith_strdup(owned.as_ptr() as *const i8) }
// the shared helper allocates from the known length without probing the
// rust buffer for a header it cannot have (see runtime_core).
crate::runtime_core::pith_strdup_string(text)
}

unsafe fn pith_build_command(
Expand Down
12 changes: 10 additions & 2 deletions cranelift/runtime/src/runtime_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ use crate::string;
use std::alloc::{alloc, Layout};

pub(crate) fn pith_strdup_string(text: &str) -> *mut i8 {
let owned = format!("{}\0", text);
unsafe { pith_strdup(owned.as_ptr() as *const i8) }
// the length is already known, so allocate the headered cstring directly.
// routing through pith_strdup would probe 16 bytes in front of the rust
// string's buffer looking for a header no rust allocation has — a read of
// memory this process does not own whenever the buffer starts its heap
// block. pith_alloc_cstring writes the nul terminator itself.
unsafe {
let result = pith_alloc_cstring(text.len());
std::ptr::copy_nonoverlapping(text.as_ptr() as *const i8, result, text.len());
result
}
}

#[no_mangle]
Expand Down
18 changes: 17 additions & 1 deletion tests/cases/test_tls_concurrent_resumption.pith
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# resumed. a torn store shows up as a failed dial, a wrong echo, or a hang.

import std.net.tls as tls
import std.time as time

CERT_PATH := "tests/live/fixtures/localhost.crt"
KEY_PATH := "tests/live/fixtures/localhost.key"
Expand Down Expand Up @@ -60,11 +61,26 @@ fn dial_once(cfg: tls.Config, tag: String) -> Bool:
return false
return got_r.ok == "echo:" + tag

# a dial that fails transiently — a starved accept loop on a loaded box, a
# refused connect while the backlog drains — is retried a few times with a
# short backoff. the property under test is the session stores staying
# coherent under concurrent handshakes, and a retried dial exercises them
# exactly as well; without the retry, one transient socket failure on a busy
# ci runner breaks the exact-count output for reasons unrelated to the lock.
fn dial_with_retry(cfg: tls.Config, tag: String) -> Bool:
mut attempt := 0
while attempt < 5:
if dial_once(cfg, tag):
return true
attempt = attempt + 1
time.delay(20 * attempt)
return false

fn worker(id: Int, cfg: tls.Config, done: Channel[Int]):
mut ok := 0
mut i := 0
while i < DIALS_PER_WORKER:
if dial_once(cfg, "w" + id.to_string() + "-" + i.to_string()):
if dial_with_retry(cfg, "w" + id.to_string() + "-" + i.to_string()):
ok = ok + 1
i = i + 1
done.send(ok)
Expand Down
Loading