Sha256: 3697b125fae6093fa35aef3a0b499b42b0bb70b302a79ce76ff5117b5e1f5e62

Contents?: true

Size: 1.51 KB

Versions: 2

Compression:

Stored size: 1.51 KB

Contents

# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true

require 'contrast/components/scope'

# This is a reasonable place for the Kernel#catch hook to live.
# No current plans for component re-design, but if we had some kind of
# "do this when a component is hooked in" thing, this would live there.
# For now, it's over-engineering to live anywhere else.  -ajm
module Kernel # :nodoc:
  alias_method :cs__catch, :catch

  # In the event of a `throw`, we need to override `catch`
  # to save & restore scope state:
  #
  #   scope_level == 0
  #
  #   catch(:abc) do
  #     with_contrast_scope do
  #       throw :abc # will leak
  #     end
  #   end
  #
  #   scope_level == 1
  #
  # Frankly, this isn't how scope should be used.  This is in place of
  # proper `ensure` blocks within the instrumentation call stack.
  # This will actually /create/ scope leaks if you're doing something like:
  #
  #   catch(:ohno) do
  #     enter scope
  #   end
  #
  #   abc()
  #
  #   exit scope
  #
  # i.e. if you intend to change net scope across a catch block boundary.

  private

  def catch *args, &block
    # Save current scope level
    scope_level = ::Contrast::SCOPE.scope_for_current_ec.instance_variable_get(:@contrast_scope)

    # Run original catch with block.
    retval = cs__catch(*args, &block)

    # Restore scope.
    ::Contrast::SCOPE.scope_for_current_ec.instance_variable_set(:@contrast_scope, scope_level)

    retval
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
contrast-agent-5.1.0 lib/contrast/extension/kernel.rb
contrast-agent-5.0.0 lib/contrast/extension/kernel.rb