Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StackOverflow in InternalCopy #9

Open
klugerama opened this issue Oct 17, 2013 · 10 comments
Open

StackOverflow in InternalCopy #9

klugerama opened this issue Oct 17, 2013 · 10 comments

Comments

@klugerama
Copy link

In InternalCopy, there is a line:

CopyFields(originalObject, visited, cloneObject, typeToReflect);

...but then in CopyFields, you have the line:

var clonedFieldValue = InternalCopy(originalFieldValue, visited);

This results in a StackOverflow exception.

@Burtsev-Alexey
Copy link
Owner

It's recursion, it should work. Can you provide simple code describing class that result in your error?

@mrinalkamboj
Copy link

I deal with the same issue, leading to the StackOverflow exception when creating a copy of a large object, when I debugged I found the following details regarding the issue:

Method - private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
Line of Issue - "var cloneObject = CloneMethod.Invoke(originalObject, null);"
count value for the - IDictionary<Object, Object> visited is 2421, which essentially show I am trying to copy a large object

Other details that you might be keen about are:

  • Class I am trying to copy is singleton
  • It further contains multiple collection objects and reference to several Singleton classes. In fact few collections are also Singleton.

I am not sure if I have a simple way to provide you the details of the issue, as it is part of our project. Let me known in case you want me to try few options to provide debug details

Also does this need implementation of the extension methods for the child objects too, I am assuming No

@Burtsev-Alexey
Copy link
Owner

I have some new ideas about what might be the cause, I'll check them.

@mrinalkamboj
Copy link

Thanks Alex. Please let me know when you have an update, I can test the changes.
Stack overflow means recursive code is leading to infinite recursion, is it because for a given type in a class, there's no break condition

@thomasvoigt
Copy link

Hi there!

My very first attempt to copy a complex business object resulted in a stack overflow exception, too. I've nailed it down to a regular expression somewhere deep down in my object hierarchy. It's simple enough to reproduce, but unfortunately I have no idea how to fix it.

Regex re = new Regex(@"\w", RegexOptions.Compiled);
Regex re2 = re.Copy<Regex>();  // <--- StackOverflow exception

HTH and best regards,
Thomas

@Burtsev-Alexey
Copy link
Owner

Thank you, will check it out.

@Burtsev-Alexey
Copy link
Owner

Checked it, yes I can reproduce this. I know why it happen, and will fix it soon. But

  1. I do not recommend copying Regex objects, or any system objects, because they contain references for almost whole loaded .NET runtime. For example your Regex object due to Complied flag, contains reference to .NET dynamic compiler (Reflection.Code.Emit) which is getting copied too. Copying some .NET system objects can destabilize CLR, like copying Garbage Collector. This code was intended for copying user created classes.

2.I will fix this problem. The problem is in System.Reflection.Pointer object that holds Void* pointer, when I'm getting its value, it returns new Object (different object Reference) but it points to same memory address. So we have endless cycle because, the field value always return new Object instance, note that its not recursion (I store visited nodes), its endless stream of objects.

@Burtsev-Alexey
Copy link
Owner

I was able to solve the problem with unmanaged pointers, but your object with Regex still will not work, the problem is in System.Reflection.Emit.SignatureHelper class that is used inside Regex, it's GetHashCode() is poorly implemented and throw NullReferenceException

public override int GetHashCode()
{
  int num = this.m_module.GetHashCode() + this.m_currSig + this.m_sizeLoc;
  if (this.m_sigDone)
    ++num;
  for (int index = 0; index < this.m_currSig; ++index)
    num += this.m_signature[index].GetHashCode();
  return num;
}

notice the usage of m_module, it's null in your example.

@Burtsev-Alexey
Copy link
Owner

I'm not sure I want to commit the unmanaged pointers fix. Though it will fix some problems, but this is far beyond this code usage. If I will start dealing with unmanaged memory, its not gonna end well.
You can disable unmanaged pointers cloning by returning same object or null, like this:

    private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
    {
        if (originalObject == null) return null;
        var typeToReflect = originalObject.GetType();
        if (IsPrimitive(typeToReflect)) return originalObject;
        if (visited.ContainsKey(originalObject)) return visited[originalObject];
        if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
        if (typeof (Pointer) == typeToReflect) return null;
        var cloneObject = CloneMethod.Invoke(originalObject, null);
        if (typeToReflect.IsArray)
        {
            var arrayType = typeToReflect.GetElementType();
            if (IsPrimitive(arrayType) == false)
            {
                Array clonedArray = (Array)cloneObject;
                clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));
            }

        }
        visited.Add(originalObject, cloneObject);
        CopyFields(originalObject, visited, cloneObject, typeToReflect);
        RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect);
        return cloneObject;
    }

@skadarsh
Copy link

skadarsh commented Dec 3, 2015

Hi Burtsev,
I am using the same ObjectExtensions.cs, And I am getting the same StackOverflow exception for certain object copy. It is coming in
var cloneObject = CloneMethod.Invoke(originalObject, null);
Do you happen to have any updated version of the ObjectExtensions.cs? It would really help and thanks in advance.

Thanks and Regards,
Adarsh S K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants