1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.Reflection; 7 using System.Globalization; 8 9 namespace System.Runtime.Serialization 10 { 11 public class ObjectManager 12 { 13 private const int DefaultInitialSize = 16; 14 private const int MaxArraySize = 0x100000; //MUST BE A POWER OF 2! 15 private const int ArrayMask = MaxArraySize - 1; 16 private const int MaxReferenceDepth = 100; 17 18 private DeserializationEventHandler _onDeserializationHandler; 19 private SerializationEventHandler _onDeserializedHandler; 20 21 internal ObjectHolder[] _objects; 22 internal object _topObject = null; 23 internal ObjectHolderList _specialFixupObjects; //This is IObjectReference, ISerializable, or has a Surrogate. 24 internal long _fixupCount; 25 internal readonly ISurrogateSelector _selector; 26 internal readonly StreamingContext _context; 27 private readonly bool _isCrossAppDomain; 28 ObjectManager(ISurrogateSelector selector, StreamingContext context)29 public ObjectManager(ISurrogateSelector selector, StreamingContext context) : this(selector, context, true, false) 30 { 31 } 32 ObjectManager(ISurrogateSelector selector, StreamingContext context, bool checkSecurity, bool isCrossAppDomain)33 internal ObjectManager(ISurrogateSelector selector, StreamingContext context, bool checkSecurity, bool isCrossAppDomain) 34 { 35 _objects = new ObjectHolder[DefaultInitialSize]; 36 _selector = selector; 37 _context = context; 38 _isCrossAppDomain = isCrossAppDomain; 39 } 40 41 private bool CanCallGetType(object obj) => true; 42 43 internal object TopObject 44 { 45 set { _topObject = value; } 46 get { return _topObject; } 47 } 48 49 internal ObjectHolderList SpecialFixupObjects => 50 _specialFixupObjects ?? (_specialFixupObjects = new ObjectHolderList()); 51 FindObjectHolder(long objectID)52 internal ObjectHolder FindObjectHolder(long objectID) 53 { 54 // The index of the bin in which we live is rightmost n bits of the objectID. 55 int index = (int)(objectID & ArrayMask); 56 if (index >= _objects.Length) 57 { 58 return null; 59 } 60 61 // Find the bin in which we live. 62 ObjectHolder temp = _objects[index]; 63 64 // Walk the chain in that bin. Return the ObjectHolder if we find it, otherwise 65 // return null. 66 while (temp != null) 67 { 68 if (temp._id == objectID) 69 { 70 return temp; 71 } 72 temp = temp._next; 73 } 74 75 return temp; 76 } 77 FindOrCreateObjectHolder(long objectID)78 internal ObjectHolder FindOrCreateObjectHolder(long objectID) 79 { 80 ObjectHolder holder; 81 holder = FindObjectHolder(objectID); 82 if (holder == null) 83 { 84 holder = new ObjectHolder(objectID); 85 AddObjectHolder(holder); 86 } 87 return holder; 88 } 89 AddObjectHolder(ObjectHolder holder)90 private void AddObjectHolder(ObjectHolder holder) 91 { 92 Debug.Assert(holder != null, "holder!=null"); 93 Debug.Assert(holder._id >= 0, "holder.m_id>=0"); 94 95 //If the id that we need to place is greater than our current length, and less 96 //than the maximum allowable size of the array. We need to double the size 97 //of the array. If the array has already reached it's maximum allowable size, 98 //we chain elements off of the buckets. 99 if (holder._id >= _objects.Length && _objects.Length != MaxArraySize) 100 { 101 int newSize = MaxArraySize; 102 103 if (holder._id < (MaxArraySize / 2)) 104 { 105 newSize = (_objects.Length * 2); 106 107 //Keep doubling until we're larger than our target size. 108 //We could also do this with log operations, but that would 109 //be slower than the brute force approach. 110 while (newSize <= holder._id && newSize < MaxArraySize) 111 { 112 newSize *= 2; 113 } 114 115 if (newSize > MaxArraySize) 116 { 117 newSize = MaxArraySize; 118 } 119 } 120 121 ObjectHolder[] temp = new ObjectHolder[newSize]; 122 Array.Copy(_objects, 0, temp, 0, _objects.Length); 123 _objects = temp; 124 } 125 126 //Find the bin in which we live and make this new element the first element in the bin. 127 int index = (int)(holder._id & ArrayMask); 128 129 ObjectHolder tempHolder = _objects[index]; 130 holder._next = tempHolder; 131 _objects[index] = holder; 132 } 133 GetCompletionInfo(FixupHolder fixup, out ObjectHolder holder, out object member, bool bThrowIfMissing)134 private bool GetCompletionInfo(FixupHolder fixup, out ObjectHolder holder, out object member, bool bThrowIfMissing) 135 { 136 //Set the member id (String or MemberInfo) for the member being fixed up. 137 member = fixup._fixupInfo; 138 139 //Find the object required for the fixup. Throw if we can't find it. 140 holder = FindObjectHolder(fixup._id); 141 142 // CompletelyFixed is our poorly named property which indicates if something requires a SerializationInfo fixup 143 // or is an incomplete object reference. We have this particular branch to handle valuetypes which implement 144 // ISerializable. In that case, we can't do any fixups on them later, so we need to delay the fixups further. 145 if (!holder.CompletelyFixed) 146 { 147 if (holder.ObjectValue != null && holder.ObjectValue is ValueType) 148 { 149 SpecialFixupObjects.Add(holder); 150 return false; 151 } 152 } 153 154 if (holder == null || holder.CanObjectValueChange || holder.ObjectValue == null) 155 { 156 if (bThrowIfMissing) 157 { 158 if (holder == null) 159 { 160 throw new SerializationException(SR.Format(SR.Serialization_NeverSeen, fixup._id)); 161 } 162 if (holder.IsIncompleteObjectReference) 163 { 164 throw new SerializationException(SR.Format(SR.Serialization_IORIncomplete, fixup._id)); 165 } 166 throw new SerializationException(SR.Format(SR.Serialization_ObjectNotSupplied, fixup._id)); 167 } 168 return false; 169 } 170 return true; 171 } 172 FixupSpecialObject(ObjectHolder holder)173 private void FixupSpecialObject(ObjectHolder holder) 174 { 175 ISurrogateSelector uselessSelector = null; 176 177 Debug.Assert(holder.RequiresSerInfoFixup, "[ObjectManager.FixupSpecialObject]holder.HasSurrogate||holder.HasISerializable"); 178 if (holder.HasSurrogate) 179 { 180 ISerializationSurrogate surrogate = holder.Surrogate; 181 Debug.Assert(surrogate != null, "surrogate!=null"); 182 object returnValue = surrogate.SetObjectData(holder.ObjectValue, holder.SerializationInfo, _context, uselessSelector); 183 if (returnValue != null) 184 { 185 if (!holder.CanSurrogatedObjectValueChange && returnValue != holder.ObjectValue) 186 { 187 throw new SerializationException(string.Format(CultureInfo.CurrentCulture, SR.Serialization_NotCyclicallyReferenceableSurrogate, surrogate.GetType().FullName)); 188 } 189 holder.SetObjectValue(returnValue, this); 190 } 191 holder._surrogate = null; 192 holder.SetFlags(); 193 } 194 else 195 { 196 //Set the object data 197 Debug.Assert(holder.ObjectValue is ISerializable, "holder.m_object is ISerializable"); 198 CompleteISerializableObject(holder.ObjectValue, holder.SerializationInfo, _context); 199 } 200 //Clear anything that we know that we're not going to need. 201 holder.SerializationInfo = null; 202 holder.RequiresSerInfoFixup = false; 203 204 // For value types, fixups would have been done. So the newly fixed object must be copied 205 // to its container. 206 if (holder.RequiresValueTypeFixup && holder.ValueTypeFixupPerformed) 207 { 208 DoValueTypeFixup(null, holder, holder.ObjectValue); 209 } 210 DoNewlyRegisteredObjectFixups(holder); 211 } 212 213 /// <summary> 214 /// Unfortunately, an ObjectReference could actually be a reference to another 215 /// object reference and we don't know how far we have to tunnel until we can find the real object. While 216 /// we're still getting instances of IObjectReference back and we're still getting new objects, keep calling 217 /// GetRealObject. Once we've got the new object, take care of all of the fixups 218 /// that we can do now that we've got it. 219 /// </summary> 220 /// <param name="holder"></param> ResolveObjectReference(ObjectHolder holder)221 private bool ResolveObjectReference(ObjectHolder holder) 222 { 223 object tempObject; 224 Debug.Assert(holder.IsIncompleteObjectReference, "holder.IsIncompleteObjectReference"); 225 226 //In the pathological case, an Object implementing IObjectReference could return a reference 227 //to a different object which implements IObjectReference. This makes us vulnerable to a 228 //denial of service attack and stack overflow. If the depthCount becomes greater than 229 //MaxReferenceDepth, we'll throw a SerializationException. 230 int depthCount = 0; 231 232 //We wrap this in a try/catch block to handle the case where we're trying to resolve a chained 233 //list of object reference (e.g. an IObjectReference can't resolve itself without some information 234 //that's currently missing from the graph). We'll catch the NullReferenceException and come back 235 //and try again later. The downside of this scheme is that if the object actually needed to throw 236 //a NullReferenceException, it's being caught and turned into a SerializationException with a 237 //fairly cryptic message. 238 try 239 { 240 do 241 { 242 tempObject = holder.ObjectValue; 243 holder.SetObjectValue(((IObjectReference)(holder.ObjectValue)).GetRealObject(_context), this); 244 //The object didn't yet have enough information to resolve the reference, so we'll 245 //return false and the graph walker should call us back again after more objects have 246 //been resolved. 247 if (holder.ObjectValue == null) 248 { 249 holder.SetObjectValue(tempObject, this); 250 return false; 251 } 252 if (depthCount++ == MaxReferenceDepth) 253 { 254 throw new SerializationException(SR.Serialization_TooManyReferences); 255 } 256 } while ((holder.ObjectValue is IObjectReference) && (tempObject != holder.ObjectValue)); 257 } 258 catch (NullReferenceException) 259 { 260 return false; 261 } 262 263 holder.IsIncompleteObjectReference = false; 264 DoNewlyRegisteredObjectFixups(holder); 265 return true; 266 } 267 268 /*===============================DoValueTypeFixup=============================== 269 **Arguments: 270 ** memberToFix -- the member in the object contained in holder being fixed up. 271 ** holder -- the ObjectHolder for the object (a value type in this case) being completed. 272 ** value -- the data to set into the field. 273 ==============================================================================*/ DoValueTypeFixup(FieldInfo memberToFix, ObjectHolder holder, object value)274 private bool DoValueTypeFixup(FieldInfo memberToFix, ObjectHolder holder, object value) 275 { 276 var fieldsTemp = new FieldInfo[4]; 277 FieldInfo[] fields = null; 278 int currentFieldIndex = 0; 279 int[] arrayIndex = null; 280 ValueTypeFixupInfo currFixup = null; 281 object fixupObj = holder.ObjectValue; 282 ObjectHolder originalHolder = holder; 283 284 Debug.Assert(holder != null, "[TypedReferenceBuilder.ctor]holder!=null"); 285 Debug.Assert(holder.RequiresValueTypeFixup, "[TypedReferenceBuilder.ctor]holder.RequiresValueTypeFixup"); 286 287 //In order to get a TypedReference, we need to get a list of all of the FieldInfos to 288 //create the path from our outermost containing object down to the actual field which 289 //we'd like to set. This loop is used to build up that list. 290 while (holder.RequiresValueTypeFixup) 291 { 292 //Enlarge the array if required (this is actually fairly unlikely as it would require that we 293 //be nested more than 4 deep. 294 if ((currentFieldIndex + 1) >= fieldsTemp.Length) 295 { 296 var temp = new FieldInfo[fieldsTemp.Length * 2]; 297 Array.Copy(fieldsTemp, 0, temp, 0, fieldsTemp.Length); 298 fieldsTemp = temp; 299 } 300 301 //Get the fixup information. If we have data for our parent field, add it to our list 302 //and continue the walk up to find the next outermost containing object. We cache the 303 //object that we have. In most cases, we could have just grabbed it after this loop finished. 304 //However, if the outermost containing object is an array, we need the object one further 305 //down the chain, so we have to do a lot of caching. 306 currFixup = holder.ValueFixup; 307 fixupObj = holder.ObjectValue; //Save the most derived 308 if (currFixup.ParentField != null) 309 { 310 FieldInfo parentField = currFixup.ParentField; 311 312 ObjectHolder tempHolder = FindObjectHolder(currFixup.ContainerID); 313 if (tempHolder.ObjectValue == null) 314 { 315 break; 316 } 317 if (Nullable.GetUnderlyingType(parentField.FieldType) != null) 318 { 319 fieldsTemp[currentFieldIndex] = parentField.FieldType.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance); 320 currentFieldIndex++; 321 } 322 323 fieldsTemp[currentFieldIndex] = parentField; 324 holder = tempHolder; 325 currentFieldIndex++; 326 } 327 else 328 { 329 //If we find an index into an array, save that information. 330 Debug.Assert(currFixup.ParentIndex != null, "[ObjectManager.DoValueTypeFixup]currFixup.ParentIndex!=null"); 331 holder = FindObjectHolder(currFixup.ContainerID); //find the array to fix. 332 arrayIndex = currFixup.ParentIndex; 333 break; 334 } 335 } 336 337 //If the outermost container isn't an array, we need to grab it. Otherwise, we just need to hang onto 338 //the boxed object that we already grabbed. We'll assign the boxed object back into the array as the 339 //last step. 340 if (!(holder.ObjectValue is Array) && holder.ObjectValue != null) 341 { 342 fixupObj = holder.ObjectValue; 343 Debug.Assert(fixupObj != null, "[ObjectManager.DoValueTypeFixup]FixupObj!=null"); 344 } 345 346 if (currentFieldIndex != 0) 347 { 348 //MakeTypedReference requires an array of exactly the correct size that goes from the outermost object 349 //in to the innermost field. We currently have an array of arbitrary size that goes from the innermost 350 //object outwards. We create an array of the right size and do the copy. 351 fields = new FieldInfo[currentFieldIndex]; 352 for (int i = 0; i < currentFieldIndex; i++) 353 { 354 FieldInfo fieldInfo = fieldsTemp[(currentFieldIndex - 1 - i)]; 355 SerializationFieldInfo serInfo = fieldInfo as SerializationFieldInfo; 356 fields[i] = serInfo == null ? fieldInfo : serInfo.FieldInfo; 357 } 358 359 Debug.Assert(fixupObj != null, "[ObjectManager.DoValueTypeFixup]fixupObj!=null"); 360 //Make the TypedReference and use it to set the value. 361 TypedReference typedRef = TypedReference.MakeTypedReference(fixupObj, fields); 362 if (memberToFix != null) 363 { 364 memberToFix.SetValueDirect(typedRef, value); 365 } 366 else 367 { 368 TypedReference.SetTypedReference(typedRef, value); 369 } 370 } 371 else if (memberToFix != null) 372 { 373 FormatterServices.SerializationSetValue(memberToFix, fixupObj, value); 374 } 375 376 //If we have an array index, it means that our outermost container was an array. We don't have 377 //any way to build a TypedReference into an array, so we'll use the array functions to set the value. 378 if (arrayIndex != null && holder.ObjectValue != null) 379 { 380 ((Array)(holder.ObjectValue)).SetValue(fixupObj, arrayIndex); 381 } 382 383 return true; 384 } 385 CompleteObject(ObjectHolder holder, bool bObjectFullyComplete)386 internal void CompleteObject(ObjectHolder holder, bool bObjectFullyComplete) 387 { 388 FixupHolderList fixups = holder._missingElements; 389 FixupHolder currentFixup; 390 SerializationInfo si; 391 object fixupInfo = null; 392 ObjectHolder tempObjectHolder = null; 393 int fixupsPerformed = 0; 394 395 Debug.Assert(holder != null, "[ObjectManager.CompleteObject]holder.m_object!=null"); 396 if (holder.ObjectValue == null) 397 { 398 throw new SerializationException(SR.Format(SR.Serialization_MissingObject, holder._id)); 399 } 400 401 if (fixups == null) 402 { 403 return; 404 } 405 //If either one of these conditions is true, we need to update the data in the 406 //SerializationInfo before calling SetObjectData. 407 if (holder.HasSurrogate || holder.HasISerializable) 408 { 409 si = holder._serInfo; 410 if (si == null) 411 { 412 throw new SerializationException(SR.Serialization_InvalidFixupDiscovered); 413 } 414 415 //Walk each of the fixups and complete the name-value pair in the SerializationInfo. 416 if (fixups != null) 417 { 418 for (int i = 0; i < fixups._count; i++) 419 { 420 if (fixups._values[i] == null) 421 { 422 continue; 423 } 424 Debug.Assert(fixups._values[i]._fixupType == FixupHolder.DelayedFixup, "fixups.m_values[i].m_fixupType==FixupHolder.DelayedFixup"); 425 if (GetCompletionInfo(fixups._values[i], out tempObjectHolder, out fixupInfo, bObjectFullyComplete)) 426 { 427 //Walk the SerializationInfo and find the member needing completion. All we have to do 428 //at this point is set the member into the Object 429 object holderValue = tempObjectHolder.ObjectValue; 430 if (CanCallGetType(holderValue)) 431 { 432 si.UpdateValue((string)fixupInfo, holderValue, holderValue.GetType()); 433 } 434 else 435 { 436 si.UpdateValue((string)fixupInfo, holderValue, typeof(MarshalByRefObject)); 437 } 438 //Decrement our total number of fixups left to do. 439 fixupsPerformed++; 440 fixups._values[i] = null; 441 if (!bObjectFullyComplete) 442 { 443 holder.DecrementFixupsRemaining(this); 444 tempObjectHolder.RemoveDependency(holder._id); 445 } 446 } 447 } 448 } 449 } 450 else 451 { 452 for (int i = 0; i < fixups._count; i++) 453 { 454 currentFixup = fixups._values[i]; 455 if (currentFixup == null) 456 { 457 continue; 458 } 459 if (GetCompletionInfo(currentFixup, out tempObjectHolder, out fixupInfo, bObjectFullyComplete)) 460 { 461 // Check to make sure we are not both reachable from the topObject 462 // and there was a typeloadexception 463 if (tempObjectHolder.TypeLoadExceptionReachable) 464 { 465 holder.TypeLoadException = tempObjectHolder.TypeLoadException; 466 // If the holder is both reachable and typeloadexceptionreachable 467 // throw an exception with the type name 468 if (holder.Reachable) 469 { 470 throw new SerializationException(SR.Format(SR.Serialization_TypeLoadFailure, holder.TypeLoadException.TypeName)); 471 } 472 } 473 474 // If the current holder is reachable, mark the dependant reachable as well 475 if (holder.Reachable) 476 { 477 tempObjectHolder.Reachable = true; 478 } 479 480 //There are two types of fixups that we could be doing: array or member. 481 //Delayed Fixups should be handled by the above branch. 482 switch (currentFixup._fixupType) 483 { 484 case FixupHolder.ArrayFixup: 485 Debug.Assert(holder.ObjectValue is Array, "holder.ObjectValue is Array"); 486 if (holder.RequiresValueTypeFixup) 487 { 488 throw new SerializationException(SR.Serialization_ValueTypeFixup); 489 } 490 else 491 { 492 ((Array)(holder.ObjectValue)).SetValue(tempObjectHolder.ObjectValue, ((int[])fixupInfo)); 493 } 494 break; 495 case FixupHolder.MemberFixup: 496 Debug.Assert(fixupInfo is MemberInfo, "fixupInfo is MemberInfo"); 497 //Fixup the member directly. 498 MemberInfo tempMember = (MemberInfo)fixupInfo; 499 if (tempMember is FieldInfo) 500 { 501 // If we have a valuetype that's been boxed to an object and requires a fixup, 502 // there are two possible states: 503 // (a)The valuetype has never been fixed up into it's container. In this case, we should 504 // just fix up the boxed valuetype. The task of pushing that valuetype into it's container 505 // will be handled later. This case is handled by the else clause of the following statement. 506 // (b)The valuetype has already been inserted into it's container. In that case, we need 507 // to go through the more complicated path laid out in DoValueTypeFixup. We can tell that the 508 // valuetype has already been inserted into it's container because we set ValueTypeFixupPerformed 509 // to true when we do this. 510 if (holder.RequiresValueTypeFixup && holder.ValueTypeFixupPerformed) 511 { 512 if (!DoValueTypeFixup((FieldInfo)tempMember, holder, tempObjectHolder.ObjectValue)) 513 { 514 throw new SerializationException(SR.Serialization_PartialValueTypeFixup); 515 } 516 } 517 else 518 { 519 FormatterServices.SerializationSetValue(tempMember, holder.ObjectValue, tempObjectHolder.ObjectValue); 520 } 521 if (tempObjectHolder.RequiresValueTypeFixup) 522 { 523 tempObjectHolder.ValueTypeFixupPerformed = true; 524 } 525 } 526 else 527 { 528 throw new SerializationException(SR.Serialization_UnableToFixup); 529 } 530 break; 531 default: 532 throw new SerializationException(SR.Serialization_UnableToFixup); 533 } 534 //Decrement our total number of fixups left to do. 535 fixupsPerformed++; 536 fixups._values[i] = null; 537 if (!bObjectFullyComplete) 538 { 539 holder.DecrementFixupsRemaining(this); 540 tempObjectHolder.RemoveDependency(holder._id); 541 } 542 } 543 } 544 } 545 546 _fixupCount -= fixupsPerformed; 547 548 if (fixups._count == fixupsPerformed) 549 { 550 holder._missingElements = null; 551 } 552 } 553 554 /// <summary> 555 /// This is called immediately after we register a new object. Walk that objects 556 /// dependency list (if it has one) and decrement the counters on each object for 557 /// the number of unsatisfiable references. If the count reaches 0, go ahead 558 /// and process the object. 559 /// </summary> 560 /// <param name="holder">dependencies The list of dependent objects</param> DoNewlyRegisteredObjectFixups(ObjectHolder holder)561 private void DoNewlyRegisteredObjectFixups(ObjectHolder holder) 562 { 563 if (holder.CanObjectValueChange) 564 { 565 return; 566 } 567 568 //If we don't have any dependencies, we're done. 569 LongList dependencies = holder.DependentObjects; 570 if (dependencies == null) 571 { 572 return; 573 } 574 575 //Walk all of the dependencies and decrement the counter on each of uncompleted objects. 576 //If one of the counters reaches 0, all of it's fields have been completed and we should 577 //go take care of its fixups. 578 dependencies.StartEnumeration(); 579 while (dependencies.MoveNext()) 580 { 581 ObjectHolder temp = FindObjectHolder(dependencies.Current); 582 Debug.Assert(temp.DirectlyDependentObjects > 0, "temp.m_missingElementsRemaining>0"); 583 temp.DecrementFixupsRemaining(this); 584 if (((temp.DirectlyDependentObjects)) == 0) 585 { 586 // If this is null, we have the case where a fixup was registered for a child, the object 587 // required by the fixup was provided, and the object to be fixed hasn't yet been seen. 588 if (temp.ObjectValue != null) 589 { 590 CompleteObject(temp, true); 591 } 592 else 593 { 594 temp.MarkForCompletionWhenAvailable(); 595 } 596 } 597 } 598 } 599 GetObject(long objectID)600 public virtual object GetObject(long objectID) 601 { 602 if (objectID <= 0) 603 { 604 throw new ArgumentOutOfRangeException(nameof(objectID), SR.ArgumentOutOfRange_ObjectID); 605 } 606 607 //Find the bin in which we're interested. IObjectReference's shouldn't be returned -- the graph 608 //needs to link to the objects to which they refer, not to the references themselves. 609 ObjectHolder holder = FindObjectHolder(objectID); 610 if (holder == null || holder.CanObjectValueChange) 611 { 612 return null; 613 } 614 615 return holder.ObjectValue; 616 } 617 RegisterObject(object obj, long objectID)618 public virtual void RegisterObject(object obj, long objectID) 619 { 620 RegisterObject(obj, objectID, null, 0, null); 621 } 622 RegisterObject(object obj, long objectID, SerializationInfo info)623 public void RegisterObject(object obj, long objectID, SerializationInfo info) 624 { 625 RegisterObject(obj, objectID, info, 0, null); 626 } 627 RegisterObject(object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)628 public void RegisterObject(object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member) 629 { 630 RegisterObject(obj, objectID, info, idOfContainingObj, member, null); 631 } 632 RegisterString(string obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)633 internal void RegisterString(string obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member) 634 { 635 ObjectHolder temp; 636 Debug.Assert(member == null || member is FieldInfo, "RegisterString - member is FieldInfo"); 637 638 temp = new ObjectHolder(obj, objectID, info, null, idOfContainingObj, (FieldInfo)member, null); 639 AddObjectHolder(temp); 640 return; 641 } 642 RegisterObject(object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex)643 public void RegisterObject(object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex) 644 { 645 if (obj == null) 646 { 647 throw new ArgumentNullException(nameof(obj)); 648 } 649 if (objectID <= 0) 650 { 651 throw new ArgumentOutOfRangeException(nameof(objectID), SR.ArgumentOutOfRange_ObjectID); 652 } 653 if (member != null && !(member is FieldInfo)) // desktop checks specifically for RuntimeFieldInfo and SerializationFieldInfo, but the former is an implementation detail in corelib 654 { 655 throw new SerializationException(SR.Serialization_UnknownMemberInfo); 656 } 657 658 ObjectHolder temp; 659 ISerializationSurrogate surrogate = null; 660 ISurrogateSelector useless; 661 662 if (_selector != null) 663 { 664 Type selectorType = CanCallGetType(obj) ? 665 obj.GetType() : 666 typeof(MarshalByRefObject); 667 668 //If we need a surrogate for this object, lets find it now. 669 surrogate = _selector.GetSurrogate(selectorType, _context, out useless); 670 } 671 672 //The object is interested in DeserializationEvents so lets register it. 673 if (obj is IDeserializationCallback) 674 { 675 DeserializationEventHandler d = new DeserializationEventHandler(((IDeserializationCallback)obj).OnDeserialization); 676 AddOnDeserialization(d); 677 } 678 679 //Formatter developers may cache and reuse arrayIndex in their code. 680 //So that we don't get bitten by this, take a copy up front. 681 if (arrayIndex != null) 682 { 683 arrayIndex = (int[])arrayIndex.Clone(); 684 } 685 686 //This is the first time which we've seen the object, we need to create a new holder. 687 temp = FindObjectHolder(objectID); 688 if (temp == null) 689 { 690 temp = new ObjectHolder(obj, objectID, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex); 691 AddObjectHolder(temp); 692 if (temp.RequiresDelayedFixup) 693 { 694 SpecialFixupObjects.Add(temp); 695 } 696 697 // We cannot compute whether this has any fixups required or not 698 AddOnDeserialized(obj); 699 return; 700 } 701 702 //If the object isn't null, we've registered this before. Not good. 703 if (temp.ObjectValue != null) 704 { 705 throw new SerializationException(SR.Serialization_RegisterTwice); 706 } 707 708 //Complete the data in the ObjectHolder 709 temp.UpdateData(obj, info, surrogate, idOfContainingObj, (FieldInfo)member, arrayIndex, this); 710 711 // The following case will only be true when somebody has registered a fixup on an object before 712 // registering the object itself. I don't believe that most well-behaved formatters will do this, 713 // but we need to allow it anyway. We will walk the list of fixups which have been recorded on 714 // the new object and fix those that we can. Because the user could still register later fixups 715 // on this object, we won't call any implementations of ISerializable now. If that's required, 716 // it will have to be handled by the code in DoFixups. 717 // README README: We have to do the UpdateData before 718 if (temp.DirectlyDependentObjects > 0) 719 { 720 CompleteObject(temp, false); 721 } 722 723 if (temp.RequiresDelayedFixup) 724 { 725 SpecialFixupObjects.Add(temp); 726 } 727 728 if (temp.CompletelyFixed) 729 { 730 //Here's where things get tricky. If this isn't an instance of IObjectReference, we need to walk it's fixup 731 //chain and decrement the counters on anything that has reached 0. Once we've notified all of the dependencies, 732 //we can simply clear the list of dependent objects. 733 DoNewlyRegisteredObjectFixups(temp); 734 temp.DependentObjects = null; 735 } 736 737 //Register the OnDeserialized methods to be invoked after deserialization is complete 738 if (temp.TotalDependentObjects > 0) 739 { 740 AddOnDeserialized(obj); 741 } 742 else 743 { 744 RaiseOnDeserializedEvent(obj); 745 } 746 } 747 748 /// <summary> 749 /// Completes an object implementing ISerializable. This will involve calling that 750 /// objects constructor which takes an instance of ISerializable and a StreamingContext. 751 /// </summary> 752 /// <param name="obj">The object to be completed.</param> 753 /// <param name="info">The SerializationInfo containing all info for obj.</param> 754 /// <param name="context">The streaming context in which the serialization is taking place.</param> CompleteISerializableObject(object obj, SerializationInfo info, StreamingContext context)755 internal void CompleteISerializableObject(object obj, SerializationInfo info, StreamingContext context) 756 { 757 if (obj == null) 758 { 759 throw new ArgumentNullException(nameof(obj)); 760 } 761 if (!(obj is ISerializable)) 762 { 763 throw new ArgumentException(SR.Serialization_NotISer); 764 } 765 766 ConstructorInfo constInfo = null; 767 Type t = obj.GetType(); 768 try 769 { 770 constInfo = GetDeserializationConstructor(t); 771 } 772 catch (Exception e) 773 { 774 throw new SerializationException(SR.Format(SR.Serialization_ConstructorNotFound, t), e); 775 } 776 777 constInfo.Invoke(obj, new object[] { info, context }); 778 } 779 GetDeserializationConstructor(Type t)780 internal static ConstructorInfo GetDeserializationConstructor(Type t) 781 { 782 // TODO #10530: Use Type.GetConstructor that takes BindingFlags when it's available 783 foreach (ConstructorInfo ci in t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)) 784 { 785 ParameterInfo[] parameters = ci.GetParameters(); 786 if (parameters.Length == 2 && 787 parameters[0].ParameterType == typeof(SerializationInfo) && 788 parameters[1].ParameterType == typeof(StreamingContext)) 789 { 790 return ci; 791 } 792 } 793 794 throw new SerializationException(SR.Format(SR.Serialization_ConstructorNotFound, t.FullName)); 795 } 796 DoFixups()797 public virtual void DoFixups() 798 { 799 ObjectHolder temp; 800 int fixupCount = -1; 801 802 //The first thing that we need to do is fixup all of the objects which implement 803 //IObjectReference. This is complicated by the fact that we need to deal with IReferenceObjects 804 //objects that have a reference to an object implementing IObjectReference. We continually 805 //walk over the list of objects until we've completed all of the object references or until 806 //we can't resolve any more (which may happen if we have two objects implementing IObjectReference 807 //which have a circular dependency on each other). We don't explicitly catch the later case here, 808 //it will be caught when we try to do the rest of the fixups and discover that we have some that 809 //can't be completed. 810 while (fixupCount != 0) 811 { 812 fixupCount = 0; 813 //Walk all of the IObjectReferences and ensure that they've been properly completed. 814 ObjectHolderListEnumerator fixupObjectsEnum = SpecialFixupObjects.GetFixupEnumerator(); 815 while (fixupObjectsEnum.MoveNext()) 816 { 817 temp = fixupObjectsEnum.Current; 818 if (temp.ObjectValue == null) 819 { 820 throw new SerializationException(SR.Format(SR.Serialization_ObjectNotSupplied, temp._id)); 821 } 822 if (temp.TotalDependentObjects == 0) 823 { 824 if (temp.RequiresSerInfoFixup) 825 { 826 FixupSpecialObject(temp); 827 fixupCount++; 828 } 829 else if (!temp.IsIncompleteObjectReference) 830 { 831 CompleteObject(temp, true); 832 } 833 834 if (temp.IsIncompleteObjectReference && ResolveObjectReference(temp)) 835 { 836 fixupCount++; 837 } 838 } 839 } 840 } 841 842 Debug.Assert(_fixupCount >= 0, "[ObjectManager.DoFixups]m_fixupCount>=0"); 843 844 //If our count is 0, we're done and should just return 845 if (_fixupCount == 0) 846 { 847 if (TopObject is TypeLoadExceptionHolder) 848 { 849 throw new SerializationException(SR.Format(SR.Serialization_TypeLoadFailure, ((TypeLoadExceptionHolder)TopObject).TypeName)); 850 } 851 return; 852 } 853 854 //If our count isn't 0, we had at least one case where an object referenced another object twice. 855 //Walk the entire list until the count is 0 or until we find an object which we can't complete. 856 for (int i = 0; i < _objects.Length; i++) 857 { 858 temp = _objects[i]; 859 while (temp != null) 860 { 861 if (temp.TotalDependentObjects > 0 /*|| temp.m_missingElements!=null*/) 862 { 863 CompleteObject(temp, true); 864 } 865 temp = temp._next; 866 } 867 if (_fixupCount == 0) 868 { 869 return; 870 } 871 } 872 873 // this assert can be trigered by user code that manages fixups manually 874 throw new SerializationException(SR.Serialization_IncorrectNumberOfFixups); 875 } 876 877 /// <summary> 878 /// Do the actual grunt work of recording a fixup and registering the dependency. 879 /// Create the necessary ObjectHolders and use them to do the addition. 880 /// </summary> 881 /// <param name="fixup">The FixupHolder to be added.</param> 882 /// <param name="objectRequired">The id of the object required to do the fixup.</param> 883 /// <param name="objectToBeFixed">The id of the object requiring the fixup.</param> RegisterFixup(FixupHolder fixup, long objectToBeFixed, long objectRequired)884 private void RegisterFixup(FixupHolder fixup, long objectToBeFixed, long objectRequired) 885 { 886 //Record the fixup with the object that needs it. 887 ObjectHolder ohToBeFixed = FindOrCreateObjectHolder(objectToBeFixed); 888 ObjectHolder ohRequired; 889 890 if (ohToBeFixed.RequiresSerInfoFixup && fixup._fixupType == FixupHolder.MemberFixup) 891 { 892 throw new SerializationException(SR.Serialization_InvalidFixupType); 893 } 894 895 //Add the fixup to the list. 896 ohToBeFixed.AddFixup(fixup, this); 897 898 //Find the object on which we're dependent and note the dependency. 899 //These dependencies will be processed when the object is supplied. 900 ohRequired = FindOrCreateObjectHolder(objectRequired); 901 902 ohRequired.AddDependency(objectToBeFixed); 903 904 _fixupCount++; 905 } 906 RecordFixup(long objectToBeFixed, MemberInfo member, long objectRequired)907 public virtual void RecordFixup(long objectToBeFixed, MemberInfo member, long objectRequired) 908 { 909 //Verify our arguments 910 if (objectToBeFixed <= 0 || objectRequired <= 0) 911 { 912 throw new ArgumentOutOfRangeException(objectToBeFixed <= 0 ? nameof(objectToBeFixed) : nameof(objectRequired), SR.Serialization_IdTooSmall); 913 } 914 if (member == null) 915 { 916 throw new ArgumentNullException(nameof(member)); 917 } 918 if (!(member is FieldInfo)) // desktop checks specifically for RuntimeFieldInfo and SerializationFieldInfo, but the former is an implementation detail in corelib 919 { 920 throw new SerializationException(SR.Format(SR.Serialization_InvalidType, member.GetType().ToString())); 921 } 922 923 //Create a new fixup holder 924 FixupHolder fixup = new FixupHolder(objectRequired, member, FixupHolder.MemberFixup); 925 RegisterFixup(fixup, objectToBeFixed, objectRequired); 926 } 927 RecordDelayedFixup(long objectToBeFixed, string memberName, long objectRequired)928 public virtual void RecordDelayedFixup(long objectToBeFixed, string memberName, long objectRequired) 929 { 930 //Verify our arguments 931 if (objectToBeFixed <= 0 || objectRequired <= 0) 932 { 933 throw new ArgumentOutOfRangeException(objectToBeFixed <= 0 ? nameof(objectToBeFixed) : nameof(objectRequired), SR.Serialization_IdTooSmall); 934 } 935 if (memberName == null) 936 { 937 throw new ArgumentNullException(nameof(memberName)); 938 } 939 940 //Create a new fixup holder 941 FixupHolder fixup = new FixupHolder(objectRequired, memberName, FixupHolder.DelayedFixup); 942 RegisterFixup(fixup, objectToBeFixed, objectRequired); 943 } 944 RecordArrayElementFixup(long arrayToBeFixed, int index, long objectRequired)945 public virtual void RecordArrayElementFixup(long arrayToBeFixed, int index, long objectRequired) 946 { 947 int[] indexArray = new int[1]; 948 indexArray[0] = index; 949 RecordArrayElementFixup(arrayToBeFixed, indexArray, objectRequired); 950 } 951 RecordArrayElementFixup(long arrayToBeFixed, int[] indices, long objectRequired)952 public virtual void RecordArrayElementFixup(long arrayToBeFixed, int[] indices, long objectRequired) 953 { 954 //Verify our arguments 955 if (arrayToBeFixed <= 0 || objectRequired <= 0) 956 { 957 throw new ArgumentOutOfRangeException(arrayToBeFixed <= 0 ? nameof(arrayToBeFixed) : nameof(objectRequired), SR.Serialization_IdTooSmall); 958 } 959 if (indices == null) 960 { 961 throw new ArgumentNullException(nameof(indices)); 962 } 963 964 FixupHolder fixup = new FixupHolder(objectRequired, indices, FixupHolder.ArrayFixup); 965 RegisterFixup(fixup, arrayToBeFixed, objectRequired); 966 } 967 RaiseDeserializationEvent()968 public virtual void RaiseDeserializationEvent() 969 { 970 // Invoke OnDerserialized event if applicable 971 _onDeserializedHandler?.Invoke(_context); 972 _onDeserializationHandler?.Invoke(null); 973 } 974 AddOnDeserialization(DeserializationEventHandler handler)975 internal virtual void AddOnDeserialization(DeserializationEventHandler handler) 976 { 977 _onDeserializationHandler = (DeserializationEventHandler)Delegate.Combine(_onDeserializationHandler, handler); 978 } 979 AddOnDeserialized(object obj)980 internal virtual void AddOnDeserialized(object obj) 981 { 982 SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType()); 983 _onDeserializedHandler = cache.AddOnDeserialized(obj, _onDeserializedHandler); 984 } 985 RaiseOnDeserializedEvent(object obj)986 internal virtual void RaiseOnDeserializedEvent(object obj) 987 { 988 SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType()); 989 cache.InvokeOnDeserialized(obj, _context); 990 } 991 RaiseOnDeserializingEvent(object obj)992 public void RaiseOnDeserializingEvent(object obj) 993 { 994 // Run the OnDeserializing methods 995 SerializationEvents cache = SerializationEventsCache.GetSerializationEventsForType(obj.GetType()); 996 cache.InvokeOnDeserializing(obj, _context); 997 } 998 } 999 1000 internal sealed class ObjectHolder 1001 { 1002 internal const int IncompleteObjectReference = 0x0001; 1003 internal const int HAS_ISERIALIZABLE = 0x0002; 1004 internal const int HAS_SURROGATE = 0x0004; 1005 internal const int REQUIRES_VALUETYPE_FIXUP = 0x0008; 1006 internal const int REQUIRES_DELAYED_FIXUP = HAS_ISERIALIZABLE | HAS_SURROGATE | IncompleteObjectReference; 1007 internal const int SER_INFO_FIXED = 0x4000; 1008 internal const int VALUETYPE_FIXUP_PERFORMED = 0x8000; 1009 1010 private object _object; 1011 internal readonly long _id; 1012 private int _missingElementsRemaining; 1013 private int _missingDecendents; 1014 internal SerializationInfo _serInfo; 1015 internal ISerializationSurrogate _surrogate; 1016 internal FixupHolderList _missingElements; 1017 internal LongList _dependentObjects; 1018 internal ObjectHolder _next; 1019 internal int _flags; 1020 private bool _markForFixupWhenAvailable; 1021 private ValueTypeFixupInfo _valueFixup; 1022 private TypeLoadExceptionHolder _typeLoad = null; 1023 private bool _reachable = false; 1024 ObjectHolder(long objID)1025 internal ObjectHolder(long objID) : this(null, objID, null, null, 0, null, null) 1026 { 1027 } 1028 ObjectHolder( object obj, long objID, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex)1029 internal ObjectHolder( 1030 object obj, long objID, SerializationInfo info, ISerializationSurrogate surrogate, 1031 long idOfContainingObj, FieldInfo field, int[] arrayIndex) 1032 { 1033 Debug.Assert(objID >= 0, "objID>=0"); 1034 1035 _object = obj; //May be null; 1036 _id = objID; 1037 1038 _flags = 0; 1039 _missingElementsRemaining = 0; 1040 _missingDecendents = 0; 1041 _dependentObjects = null; 1042 _next = null; 1043 1044 _serInfo = info; 1045 _surrogate = surrogate; 1046 _markForFixupWhenAvailable = false; 1047 1048 if (obj is TypeLoadExceptionHolder) 1049 { 1050 _typeLoad = (TypeLoadExceptionHolder)obj; 1051 } 1052 1053 if (idOfContainingObj != 0 && ((field != null && field.FieldType.IsValueType) || arrayIndex != null)) 1054 { 1055 if (idOfContainingObj == objID) 1056 { 1057 throw new SerializationException(SR.Serialization_ParentChildIdentical); 1058 } 1059 1060 _valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex); 1061 } 1062 1063 SetFlags(); 1064 } 1065 ObjectHolder( string obj, long objID, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainingObj, FieldInfo field, int[] arrayIndex)1066 internal ObjectHolder( 1067 string obj, long objID, SerializationInfo info, ISerializationSurrogate surrogate, 1068 long idOfContainingObj, FieldInfo field, int[] arrayIndex) 1069 { 1070 Debug.Assert(objID >= 0, "objID>=0"); 1071 1072 _object = obj; //May be null; 1073 _id = objID; 1074 1075 _flags = 0; 1076 _missingElementsRemaining = 0; 1077 _missingDecendents = 0; 1078 _dependentObjects = null; 1079 _next = null; 1080 1081 _serInfo = info; 1082 _surrogate = surrogate; 1083 _markForFixupWhenAvailable = false; 1084 1085 if (idOfContainingObj != 0 && arrayIndex != null) 1086 { 1087 _valueFixup = new ValueTypeFixupInfo(idOfContainingObj, field, arrayIndex); 1088 } 1089 1090 if (_valueFixup != null) 1091 { 1092 _flags |= REQUIRES_VALUETYPE_FIXUP; 1093 } 1094 } 1095 IncrementDescendentFixups(int amount)1096 private void IncrementDescendentFixups(int amount) => _missingDecendents += amount; 1097 DecrementFixupsRemaining(ObjectManager manager)1098 internal void DecrementFixupsRemaining(ObjectManager manager) 1099 { 1100 _missingElementsRemaining--; 1101 if (RequiresValueTypeFixup) 1102 { 1103 UpdateDescendentDependencyChain(-1, manager); 1104 } 1105 } 1106 1107 /// <summary> 1108 /// Removes a dependency of the object represented in this holder. 1109 /// This is normally the result of the dependency having been filled when 1110 /// the object is going to be only partially completed. If we plan to fully 1111 /// update the object, we do not take the work to do this. 1112 /// </summary> 1113 /// <param name="id">The id of the object for which to remove the dependency.</param> RemoveDependency(long id)1114 internal void RemoveDependency(long id) 1115 { 1116 Debug.Assert(_dependentObjects != null, "[ObjectHolder.RemoveDependency]m_dependentObjects!=null"); 1117 Debug.Assert(id >= 0, "[ObjectHolder.RemoveDependency]id>=0"); 1118 _dependentObjects.RemoveElement(id); 1119 } 1120 1121 /// <summary> 1122 /// Note a fixup that has to be done before this object can be completed. 1123 /// Fixups are things that need to happen when other objects in the graph 1124 /// are added. Dependencies are things that need to happen when this object 1125 /// is added. 1126 /// </summary> 1127 /// <param name="fixup">The fixup holder containing enough information to complete the fixup.</param> AddFixup(FixupHolder fixup, ObjectManager manager)1128 internal void AddFixup(FixupHolder fixup, ObjectManager manager) 1129 { 1130 if (_missingElements == null) 1131 { 1132 _missingElements = new FixupHolderList(); 1133 } 1134 _missingElements.Add(fixup); 1135 _missingElementsRemaining++; 1136 1137 if (RequiresValueTypeFixup) 1138 { 1139 UpdateDescendentDependencyChain(1, manager); 1140 } 1141 } 1142 1143 /// <summary> 1144 /// Updates the total list of dependencies to account for a fixup being added 1145 /// or completed in a child value class. This will update all value classes 1146 /// containing that child and the object which contains all of them. 1147 /// </summary> 1148 /// <param name="amount">the amount by which to increment (or decrement) the dependency chain.</param> 1149 /// <param name="manager">The ObjectManager used to lookup other objects up the chain.</param> UpdateDescendentDependencyChain(int amount, ObjectManager manager)1150 private void UpdateDescendentDependencyChain(int amount, ObjectManager manager) 1151 { 1152 ObjectHolder holder = this; 1153 1154 //This loop walks one more object up the chain than there are valuetypes. This 1155 //is because we need to increment the TotalFixups in the holders as well. 1156 do 1157 { 1158 holder = manager.FindOrCreateObjectHolder(holder.ContainerID); 1159 Debug.Assert(holder != null, "[ObjectHolder.UpdateTotalDependencyChain]holder!=null"); 1160 holder.IncrementDescendentFixups(amount); 1161 } while (holder.RequiresValueTypeFixup); 1162 } 1163 1164 /// <summary> 1165 /// Note an object which is dependent on the one which will be contained in 1166 /// this ObjectHolder. Dependencies should only be added if the object hasn't 1167 /// yet been added. NB: An incomplete object counts as having no object. 1168 /// </summary> 1169 /// <param name="dependentObject">the id of the object which is dependent on this object being provided.</param> AddDependency(long dependentObject)1170 internal void AddDependency(long dependentObject) 1171 { 1172 if (_dependentObjects == null) 1173 { 1174 _dependentObjects = new LongList(); 1175 } 1176 _dependentObjects.Add(dependentObject); 1177 } 1178 1179 /// <summary> 1180 /// Update the data in the object holder. This should be called when the object 1181 /// is finally registered. Presumably the ObjectHolder was created to track 1182 /// some dependencies or preregistered fixups and we now need to actually record the 1183 /// object and other associated data. We take this opportunity to set the flags 1184 /// so that we can do some faster processing in the future. 1185 /// </summary> 1186 /// <param name="obj">The object being held by this object holder. (This should no longer be null).</param> 1187 /// <param name="field">The SerializationInfo associated with this object, only required if we're doing delayed fixups.</param> 1188 /// <param name="manager">the ObjectManager being used to track these ObjectHolders.</param> 1189 /// <param name="surrogate">The surrogate handling this object. May be null.</param> 1190 /// <param name="idOfContainer">The id of the object containing this one if this is a valuetype.</param> UpdateData( object obj, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainer, FieldInfo field, int[] arrayIndex, ObjectManager manager)1191 internal void UpdateData( 1192 object obj, SerializationInfo info, ISerializationSurrogate surrogate, long idOfContainer, 1193 FieldInfo field, int[] arrayIndex, ObjectManager manager) 1194 { 1195 Debug.Assert(obj != null, "obj!=null"); 1196 Debug.Assert(_id > 0, "m_id>0"); 1197 1198 //Record the fields that we can. 1199 SetObjectValue(obj, manager); 1200 _serInfo = info; 1201 _surrogate = surrogate; 1202 1203 if (idOfContainer != 0 && ((field != null && field.FieldType.IsValueType) || arrayIndex != null)) 1204 { 1205 if (idOfContainer == _id) 1206 { 1207 throw new SerializationException(SR.Serialization_ParentChildIdentical); 1208 } 1209 _valueFixup = new ValueTypeFixupInfo(idOfContainer, field, arrayIndex); 1210 } 1211 1212 SetFlags(); 1213 1214 if (RequiresValueTypeFixup) 1215 { 1216 UpdateDescendentDependencyChain(_missingElementsRemaining, manager); 1217 } 1218 } 1219 MarkForCompletionWhenAvailable()1220 internal void MarkForCompletionWhenAvailable() => _markForFixupWhenAvailable = true; 1221 1222 /// <summary> 1223 /// An internal-only routine to set the flags based upon the data contained in 1224 /// the ObjectHolder 1225 /// </summary> SetFlags()1226 internal void SetFlags() 1227 { 1228 if (_object is IObjectReference) 1229 { 1230 _flags |= IncompleteObjectReference; 1231 } 1232 1233 _flags &= ~(HAS_ISERIALIZABLE | HAS_SURROGATE); 1234 if (_surrogate != null) 1235 { 1236 _flags |= HAS_SURROGATE; 1237 } 1238 else if (_object is ISerializable) 1239 { 1240 _flags |= HAS_ISERIALIZABLE; 1241 } 1242 1243 if (_valueFixup != null) 1244 { 1245 _flags |= REQUIRES_VALUETYPE_FIXUP; 1246 } 1247 } 1248 1249 internal bool IsIncompleteObjectReference 1250 { 1251 get { return (_flags & IncompleteObjectReference) != 0; } 1252 set 1253 { 1254 if (value) 1255 { 1256 _flags |= IncompleteObjectReference; 1257 } 1258 else 1259 { 1260 _flags &= ~IncompleteObjectReference; 1261 } 1262 } 1263 } 1264 1265 internal bool RequiresDelayedFixup => (_flags & REQUIRES_DELAYED_FIXUP) != 0; 1266 1267 internal bool RequiresValueTypeFixup => (_flags & REQUIRES_VALUETYPE_FIXUP) != 0; 1268 1269 // ValueTypes which require fixups are initially handed to the ObjectManager 1270 // as boxed objects. When they're still boxed objects, we should just do fixups 1271 // on them like we would any other object. As soon as they're pushed into their 1272 // containing object we set ValueTypeFixupPerformed to true and have to go through 1273 // a more complicated path to set fixed up valuetype objects. 1274 // We check whether or not there are any dependent objects. 1275 internal bool ValueTypeFixupPerformed 1276 { 1277 get 1278 { 1279 return (((_flags & VALUETYPE_FIXUP_PERFORMED) != 0) || 1280 (_object != null && ((_dependentObjects == null) || _dependentObjects.Count == 0))); 1281 } 1282 set 1283 { 1284 if (value) 1285 { 1286 _flags |= VALUETYPE_FIXUP_PERFORMED; 1287 } 1288 } 1289 } 1290 1291 internal bool HasISerializable => (_flags & HAS_ISERIALIZABLE) != 0; 1292 1293 internal bool HasSurrogate => (_flags & HAS_SURROGATE) != 0; 1294 1295 internal bool CanSurrogatedObjectValueChange => 1296 (_surrogate == null || _surrogate.GetType() != typeof(SurrogateForCyclicalReference)); 1297 1298 internal bool CanObjectValueChange => 1299 IsIncompleteObjectReference ? true : 1300 HasSurrogate ? CanSurrogatedObjectValueChange : 1301 false; 1302 1303 internal int DirectlyDependentObjects => _missingElementsRemaining; 1304 1305 internal int TotalDependentObjects => _missingElementsRemaining + _missingDecendents; 1306 1307 internal bool Reachable { get { return _reachable; } set { _reachable = value; } } 1308 1309 internal bool TypeLoadExceptionReachable => _typeLoad != null; 1310 1311 internal TypeLoadExceptionHolder TypeLoadException { get { return _typeLoad; } set { _typeLoad = value; } } 1312 1313 internal object ObjectValue => _object; 1314 SetObjectValue(object obj, ObjectManager manager)1315 internal void SetObjectValue(object obj, ObjectManager manager) 1316 { 1317 _object = obj; 1318 if (obj == manager.TopObject) 1319 { 1320 _reachable = true; 1321 } 1322 if (obj is TypeLoadExceptionHolder) 1323 { 1324 _typeLoad = (TypeLoadExceptionHolder)obj; 1325 } 1326 1327 if (_markForFixupWhenAvailable) 1328 { 1329 manager.CompleteObject(this, true); 1330 } 1331 } 1332 1333 internal SerializationInfo SerializationInfo { get { return _serInfo; } set { _serInfo = value; } } 1334 1335 internal ISerializationSurrogate Surrogate => _surrogate; 1336 1337 internal LongList DependentObjects { get { return _dependentObjects; } set { _dependentObjects = value; } } 1338 1339 internal bool RequiresSerInfoFixup 1340 { 1341 get 1342 { 1343 if (((_flags & HAS_SURROGATE) == 0) && ((_flags & HAS_ISERIALIZABLE) == 0)) 1344 { 1345 return false; 1346 } 1347 1348 return (_flags & SER_INFO_FIXED) == 0; 1349 } 1350 set 1351 { 1352 if (!value) 1353 { 1354 _flags |= SER_INFO_FIXED; 1355 } 1356 else 1357 { 1358 _flags &= ~SER_INFO_FIXED; 1359 } 1360 } 1361 } 1362 1363 internal ValueTypeFixupInfo ValueFixup => _valueFixup; 1364 1365 internal bool CompletelyFixed => !RequiresSerInfoFixup && !IsIncompleteObjectReference; 1366 1367 internal long ContainerID => _valueFixup != null ? _valueFixup.ContainerID : 0; 1368 } 1369 1370 [Serializable] 1371 internal sealed class FixupHolder 1372 { 1373 internal const int ArrayFixup = 0x1; 1374 internal const int MemberFixup = 0x2; 1375 internal const int DelayedFixup = 0x4; 1376 1377 internal long _id; 1378 internal object _fixupInfo; //This is either an array index, a String, or a MemberInfo 1379 internal readonly int _fixupType; 1380 FixupHolder(long id, object fixupInfo, int fixupType)1381 internal FixupHolder(long id, object fixupInfo, int fixupType) 1382 { 1383 Debug.Assert(id > 0, "id>0"); 1384 Debug.Assert(fixupInfo != null, "fixupInfo!=null"); 1385 Debug.Assert(fixupType == ArrayFixup || fixupType == MemberFixup || fixupType == DelayedFixup, "fixupType==ArrayFixup || fixupType == MemberFixup || fixupType==DelayedFixup"); 1386 1387 _id = id; 1388 _fixupInfo = fixupInfo; 1389 _fixupType = fixupType; 1390 } 1391 } 1392 1393 [Serializable] 1394 internal sealed class FixupHolderList 1395 { 1396 internal const int InitialSize = 2; 1397 1398 internal FixupHolder[] _values; 1399 internal int _count; 1400 FixupHolderList()1401 internal FixupHolderList() : this(InitialSize) 1402 { 1403 } 1404 FixupHolderList(int startingSize)1405 internal FixupHolderList(int startingSize) 1406 { 1407 _count = 0; 1408 _values = new FixupHolder[startingSize]; 1409 } 1410 Add(FixupHolder fixup)1411 internal void Add(FixupHolder fixup) 1412 { 1413 if (_count == _values.Length) 1414 { 1415 EnlargeArray(); 1416 } 1417 _values[_count++] = fixup; 1418 } 1419 EnlargeArray()1420 private void EnlargeArray() 1421 { 1422 int newLength = _values.Length * 2; 1423 if (newLength < 0) 1424 { 1425 if (newLength == int.MaxValue) 1426 { 1427 throw new SerializationException(SR.Serialization_TooManyElements); 1428 } 1429 newLength = int.MaxValue; 1430 } 1431 1432 FixupHolder[] temp = new FixupHolder[newLength]; 1433 Array.Copy(_values, 0, temp, 0, _count); 1434 _values = temp; 1435 } 1436 } 1437 1438 [Serializable] 1439 internal sealed class LongList 1440 { 1441 private const int InitialSize = 2; 1442 1443 private long[] _values; 1444 private int _count; //The total number of valid items still in the list; 1445 private int _totalItems; //The total number of allocated entries. This includes space for items which have been marked as deleted. 1446 private int _currentItem; //Used when doing an enumeration over the list. 1447 1448 // An m_currentItem of -1 indicates that the enumeration hasn't been started. 1449 // An m_values[xx] of -1 indicates that the item has been deleted. LongList()1450 internal LongList() : this(InitialSize) 1451 { 1452 } 1453 LongList(int startingSize)1454 internal LongList(int startingSize) 1455 { 1456 _count = 0; 1457 _totalItems = 0; 1458 _values = new long[startingSize]; 1459 } 1460 Add(long value)1461 internal void Add(long value) 1462 { 1463 if (_totalItems == _values.Length) 1464 { 1465 EnlargeArray(); 1466 } 1467 _values[_totalItems++] = value; 1468 _count++; 1469 } 1470 1471 internal int Count => _count; 1472 StartEnumeration()1473 internal void StartEnumeration() => _currentItem = -1; 1474 MoveNext()1475 internal bool MoveNext() 1476 { 1477 while (++_currentItem < _totalItems && _values[_currentItem] == -1) ; 1478 return _currentItem != _totalItems; 1479 } 1480 1481 internal long Current 1482 { 1483 get 1484 { 1485 Debug.Assert(_currentItem != -1, "[LongList.Current]m_currentItem!=-1"); 1486 Debug.Assert(_values[_currentItem] != -1, "[LongList.Current]m_values[m_currentItem]!=-1"); 1487 return _values[_currentItem]; 1488 } 1489 } 1490 RemoveElement(long value)1491 internal bool RemoveElement(long value) 1492 { 1493 int i; 1494 for (i = 0; i < _totalItems; i++) 1495 { 1496 if (_values[i] == value) 1497 { 1498 break; 1499 } 1500 } 1501 if (i == _totalItems) 1502 { 1503 return false; 1504 } 1505 _values[i] = -1; 1506 return true; 1507 } 1508 EnlargeArray()1509 private void EnlargeArray() 1510 { 1511 int newLength = _values.Length * 2; 1512 if (newLength < 0) 1513 { 1514 if (newLength == int.MaxValue) 1515 { 1516 throw new SerializationException(SR.Serialization_TooManyElements); 1517 } 1518 newLength = int.MaxValue; 1519 } 1520 1521 long[] temp = new long[newLength]; 1522 Array.Copy(_values, 0, temp, 0, _count); 1523 _values = temp; 1524 } 1525 } 1526 1527 internal sealed class ObjectHolderList 1528 { 1529 internal const int DefaultInitialSize = 8; 1530 1531 internal ObjectHolder[] _values; 1532 internal int _count; 1533 ObjectHolderList()1534 internal ObjectHolderList() : this(DefaultInitialSize) 1535 { 1536 } 1537 ObjectHolderList(int startingSize)1538 internal ObjectHolderList(int startingSize) 1539 { 1540 Debug.Assert(startingSize > 0 && startingSize < 0x1000, "startingSize>0 && startingSize<0x1000"); 1541 _count = 0; 1542 _values = new ObjectHolder[startingSize]; 1543 } 1544 Add(ObjectHolder value)1545 internal void Add(ObjectHolder value) 1546 { 1547 if (_count == _values.Length) 1548 { 1549 EnlargeArray(); 1550 } 1551 _values[_count++] = value; 1552 } 1553 GetFixupEnumerator()1554 internal ObjectHolderListEnumerator GetFixupEnumerator() => new ObjectHolderListEnumerator(this, true); 1555 EnlargeArray()1556 private void EnlargeArray() 1557 { 1558 int newLength = _values.Length * 2; 1559 if (newLength < 0) 1560 { 1561 if (newLength == int.MaxValue) 1562 { 1563 throw new SerializationException(SR.Serialization_TooManyElements); 1564 } 1565 newLength = int.MaxValue; 1566 } 1567 1568 ObjectHolder[] temp = new ObjectHolder[newLength]; 1569 Array.Copy(_values, 0, temp, 0, _count); 1570 _values = temp; 1571 } 1572 1573 internal int Version => _count; 1574 1575 internal int Count => _count; 1576 } 1577 1578 internal sealed class ObjectHolderListEnumerator 1579 { 1580 private readonly bool _isFixupEnumerator; 1581 private readonly ObjectHolderList _list; 1582 private readonly int _startingVersion; 1583 private int _currPos; 1584 ObjectHolderListEnumerator(ObjectHolderList list, bool isFixupEnumerator)1585 internal ObjectHolderListEnumerator(ObjectHolderList list, bool isFixupEnumerator) 1586 { 1587 Debug.Assert(list != null, "[ObjectHolderListEnumerator.ctor]list!=null"); 1588 _list = list; 1589 _startingVersion = _list.Version; 1590 _currPos = -1; 1591 _isFixupEnumerator = isFixupEnumerator; 1592 } 1593 MoveNext()1594 internal bool MoveNext() 1595 { 1596 Debug.Assert(_startingVersion == _list.Version, "[ObjectHolderListEnumerator.MoveNext]m_startingVersion==m_list.Version"); 1597 if (_isFixupEnumerator) 1598 { 1599 while (++_currPos < _list.Count && _list._values[_currPos].CompletelyFixed) ; 1600 return _currPos != _list.Count; 1601 } 1602 else 1603 { 1604 _currPos++; 1605 return _currPos != _list.Count; 1606 } 1607 } 1608 1609 internal ObjectHolder Current 1610 { 1611 get 1612 { 1613 Debug.Assert(_currPos != -1, "[ObjectHolderListEnumerator.Current]m_currPos!=-1"); 1614 Debug.Assert(_currPos < _list.Count, "[ObjectHolderListEnumerator.Current]m_currPos<m_list.Count"); 1615 Debug.Assert(_startingVersion == _list.Version, "[ObjectHolderListEnumerator.Current]m_startingVersion==m_list.Version"); 1616 return _list._values[_currPos]; 1617 } 1618 } 1619 } 1620 1621 public sealed class TypeLoadExceptionHolder 1622 { TypeLoadExceptionHolder(string typeName)1623 internal TypeLoadExceptionHolder(string typeName) 1624 { 1625 TypeName = typeName; 1626 } 1627 1628 internal string TypeName { get; } 1629 } 1630 1631 // TODO: Temporary workaround. Remove this once SerializationInfo.UpdateValue is exposed 1632 // from coreclr for use by ObjectManager. 1633 internal static class SerializationInfoExtensions 1634 { 1635 private static readonly Action<SerializationInfo, string, object, Type> s_updateValue = 1636 (Action<SerializationInfo, string, object, Type>)typeof(SerializationInfo) 1637 .GetMethod("UpdateValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 1638 .CreateDelegate(typeof(Action<SerializationInfo, string, object, Type>)); 1639 UpdateValue(this SerializationInfo si, string name, object value, Type type)1640 public static void UpdateValue(this SerializationInfo si, string name, object value, Type type) => 1641 s_updateValue(si, name, value, type); 1642 } 1643 } 1644