Fix possible stack overflow in validator.
This commit is contained in:
parent
de581de6a7
commit
7dfebf99fd
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# [3.0.27] 2022-1-28
|
||||
|
||||
- Fix possible stack overflow in validator, thanks @quapka.
|
||||
|
||||
# [3.0.26] 2022-1-26
|
||||
|
||||
- Add `skip_input` attribute to `InputObject` macro, `skip_output` attribute to `SimpleObject` macro.
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| >= 3.0.0 | :white_check_mark: |
|
||||
| Version | Supported |
|
||||
|----------|--------------------|
|
||||
| >= 3.0.0 | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::parser::types::{Field, Selection, SelectionSet};
|
||||
use crate::validation::visitor::{Visitor, VisitorContext};
|
||||
|
@ -15,6 +15,7 @@ impl<'a> Visitor<'a> for OverlappingFieldsCanBeMerged {
|
|||
) {
|
||||
let mut find_conflicts = FindConflicts {
|
||||
outputs: Default::default(),
|
||||
visited: Default::default(),
|
||||
ctx,
|
||||
};
|
||||
find_conflicts.find(selection_set);
|
||||
|
@ -23,6 +24,7 @@ impl<'a> Visitor<'a> for OverlappingFieldsCanBeMerged {
|
|||
|
||||
struct FindConflicts<'a, 'ctx> {
|
||||
outputs: HashMap<&'a str, &'a Positioned<Field>>,
|
||||
visited: HashSet<&'a str>,
|
||||
ctx: &'a mut VisitorContext<'ctx>,
|
||||
}
|
||||
|
||||
|
@ -46,6 +48,13 @@ impl<'a, 'ctx> FindConflicts<'a, 'ctx> {
|
|||
if let Some(fragment) =
|
||||
self.ctx.fragment(&fragment_spread.node.fragment_name.node)
|
||||
{
|
||||
if !self
|
||||
.visited
|
||||
.insert(fragment_spread.node.fragment_name.node.as_str())
|
||||
{
|
||||
// To avoid recursing itself, this error is detected by the `NoFragmentCycles` validator.
|
||||
continue;
|
||||
}
|
||||
self.find(&fragment.node.selection_set);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,3 +54,51 @@ async fn test_flatten() {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recursive_fragment_definition() {
|
||||
#[derive(SimpleObject)]
|
||||
struct Hello {
|
||||
world: String,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
// this setup is actually completely irrelevant we just need to be able ot execute a query
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> Hello {
|
||||
Hello {
|
||||
world: "Hello World".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "fragment f on Query {...f} { __typename }";
|
||||
assert!(schema.execute(query).await.into_result().is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recursive_fragment_definition_nested() {
|
||||
#[derive(SimpleObject)]
|
||||
struct Hello {
|
||||
world: String,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
// this setup is actually completely irrelevant we just need to be able ot execute a query
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> Hello {
|
||||
Hello {
|
||||
world: "Hello World".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "fragment f on Query { a { ...f a { ...f } } } { __typename }";
|
||||
assert!(schema.execute(query).await.into_result().is_err());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue