Browse Source

Prevent potential stack overflow in ElementReturnType.BaseType.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3896 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
7674e2dc2f
  1. 1
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj
  2. 56
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/BusyManager.cs
  3. 39
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ElementReturnType.cs
  4. 124
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs

1
src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj

@ -62,6 +62,7 @@ @@ -62,6 +62,7 @@
<Compile Include="..\..\GlobalAssemblyInfo.cs">
<Link>Configuration\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Src\BusyManager.cs" />
<Compile Include="Src\CSharp\OverloadResolution.cs" />
<Compile Include="Src\CSharp\TypeInference.cs" />
<Compile Include="Src\DomCache.cs" />

56
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/BusyManager.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Dom
{
/// <summary>
/// This class is used to prevent stack overflows by representing a 'busy' flag
/// that prevents reentrance when another call is running.
/// However, using a simple 'bool busy' is not thread-safe, so we use a
/// thread-static BusyManager.
/// </summary>
sealed class BusyManager
{
public struct BusyLock : IDisposable
{
public static readonly BusyLock Failed = new BusyLock(null);
readonly BusyManager manager;
public BusyLock(BusyManager manager)
{
this.manager = manager;
}
public bool Success {
get { return manager != null; }
}
public void Dispose()
{
if (manager != null) {
manager.activeObjects.RemoveAt(manager.activeObjects.Count - 1);
}
}
}
readonly List<object> activeObjects = new List<object>();
public BusyLock Enter(object obj)
{
for (int i = 0; i < activeObjects.Count; i++) {
if (activeObjects[i] == obj)
return BusyLock.Failed;
}
activeObjects.Add(obj);
return new BusyLock(this);
}
}
}

39
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ElementReturnType.cs

