rustdoc-search: avoid infinite where clause unbox

Fixes #118242
This commit is contained in:
Michael Howell 2023-11-24 09:47:55 -07:00
parent b06258cde4
commit 1b7b9540fe
3 changed files with 68 additions and 8 deletions

View File

@ -1755,17 +1755,26 @@ function initSearch(rawSearchIndex) {
if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
return false;
}
// Where clauses can represent cyclical data.
// `null` prevents it from trying to unbox in an infinite loop
const mgensTmp = new Map(mgens);
mgensTmp.set(fnType.id, null);
// This is only a potential unbox if the search query appears in the where clause
// for example, searching `Read -> usize` should find
// `fn read_all<R: Read>(R) -> Result<usize>`
// generic `R` is considered "unboxed"
return checkIfInList(whereClause[(-fnType.id) - 1], queryElem, whereClause);
return checkIfInList(
whereClause[(-fnType.id) - 1],
queryElem,
whereClause,
mgensTmp
);
} else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
const simplifiedGenerics = [
...fnType.generics,
...Array.from(fnType.bindings.values()).flat(),
];
return checkIfInList(simplifiedGenerics, queryElem, whereClause);
return checkIfInList(simplifiedGenerics, queryElem, whereClause, mgens);
}
return false;
}
@ -1777,12 +1786,13 @@ function initSearch(rawSearchIndex) {
* @param {Array<FunctionType>} list
* @param {QueryElement} elem - The element from the parsed query.
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
*
* @return {boolean} - Returns true if found, false otherwise.
*/
function checkIfInList(list, elem, whereClause) {
function checkIfInList(list, elem, whereClause, mgens) {
for (const entry of list) {
if (checkType(entry, elem, whereClause)) {
if (checkType(entry, elem, whereClause, mgens)) {
return true;
}
}
@ -1796,23 +1806,29 @@ function initSearch(rawSearchIndex) {
* @param {Row} row
* @param {QueryElement} elem - The element from the parsed query.
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
*
* @return {boolean} - Returns true if the type matches, false otherwise.
*/
function checkType(row, elem, whereClause) {
function checkType(row, elem, whereClause, mgens) {
if (row.bindings.size === 0 && elem.bindings.size === 0) {
if (elem.id < 0) {
return row.id < 0 || checkIfInList(row.generics, elem, whereClause);
return row.id < 0 || checkIfInList(row.generics, elem, whereClause, mgens);
}
if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
// special case
elem.id !== typeNameIdOfArrayOrSlice
) {
return row.id === elem.id || checkIfInList(row.generics, elem, whereClause);
return row.id === elem.id || checkIfInList(
row.generics,
elem,
whereClause,
mgens
);
}
}
return unifyFunctionTypes([row], [elem], whereClause);
return unifyFunctionTypes([row], [elem], whereClause, mgens);
}
function checkPath(contains, ty, maxEditDistance) {

View File

@ -0,0 +1,9 @@
// Crash reduction of
// https://github.com/rust-lang/rust/issues/118242
const EXPECTED = [
{
'query': 't',
'correction': null,
},
];

View File

@ -0,0 +1,35 @@
#![crate_name="foo"]
// reduced from sqlx 0.7.3
use std::future::Future;
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
pub enum Error {}
pub trait Acquire<'c> {
type Database: Database;
type Connection: Deref<Target = <Self::Database as Database>::Connection> + DerefMut + Send;
}
pub trait Database {
type Connection: Connection<Database = Self>;
}
pub trait Connection {
type Database: Database;
type Options: ConnectionOptions<Connection = Self>;
fn begin(
&mut self
) -> Pin<Box<dyn Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_>>
where
Self: Sized;
}
pub trait ConnectionOptions {
type Connection: Connection;
}
pub struct Transaction<'c, DB: Database> {
_db: &'c DB,
}
impl<'t, 'c, DB: Database> Acquire<'t> for &'t mut Transaction<'c, DB>
where <DB as Database>::Connection: Send
{
type Database = DB;
type Connection = &'t mut <DB as Database>::Connection;
}