Merge pull request #5370 from microsoft/fix/stack-overflow

fix/stack overflow
This commit is contained in:
Vincent Biret 2024-09-10 08:55:57 -04:00 коммит произвёл GitHub
Родитель bb90c48ce8 6eecf1ad84
Коммит 7a39ecff15
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
6 изменённых файлов: 32 добавлений и 27 удалений

Просмотреть файл

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Fixed a stack overflow in the core generator caused by circular comparisons. [#5369](https://github.com/microsoft/kiota/issues/5369)
- Fixed a bug where collection/array of primitive types members for union/intersection types would be ignored. [#5283](https://github.com/microsoft/kiota/issues/5283)
- Fixed a when generating a plugin when only an operation is selected in the root node in the extension. [#5300](https://github.com/microsoft/kiota/issues/5300)
- Fixed a bug where function descriptions in plugin manifest defaults to path summary instead of description[#5301](https://github.com/microsoft/kiota/issues/5301)

Просмотреть файл

@ -43,10 +43,12 @@ public class ApiDependencyComparer : IEqualityComparer<ApiDependency>
string? xExtensions = GetDependencyExtensionsValue(x), yExtensions = GetDependencyExtensionsValue(y);
// Assume requests are equal if we aren't comparing them.
var requestsEqual = !_compareRequests || x.Requests.SequenceEqual(y.Requests, _requestInfoComparer);
var requestsEqual = !_compareRequests || GetOrderedRequests(x.Requests).SequenceEqual(GetOrderedRequests(y.Requests), _requestInfoComparer);
return _stringComparer.Equals(xExtensions, yExtensions)
&& requestsEqual;
}
private static IOrderedEnumerable<RequestInfo> GetOrderedRequests(IList<RequestInfo> requests) =>
requests.OrderBy(x => x.UriTemplate, StringComparer.Ordinal).ThenBy(x => x.Method, StringComparer.Ordinal);
/// <inheritdoc/>
public int GetHashCode([DisallowNull] ApiDependency obj)
{
@ -56,7 +58,7 @@ public class ApiDependencyComparer : IEqualityComparer<ApiDependency>
hash.Add(GetDependencyExtensionsValue(obj) ?? string.Empty, _stringComparer);
if (!_compareRequests) return hash.ToHashCode();
foreach (var request in obj.Requests)
foreach (var request in GetOrderedRequests(obj.Requests))
{
hash.Add(request, _requestInfoComparer);
}

Просмотреть файл

@ -27,7 +27,9 @@ internal class OpenApiSchemaComparer : IEqualityComparer<OpenApiSchema>
/// <inheritdoc/>
public bool Equals(OpenApiSchema? x, OpenApiSchema? y)
{
return EqualsInternal(x, y);
// this workaround might result in collisions, however so far this has not been a problem
// implemented this way to avoid stack overflow caused by schemas referencing themselves
return x == null && y == null || x != null && y != null && GetHashCode(x) == GetHashCode(y);
}
/// <inheritdoc/>
public int GetHashCode([DisallowNull] OpenApiSchema obj)
@ -37,25 +39,6 @@ internal class OpenApiSchemaComparer : IEqualityComparer<OpenApiSchema>
return hash.ToHashCode();
}
private bool EqualsInternal(OpenApiSchema? x, OpenApiSchema? y)
{
if (x is null || y is null) return object.Equals(x, y);
return x.Deprecated == y.Deprecated
&& x.Nullable == y.Nullable
&& x.AdditionalPropertiesAllowed == y.AdditionalPropertiesAllowed
&& discriminatorComparer.Equals(x.Discriminator, y.Discriminator)
&& string.Equals(x.Format, y.Format, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.Type, y.Type, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.Title, y.Title, StringComparison.Ordinal)
&& openApiAnyComparer.Equals(x.Default, y.Default)
&& EqualsInternal(x.AdditionalProperties, y.AdditionalProperties)
&& EqualsInternal(x.Items, y.Items)
&& Enumerable.SequenceEqual(x.Properties, y.Properties, schemaMapComparer)
&& Enumerable.SequenceEqual(x.AnyOf, y.AnyOf, this)
&& Enumerable.SequenceEqual(x.AllOf, y.AllOf, this)
&& Enumerable.SequenceEqual(x.OneOf, y.OneOf, this);
}
private void GetHashCodeInternal([DisallowNull] OpenApiSchema obj, HashSet<OpenApiSchema> visitedSchemas, ref HashCode hash)
{
if (obj is null) return;
@ -143,15 +126,17 @@ internal class OpenApiDiscriminatorComparer : IEqualityComparer<OpenApiDiscrimin
public bool Equals(OpenApiDiscriminator? x, OpenApiDiscriminator? y)
{
if (x is null || y is null) return object.Equals(x, y);
return x.PropertyName.EqualsIgnoreCase(y.PropertyName) && x.Mapping.SequenceEqual(y.Mapping, mappingComparer);
return x.PropertyName.EqualsIgnoreCase(y.PropertyName) && GetOrderedRequests(x.Mapping).SequenceEqual(GetOrderedRequests(y.Mapping), mappingComparer);
}
private static IOrderedEnumerable<KeyValuePair<string, string>> GetOrderedRequests(IDictionary<string, string> mappings) =>
mappings.OrderBy(x => x.Key, StringComparer.Ordinal);
/// <inheritdoc/>
public int GetHashCode([DisallowNull] OpenApiDiscriminator obj)
{
var hash = new HashCode();
if (obj == null) return hash.ToHashCode();
hash.Add(obj.PropertyName);
foreach (var mapping in obj.Mapping)
foreach (var mapping in GetOrderedRequests(obj.Mapping))
{
hash.Add(mapping, mappingComparer);
}

Просмотреть файл

@ -23,7 +23,7 @@ public class ApiPluginConfigurationComparer : BaseApiConsumerConfigurationCompar
public override bool Equals(ApiPluginConfiguration? x, ApiPluginConfiguration? y)
{
if (x is null || y is null) return object.Equals(x, y);
return x.Types.SequenceEqual(y.Types, _stringComparer) && base.Equals(x, y);
return _stringIEnumerableDeepComparer.Equals(x.Types, y.Types) && base.Equals(x, y);
}
/// <inheritdoc/>

Просмотреть файл

@ -23,8 +23,7 @@ public abstract class BaseApiConsumerConfigurationComparer<T> : IEqualityCompare
if (x is null || y is null) return object.Equals(x, y);
return _stringComparer.Equals(x.DescriptionLocation, y.DescriptionLocation)
&& _stringComparer.Equals(x.OutputPath, y.OutputPath)
&& x.IncludePatterns.SequenceEqual(y.IncludePatterns, _stringComparer)
&& x.ExcludePatterns.SequenceEqual(y.ExcludePatterns, _stringComparer);
&& _stringIEnumerableDeepComparer.Equals(x.IncludePatterns, y.IncludePatterns);
}
public virtual int GetHashCode([DisallowNull] T obj)

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using Kiota.Builder.Validation;
using Microsoft.OpenApi.Models;
using Xunit;
namespace Kiota.Builder.Tests.Validation;
@ -21,4 +22,21 @@ public class OpenApiSchemaComparerTests
{
Assert.True(_comparer.Equals(new(), new()));
}
[Fact]
public void DoesNotStackOverFlowOnCircularReferencesForEquals()
{
var schema = new OpenApiSchema
{
};
schema.Properties.Add("test", schema);
schema.AnyOf.Add(schema);
var schema2 = new OpenApiSchema
{
};
schema2.Properties.Add("test", schema2);
schema2.AnyOf.Add(schema2);
Assert.True(_comparer.Equals(schema, schema2));
}
}