@ -28,24 +28,35 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -28,24 +28,35 @@ namespace ICSharpCode.SharpDevelop.Dom
this.pc = pc;
}
[ThreadStatic] static BusyManager _busyManager;
static BusyManager busyManager {
get { return _busyManager ?? (_busyManager = new BusyManager()); }
}
public override IReturnType BaseType {
get {
// get element type from enumerableType
if (enumerableType.IsArrayReturnType)
return enumerableType.CastToArrayReturnType().ArrayElementType;
IClass c = enumerableType.GetUnderlyingClass();
if (c == null)
using (var l = busyManager.Enter(this)) {
if (!l.Success)
return null;
// get element type from enumerableType
if (enumerableType.IsArrayReturnType)
return enumerableType.CastToArrayReturnType().ArrayElementType;
IClass c = enumerableType.GetUnderlyingClass();
if (c == null)
return null;
IClass genumerable = pc.GetClass("System.Collections.Generic.IEnumerable", 1);
if (c.IsTypeInInheritanceTree(genumerable)) {
return MemberLookupHelper.GetTypeParameterPassedToBaseClass(enumerableType, genumerable, 0);
}
IClass enumerable = pc.GetClass("System.Collections.IEnumerable", 0);
if (c.IsTypeInInheritanceTree(enumerable)) {
return pc.SystemTypes.Object;
}
return null;
IClass genumerable = pc.GetClass("System.Collections.Generic.IEnumerable", 1);
if (c.IsTypeInInheritanceTree(genumerable)) {
return MemberLookupHelper.GetTypeParameterPassedToBaseClass(enumerableType, genumerable, 0);
}
IClass enumerable = pc.GetClass("System.Collections.IEnumerable", 0);
if (c.IsTypeInInheritanceTree(enumerable)) {
return pc.SystemTypes.Object;
}
return null;
}
}

124
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs

@ -33,17 +33,17 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -33,17 +33,17 @@ namespace ICSharpCode.SharpDevelop.Dom
return true;
IReturnType baseType = BaseType;
bool tmp = (baseType != null && TryEnter()) ? baseType.Equals(other) : false;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.Equals(other) : false;
}
}
public override int GetHashCode()
{
IReturnType baseType = BaseType;
int tmp = (baseType != null && TryEnter()) ? baseType.GetHashCode() : 0;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetHashCode() : 0;
}
}
protected int GetObjectHashCode()
@ -52,121 +52,103 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -52,121 +52,103 @@ namespace ICSharpCode.SharpDevelop.Dom
}
// Required to prevent stack overflow on inferrence cycles
bool busy;
// keep this method as small as possible, it should be inlined!
bool TryEnter()
{
if (busy) {
PrintTryEnterWarning();
return false;
} else {
busy = true;
return true;
}
}
void Leave()
{
busy = false;
}
[ThreadStatic] static BusyManager _busyManager;
void PrintTryEnterWarning()
{
LoggingService.Info("TryEnter failed on " + ToString());
static BusyManager busyManager {
get { return _busyManager ?? (_busyManager = new BusyManager()); }
}
public virtual string FullyQualifiedName {
get {
IReturnType baseType = BaseType;
string tmp = (baseType != null && TryEnter()) ? baseType.FullyQualifiedName : "?";
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.FullyQualifiedName : "?";
}
}
}
public virtual string Name {
get {
IReturnType baseType = BaseType;
string tmp = (baseType != null && TryEnter()) ? baseType.Name : "?";
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.Name : "?";
}
}
}
public virtual string Namespace {
get {
IReturnType baseType = BaseType;
string tmp = (baseType != null && TryEnter()) ? baseType.Namespace : "?";
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.Namespace : "?";
}
}
}
public virtual string DotNetName {
get {
IReturnType baseType = BaseType;
string tmp = (baseType != null && TryEnter()) ? baseType.DotNetName : "?";
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.DotNetName : "?";
}
}
}
public virtual int TypeArgumentCount {
get {
IReturnType baseType = BaseType;
int tmp = (baseType != null && TryEnter()) ? baseType.TypeArgumentCount : 0;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.TypeArgumentCount : 0;
}
}
}
public virtual IClass GetUnderlyingClass()
{
IReturnType baseType = BaseType;
IClass tmp = (baseType != null && TryEnter()) ? baseType.GetUnderlyingClass() : null;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetUnderlyingClass() : null;
}
}
public virtual List<IMethod> GetMethods()
{
IReturnType baseType = BaseType;
List<IMethod> tmp = (baseType != null && TryEnter()) ? baseType.GetMethods() : new List<IMethod>();
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetMethods() : new List<IMethod>();
}
}
public virtual List<IProperty> GetProperties()
{
IReturnType baseType = BaseType;
List<IProperty> tmp = (baseType != null && TryEnter()) ? baseType.GetProperties() : new List<IProperty>();
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetProperties() : new List<IProperty>();
}
}
public virtual List<IField> GetFields()
{
IReturnType baseType = BaseType;
List<IField> tmp = (baseType != null && TryEnter()) ? baseType.GetFields() : new List<IField>();
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetFields() : new List<IField>();
}
}
public virtual List<IEvent> GetEvents()
{
IReturnType baseType = BaseType;
List<IEvent> tmp = (baseType != null && TryEnter()) ? baseType.GetEvents() : new List<IEvent>();
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetEvents() : new List<IEvent>();
}
}
public virtual bool IsDefaultReturnType {
get {
IReturnType baseType = BaseType;
bool tmp = (baseType != null && TryEnter()) ? baseType.IsDefaultReturnType : false;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.IsDefaultReturnType : false;
}
}
}
@ -178,13 +160,9 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -178,13 +160,9 @@ namespace ICSharpCode.SharpDevelop.Dom
public virtual T CastToDecoratingReturnType<T>() where T : DecoratingReturnType
{
IReturnType baseType = BaseType;
T temp;
if (baseType != null && TryEnter())
temp = baseType.CastToDecoratingReturnType<T>();
else
temp = null;
Leave();
return temp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.CastToDecoratingReturnType<T>() : null;
}
}
@ -221,18 +199,18 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -221,18 +199,18 @@ namespace ICSharpCode.SharpDevelop.Dom
public virtual bool? IsReferenceType {
get {
IReturnType baseType = BaseType;
bool? tmp = (baseType != null && TryEnter()) ? baseType.IsReferenceType : null;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.IsReferenceType : null;
}
}
}
public virtual IReturnType GetDirectReturnType()
{
IReturnType baseType = BaseType;
IReturnType tmp = (baseType != null && TryEnter()) ? baseType.GetDirectReturnType() : UnknownReturnType.Instance;
Leave();
return tmp;
using (var l = busyManager.Enter(this)) {
return (l.Success && baseType != null) ? baseType.GetDirectReturnType() : UnknownReturnType.Instance;
}
}
}
}

Loading…
Cancel
Save