Skip to content

Commit d220bf1

Browse files
committed
rustdoc-search: avoid infinite where clause unbox
Fixes #118242
1 parent b06258c commit d220bf1

File tree

3 files changed

+61
-6
lines changed

3 files changed

+61
-6
lines changed

src/librustdoc/html/static/js/search.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -1755,17 +1755,26 @@ function initSearch(rawSearchIndex) {
17551755
if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
17561756
return false;
17571757
}
1758+
// Where clauses can represent cyclical data.
1759+
// `null` prevents it from trying to unbox in an infinite loop
1760+
const mgensTmp = new Map(mgens);
1761+
mgensTmp.set(fnType.id, null);
17581762
// This is only a potential unbox if the search query appears in the where clause
17591763
// for example, searching `Read -> usize` should find
17601764
// `fn read_all<R: Read>(R) -> Result<usize>`
17611765
// generic `R` is considered "unboxed"
1762-
return checkIfInList(whereClause[(-fnType.id) - 1], queryElem, whereClause);
1766+
return checkIfInList(
1767+
whereClause[(-fnType.id) - 1],
1768+
queryElem,
1769+
whereClause,
1770+
mgensTmp
1771+
);
17631772
} else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
17641773
const simplifiedGenerics = [
17651774
...fnType.generics,
17661775
...Array.from(fnType.bindings.values()).flat(),
17671776
];
1768-
return checkIfInList(simplifiedGenerics, queryElem, whereClause);
1777+
return checkIfInList(simplifiedGenerics, queryElem, whereClause, mgens);
17691778
}
17701779
return false;
17711780
}
@@ -1777,12 +1786,13 @@ function initSearch(rawSearchIndex) {
17771786
* @param {Array<FunctionType>} list
17781787
* @param {QueryElement} elem - The element from the parsed query.
17791788
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
1789+
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
17801790
*
17811791
* @return {boolean} - Returns true if found, false otherwise.
17821792
*/
1783-
function checkIfInList(list, elem, whereClause) {
1793+
function checkIfInList(list, elem, whereClause, mgens) {
17841794
for (const entry of list) {
1785-
if (checkType(entry, elem, whereClause)) {
1795+
if (checkType(entry, elem, whereClause, mgens)) {
17861796
return true;
17871797
}
17881798
}
@@ -1796,10 +1806,11 @@ function initSearch(rawSearchIndex) {
17961806
* @param {Row} row
17971807
* @param {QueryElement} elem - The element from the parsed query.
17981808
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
1809+
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
17991810
*
18001811
* @return {boolean} - Returns true if the type matches, false otherwise.
18011812
*/
1802-
function checkType(row, elem, whereClause) {
1813+
function checkType(row, elem, whereClause, mgens) {
18031814
if (row.bindings.size === 0 && elem.bindings.size === 0) {
18041815
if (elem.id < 0) {
18051816
return row.id < 0 || checkIfInList(row.generics, elem, whereClause);
@@ -1812,7 +1823,7 @@ function initSearch(rawSearchIndex) {
18121823
return row.id === elem.id || checkIfInList(row.generics, elem, whereClause);
18131824
}
18141825
}
1815-
return unifyFunctionTypes([row], [elem], whereClause);
1826+
return unifyFunctionTypes([row], [elem], whereClause, mgens);
18161827
}
18171828

18181829
function checkPath(contains, ty, maxEditDistance) {

tests/rustdoc-js/assoc-type-loop.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Crash reduction of
2+
// https://github.com/rust-lang/rust/issues/118242
3+
4+
const EXPECTED = [
5+
{
6+
'query': 't',
7+
'correction': null,
8+
},
9+
];

tests/rustdoc-js/assoc-type-loop.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![crate_name="foo"]
2+
3+
// reduced from sqlx 0.7.3
4+
use std::future::Future;
5+
use std::pin::Pin;
6+
use std::ops::{Deref, DerefMut};
7+
pub enum Error {}
8+
pub trait Acquire<'c> {
9+
type Database: Database;
10+
type Connection: Deref<Target = <Self::Database as Database>::Connection> + DerefMut + Send;
11+
}
12+
pub trait Database {
13+
type Connection: Connection<Database = Self>;
14+
}
15+
pub trait Connection {
16+
type Database: Database;
17+
type Options: ConnectionOptions<Connection = Self>;
18+
fn begin(
19+
&mut self
20+
) -> Pin<Box<dyn Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_>>
21+
where
22+
Self: Sized;
23+
}
24+
pub trait ConnectionOptions {
25+
type Connection: Connection;
26+
}
27+
pub struct Transaction<'c, DB: Database> {
28+
_db: &'c DB,
29+
}
30+
impl<'t, 'c, DB: Database> Acquire<'t> for &'t mut Transaction<'c, DB>
31+
where <DB as Database>::Connection: Send
32+
{
33+
type Database = DB;
34+
type Connection = &'t mut <DB as Database>::Connection;
35+
}

0 commit comments

Comments
 (0)