lib/contrast/extension/assess/assess_extension.rb in contrast-agent-3.13.2 vs lib/contrast/extension/assess/assess_extension.rb in contrast-agent-3.14.0

- old
+ new

@@ -1,57 +1,44 @@ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true -cs__scoped_require 'contrast/agent/assess/properties' -cs__scoped_require 'contrast/agent/assess/insulator' +require 'contrast/agent/assess/properties' +require 'contrast/agent/assess/finalizers/finalize' module Contrast module Extension module Assess # This module is responsible for maintaining the data we need to # construct a trace event for the object in which it is included. Rather # than have this code all over the place, any class that wants to use # dataflow features should be sent # 'include Contrast::Extension::Assess::AssessExtension' module AssessExtension + def cs__transfer_properties dup + Contrast::Agent::Assess::Finalizers::Finalize::PROPERTIES_HASH[dup] ||= Contrast::Agent::Assess::Finalizers::Finalize::PROPERTIES_HASH[self].dup + end + # Lazily build properties object. Only objects that have been tracked # will have the @_cs__properties, but all will respond to the # cs__properties method call. You should only call this method if you # either intend to start tracking an object or you have already checked # cs__tracked? and it is true. def cs__properties - # If this object was tracked before being frozen, it'll have - # mutable properties we need inside of the insulator @_cs__properties - if cs__frozen? - if instance_variable_defined?(:@_cs__properties) - @_cs__properties.properties - else - Contrast::Agent::Assess::Insulator.generate_frozen.properties - end - else - @_cs__properties ||= Contrast::Agent::Assess::Insulator.generate - @_cs__properties.properties - end + Contrast::Agent::Assess::Finalizers::Finalize::PROPERTIES_HASH[self] ||= Contrast::Agent::Assess::Properties.new end - def cs__properties? - instance_variable_defined?(:@_cs__properties) - end - # This is a way to check if we are already tracking an object without # adding tracking to it. If the object already has been tracked we will # return the tracking state of its properties. If the object hasn't # already been tracked we will return false without starting to track # it def cs__tracked? - cs__properties? && cs__properties.tracked? + !!Contrast::Agent::Assess::Finalizers::Finalize::PROPERTIES_HASH[self]&.tracked? end def cs__reset_properties - return unless cs__properties? - - @_cs__properties = nil + Contrast::Agent::Assess::Finalizers::Finalize::PROPERTIES_HASH[self] = nil end # copy tags and info from object to self if object support methods # obj: the object from which to copy tags and events # shift: how far to shift the tags, negative moves left @@ -59,18 +46,13 @@ def cs__copy_from obj, shift = 0, skip_tags = nil return if obj.equal?(self) return unless Contrast::Utils::DuckUtils.quacks_to?(obj, :cs__tracked?) return unless obj.cs__tracked? - return if cs__properties == Contrast::Agent::Assess::Insulator.generate_frozen.properties + return unless cs__properties - # This was fun to find... - # the clone and dup methods don't apply to instance variables in the - # cloned/ duped thing, so the arrays in the properties were the same. - # The most infinite of infinite loops ensued. - # DO NOT TAKE THIS OUT! - cs__reset_properties if obj.cs__properties == cs__properties + cs__adjust_duplicate(obj) obj.cs__properties.events.each do |event| cs__properties.events << event end @@ -138,9 +120,25 @@ existing.each do |range| range.update_end(length) if range.end_idx > length end end + end + + private + + # Because of how our tracking works now, sometimes the Source and + # Target are the same, but their IDs in our map will be different due + # to PreShift duplication. To account for this, we have to ensure that + # the Object we're copying from does not have the same Properties + # that the Object we're copying to does. If they are the same, wipe the + # Target so that the copy method can update events and ranges as + # necessary. + # DO NOT TAKE THIS OUT! + def cs__adjust_duplicate obj + cs__reset_properties if obj.cs__properties == cs__properties + cs__reset_properties if obj.cs__properties.__id__ == cs__properties.dupped_from + cs__reset_properties if obj.cs__properties.dupped_from == cs__properties.__id__ end end end end end