') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); std.Io.Threaded: fix incorrect alignment of trailing data in closure by Techatrix · Pull Request #25868 · ziglang/zig · GitHub
Skip to content

std.Io.Threaded: fix incorrect alignment of trailing data in closure - #25868

Closed
Techatrix wants to merge 2 commits into
ziglang:masterfrom
Techatrix:io-threaded-alignment
Closed

std.Io.Threaded: fix incorrect alignment of trailing data in closure#25868
Techatrix wants to merge 2 commits into
ziglang:masterfrom
Techatrix:io-threaded-alignment

Conversation

@Techatrix

Copy link
Copy Markdown
Contributor

When calling async, concurrent or std.Io.Group.async on std.Io.Threaded with a function that has parameters or a return value with extra alignment, it may fail because the internal async closure did not properly create well aligned storage for them.

conststd=@import("std");
pubfnmain() !void {
// Depending on which allocator is used, the code may work "by accident". // Using a fixed buffer allocator did consistently reproduce the issue for mevarbuffer: [1024]u8align(64) =undefined;
varfba: std.heap.FixedBufferAllocator= .init(buffer[1..]);
varthreaded: std.Io.Threaded= .init(fba.allocator());
deferthreaded.deinit();
constio=threaded.io();
varfuture=io.async(paramWithExtraAlignment, .{.{}});
future.await(io);
}
fnparamWithExtraAlignment(unused: Align64) void {
_=unused;
}
constAlign64=struct {
unused: u8align(64) =0,
};
zig run sample.zig thread 5824 panic: incorrect alignment
/home/techatrix/repos/zig/lib/std/Io.zig:1534:46: 0x1163409 in start (std.zig)
const args_casted: *const Args = @ptrCast(@alignCast(context));
^
/home/techatrix/repos/zig/lib/std/Io/Threaded.zig:405:16: 0x106af5e in start (std.zig)
ac.func(ac.contextPointer(), ac.resultPointer());
^
/home/techatrix/repos/zig/lib/std/Io/Threaded.zig:188:26: 0x10d9b06 in worker (std.zig)
closure.start(closure);
^
/home/techatrix/repos/zig/lib/std/Thread.zig:558:13: 0x10b3100 in callFn__anon_16055 (std.zig)
@call(.auto, f, args);
^
/home/techatrix/repos/zig/lib/std/Thread.zig:1534:30: 0x108f070 in entryFn (std.zig)
return callFn(f, self.fn_args);
^
/home/techatrix/repos/zig/lib/std/os/linux/x86_64.zig:105:5: 0x10b31b5 in clone (std.zig)
asm volatile (
^
Aborted (core dumped)

@squeek502

Copy link
Copy Markdown
Member

Overlaps with #25817 (cc @castholm)

@castholmcastholm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the problem I point out, the differences between this PR and #25817 is that this PR is slightly more efficient with the sizes of closure fields (2 * u8 + 2 * usize vs 3 * usize) but allocates a few more wasted bytes when the context alignment is <= the closure alignemnt.

#25817 also deduplicates the allocation code to a common init() function to avoid having the code paths going out of sync.

I could try to adapt the test to my PR if you think it'd be useful.

Comment on lines 422 to 426
fn resultPointer(ac: *AsyncClosure) [*]u8 {
const base: [*]u8 = @ptrCast(ac);
return base + ac.result_offset;
const closure_size_with_padding = @sizeOf(AsyncClosure) + ac.context_alignment.forward(@alignOf(AsyncClosure));
return @ptrFromInt(ac.result_alignment.forward(@intFromPtr(base + closure_size_with_padding)));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong to me, the code is not aware of the context length. resultPointer() will return a pointer into the middle of the context. AsyncClosure needs to remember either the computed result offset, or the context alignment + context length + result alignment to recompute it.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I adjusted it to result offset instead of the total allocated memory for the closure.

@Techatrix
Techatrixforce-pushed the io-threaded-alignment branch 2 times, most recently from 50f3eed to a00a915CompareNovember 9, 2025 23:42
@Techatrix

Copy link
Copy Markdown
ContributorAuthor

I could try to adapt the test to my PR if you think it'd be useful.

Feel free to reuse the tests in your PR.

@squeek502

Copy link
Copy Markdown
Member

Superseded by #25817

@Techatrix
Techatrix deleted the io-threaded-alignment branch November 14, 2025 07:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Techatrix@squeek502@castholm