Skip to content

tp: work around clang compiler vectorization bug#170

Open
cdamus wants to merge 2 commits intosokatoafrom
issue/sokatoa-4933-clang21-bug
Open

tp: work around clang compiler vectorization bug#170
cdamus wants to merge 2 commits intosokatoafrom
issue/sokatoa-4933-clang21-bug

Conversation

@cdamus
Copy link
Copy Markdown
Collaborator

@cdamus cdamus commented Mar 27, 2026

Apple Clang 21 (macOS 26.4 / Xcode 26) has a vectorization bug that miscompiles the WebSocket unmasking loop in http_server.cc. The pattern mask[i % sizeof(mask)] with a 4-byte mask is compiled into a vector where every other group of 4 bytes is XORed with zero: bytes 0–3 are correctly unmasked, bytes 4–7 stay masked, bytes 8–11 correct,
12–15 masked, etc.

This caused the RPC request field (bytes 4–5 of the inner proto) to be left at its masked value (0x52 instead of 0x10=field-2-varint-tag), which decoded as field_id=10/wire_type=2 instead of field_id=2/varint, making req.request() return 0 (TPM_UNSPECIFIED). The server responded with invalid_request=0.

Also included in this PR is a fix in the Perfetto UI side of the Engine class to fix the application hanging on unexpected results like this from the trace processor shell. So with the broken trace processor that commit 1b1b439 lets the error be shown in the usual way in the Sokatoa Capture Widget instead of it showing a loading spinner forever.

These changes should, of course, work just fine with any other version of the or clang compiler or gcc.


@wpaul-samsung this is the problem I reported initially on your yarn upgrade PR in Sokatoa, which I hadn't realized at the time coincided with an OS/Xcode upgrade on my system.

cdamus added 2 commits March 27, 2026 16:30
When the trace processor shell returns a protocol error response, the
engine communicating with it just hangs. The engine must accurately
detect the protocol error response and then flush its pending state.
This then lets the error be thrown to Sokatoa for reporting to the user.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
Apple Clang 21 (macOS 26.4 / Xcode 26) has a vectorization bug that
miscompiles the WebSocket unmasking loop in http_server.cc. The pattern
mask[i % sizeof(mask)] with a 4-byte mask is compiled into a vector
where every other group of 4 bytes is XORed with zero: bytes 0–3 are
correctly unmasked, bytes 4–7 stay masked, bytes 8–11 correct,
12–15 masked, etc.

This caused the RPC request field (bytes 4–5 of the inner proto) to be
left at its masked value (0x52 instead of 0x10=field-2-varint-tag),
which decoded as field_id=10/wire_type=2 instead of field_id=2/varint,
making req.request() return 0 (TPM_UNSPECIFIED). The server responded
with invalid_request=0.

For android-graphics/sokatoa#4933

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
Copy link
Copy Markdown
Collaborator

@colin-grant-work colin-grant-work left a comment

Choose a reason for hiding this comment

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

Without this change, I see the load failure reported; with this change, traces load successfully.

Comment on lines +692 to +725
// Reject all pending operations so callers don't hang forever when the
// engine enters a failed state (e.g. after receiving an invalid_request).
for (const p of this.pendingParses) p.reject(error);
this.pendingParses = [];
for (const p of this.pendingEOFs) p.reject(error);
this.pendingEOFs = [];
for (const p of this.pendingResetTraceProcessors) p.reject(error);
this.pendingResetTraceProcessors = [];
for (const p of this.pendingRestoreTables) p.reject(error);
this.pendingRestoreTables = [];
for (const p of this.pendingComputeMetrics) p.reject(error);
this.pendingComputeMetrics = [];
this.pendingReadMetatrace?.reject(error);
this.pendingReadMetatrace = undefined;
this.pendingRegisterSqlPackage?.reject(error);
this.pendingRegisterSqlPackage = undefined;
this.pendingAnalyzeStructuredQueries?.reject(error);
this.pendingAnalyzeStructuredQueries = undefined;
this.pendingTraceSummary?.reject(error);
this.pendingTraceSummary = undefined;
// Complete any pending streaming queries with an error result.
// WritableQueryResult has no reject() method — errors are signalled by
// calling appendResultBatch() with a QueryResult proto that has `error`
// set and a final batch with `is_last_batch=true`.
if (this.pendingQueries.length > 0) {
const errBatch = protos.QueryResult.encode(
protos.QueryResult.create({
error: reason,
batch: [protos.QueryResult.CellsBatch.create({isLastBatch: true})],
}),
).finish();
for (const q of this.pendingQueries) q.appendResultBatch(errBatch);
this.pendingQueries = [];
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Breaking this out into something like a rejectAllPending function would make its goal clear without the opening comment.

Sign up for free to 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.

2 participants