Skip to content

libshaderc_util: make DecodeLineDirective robust to a non-canonical #line prefix#1578

Closed
adilburaksen wants to merge 1 commit into
google:mainfrom
adilburaksen:harden-decodelinedirective-prefix
Closed

libshaderc_util: make DecodeLineDirective robust to a non-canonical #line prefix#1578
adilburaksen wants to merge 1 commit into
google:mainfrom
adilburaksen:harden-decodelinedirective-prefix

Conversation

@adilburaksen

Copy link
Copy Markdown

Description

Compiler::GetShaderStageFromSourceCode guards with starts_with("#line") — five
characters, no trailing space (kLineDirective = "#line") — and then calls
DecodeLineDirective, whose own local kLineDirective is "#line " (six characters)
and which does directive.substr(kLineDirective.size()) == substr(6).

DecodeLineDirective's documented precondition (a canonicalized #line directive) is
enforced only by assert(directive.starts_with(kLineDirective)), which is compiled out
under NDEBUG. A line equal to exactly "#line" (five characters) passes the caller's
five-character check but is one character shorter than the six the callee consumes, so in
a release build string_piece::substr(6) produces a piece whose begin_ > end_ (its own
bound is likewise an assert), after which size() underflows.

This is latent in practice because glslang's preprocessor rejects a bare #line before
this code runs, so it is not a reachable defect via shader input — but the helper should
not silently rely on that. This change verifies the full canonical prefix at runtime and
returns early otherwise, so the release behavior matches the precondition regardless of
the caller. No functional change for well-formed #line <n> directives.

…refix

GetShaderStageFromSourceCode checks for the "#line" prefix (five characters,
without the trailing space) before calling DecodeLineDirective, whose local
kLineDirective is "#line " (six characters) and which does
substr(kLineDirective.size()). The precondition that the argument is a
canonical "#line " directive was enforced only by an assert, which is compiled
out in release builds, so a line equal to exactly "#line" would make
string_piece::substr advance past the end of the piece.

Verify the full canonical prefix at runtime and return early otherwise, so the
release behavior matches the documented precondition regardless of the caller.
@dneto0

dneto0 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Thanks for finding this!

The real underyling problem is that there are two definitions of kLineDirective and they are out of sync. I'll fix this another way.

dneto0 added a commit that referenced this pull request Jul 8, 2026
@dneto0

dneto0 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Fixed by #1579 instead

@dneto0 dneto0 closed this Jul 9, 2026
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