lib/contrast/utils/class_util.rb in contrast-agent-4.10.0 vs lib/contrast/utils/class_util.rb in contrast-agent-4.11.0
- old
+ new
@@ -1,15 +1,17 @@
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true
require 'contrast/extension/module'
require 'contrast/utils/object_share'
+require 'contrast/utils/lru_cache'
module Contrast
module Utils
# Utility methods for exploring the complete space of Objects
class ClassUtil
+ @lru_cache = LRUCache.new
class << self
# some classes have had things prepended to them, like Marshal in Rails
# 5 and higher. Their ActiveSupport::MarshalWithAutoloading will break
# our alias patching approach, as will any other prepend on something
# that we touch. Prepend and Alias are inherently incompatible monkey
@@ -45,30 +47,35 @@
# form expected by our dataflow events.
#
# @param object [Object, nil] the entity to convert to a String
# @return [String] the human readable form of the String, as defined by
# https://bitbucket.org/contrastsecurity/assess-specifications/src/master/vulnerability/capture-snapshot.md
+
def to_contrast_string object
- # Only treat object like a string if it actually is a string
+ # After implementing the LRU Cache, we firstly need to check if already had that object cached
+ # and if we have it - we can return it directly
+ return @lru_cache[object.__id__] if @lru_cache.key? object.__id__
+
+ # Only treat object like a string if it actually is a string+
# some subclasses of String override string methods we depend on
- if object.cs__class == String
- cached = to_cached_string(object)
- return cached if cached
+ @lru_cache[object.__id__] = if object.cs__class == String
+ cached = to_cached_string(object)
+ return cached if cached
- object.dup
- elsif object.nil?
- Contrast::Utils::ObjectShare::NIL_STRING
- elsif object.cs__is_a?(Symbol)
- ":#{ object }"
- elsif object.cs__is_a?(Module) || object.cs__is_a?(Class)
- "#{ object.cs__name }@#{ object.__id__ }"
- elsif object.cs__is_a?(Regexp)
- object.source
- elsif use_to_s?(object)
- object.to_s
- else
- "#{ object.cs__class.cs__name }@#{ object.__id__ }"
- end
+ object.dup
+ elsif object.nil?
+ Contrast::Utils::ObjectShare::NIL_STRING
+ elsif object.cs__is_a?(Symbol)
+ ":#{ object }"
+ elsif object.cs__is_a?(Module) || object.cs__is_a?(Class)
+ "#{ object.cs__name }@#{ object.__id__ }"
+ elsif object.cs__is_a?(Regexp)
+ object.source
+ elsif use_to_s?(object)
+ object.to_s
+ else
+ "#{ object.cs__class.cs__name }@#{ object.__id__ }"
+ end
end
# The method const_defined? can cause autoload, which is bad for us.
# The method autoload? doesn't traverse namespaces. This method lets us
# provide a constant, as a String, and parse it to determine if it has