Skip to content

fix(c,cpp): quadratic ReDoS in FUNCTION_DECLARATION regex (#4362)#4413

Open
xxiaoxiong wants to merge 2 commits into
highlightjs:mainfrom
xxiaoxiong:fix/c-cpp-redos-function-declaration
Open

fix(c,cpp): quadratic ReDoS in FUNCTION_DECLARATION regex (#4362)#4413
xxiaoxiong wants to merge 2 commits into
highlightjs:mainfrom
xxiaoxiong:fix/c-cpp-redos-function-declaration

Conversation

@xxiaoxiong
Copy link
Copy Markdown

Description

Fixes a quadratic ReDoS vulnerability in the C/C++ FUNCTION_DECLARATION regex.

Root Cause

The pattern for FUNCTION_DECLARATION contains a nested quantifier:

begin: '(' + FUNCTION_TYPE_RE + '[\*&\s]+)+' + FUNCTION_TITLE,

The outer + wraps a group whose inner [\*&\s]+ also uses +. When applied to input without a matching function title (e.g. repeated words separated by spaces), the regex engine tries all possible ways to partition whitespace between the inner and outer groups, resulting in O(n²) backtracking.

Fix

Restructured the pattern to avoid the nested quantifier by splitting the outer + into an outer * (repeating type+modifier pairs) plus a final optional type pair:

begin: '(' + FUNCTION_TYPE_RE + '\s*[\*&]+\s*)*(?:' + FUNCTION_TYPE_RE + '\s*[\*&]*\s*)?' + FUNCTION_TITLE,

PoC

const hljs = require('highlight.js');
for (const n of [2000, 4000, 8000, 16000, 32000]) {
  const start = process.hrtime.bigint();
  hljs.highlight('a '.repeat(n), { language: 'c', ignoreIllegals: true });
  const ms = Number(process.hrtime.bigint() - start) / 1e6;
  console.log(`len=${(n*2).toString().padStart(6)}: ${ms.toFixed(0)}ms`);
}

Affected Languages

  • C (c.js)
  • C++ (cpp.js)
  • Arduino (inherits from C++)

Fixes #4362

…ion with array syntax

When TypeScript uses angle bracket type assertions with array syntax
(e.g. `<string[]>value`), the XML_TAG pattern in JavaScript grammar
was incorrectly matching `<string` as a potential HTML tag start.
Since `[` cannot appear immediately after an HTML tag name, this
change marks it as a non-HTML pattern, preserving correct highlighting
for TypeScript type assertions.

Fixes highlightjs#4301
The begin pattern '(' + FUNCTION_TYPE_RE + '[\*&\s]+)+' + FUNCTION_TITLE
contains a nested quantifier: the outer + wraps a group that itself
contains [\*&\s]+. When applied to input without a matching function
title (e.g. repeated words separated by spaces), the regex engine tries
all possible ways to partition whitespace between inner and outer
groups, resulting in O(n^2) backtracking.

Fix by restructuring the pattern to avoid nested quantifiers:
  (' + FUNCTION_TYPE_RE + '\s*[\*&]+\s*)*(?:' + FUNCTION_TYPE_RE
  + '\s*[\*&]*\s*)?' + FUNCTION_TITLE

The outer + is split into an outer * (repeating type+modifier pairs)
and a final optional type pair, with whitespace and pointer/reference
operators matched separately in each group rather than in a single
overlapping character class. This eliminates the quadratic backtracking
while preserving the original matching semantics.

Fixes highlightjs#4362

Affects: C (c.js) and C++ (cpp.js), inherited by Arduino.
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.

Security: Quadratic ReDoS in C/C++/Arduino FUNCTION_DECLARATION regex (v11.11.1)

1 participant