Skip to content

Ignore inherited methods in BinData field-name guard (#261)#300

Open
arpitjain099 wants to merge 1 commit into
rapid7:masterfrom
arpitjain099:bug/261/reserved-name-inherited-methods
Open

Ignore inherited methods in BinData field-name guard (#261)#300
arpitjain099 wants to merge 1 commit into
rapid7:masterfrom
arpitjain099:bug/261/reserved-name-inherited-methods

Conversation

@arpitjain099
Copy link
Copy Markdown

Fixes #261.

Problem

Loading ruby_smb after a mocking library has patched Object raises a
SyntaxError from BinData while the gem's own struct definitions are being
built:

SyntaxError: field 'stub' shadows an existing method in RubySMB::Dcerpc::Request

The common trigger is an RSpec suite configured with config.mock_with :rspec,
because rspec-mocks adds a #stub helper to BasicObject/Object. If that
happens before require 'ruby_smb' (a normal spec_helper.rb ordering), the
inherited #stub collides with the legitimate :stub field on
RubySMB::Dcerpc::Request.

The root cause is in BinData's field-name guard
(BinData::DSLMixin::DSLFieldValidator#name_shadows_method?), which calls
@the_class.method_defined?(name). Without the second argument,
method_defined? also returns true for methods inherited from ancestors such
as Object, Kernel and Hash, so any field whose name matches an inherited
helper method is wrongly rejected.

Fix

This adds a small compatibility shim (lib/ruby_smb/compatibility.rb, required
immediately after require 'bindata') that narrows the guard to
@the_class.method_defined?(name, false). The false restricts the check to
methods defined directly on the struct class, which is what the guard is meant
to enforce.

Why this does not weaken the guard:

  • Field accessors are installed per instance with define_singleton_method, so
    an inherited method that happens to share a field's name never gets in the way
    at runtime. Only a method defined directly on the struct class is a genuine
    collision, and that case still raises.
  • Names that clash with Hash methods or BinData DSL internals are handled by a
    separate, independent check (name_is_reserved? against
    BinData::Struct::RESERVED). That list is unchanged, so reserved names such as
    keys still raise.

This is purely a compatibility/loosening of which field names are accepted. It
does not rename, retype, or otherwise change any BinData data definition, so the
versioning note in CONTRIBUTING.md (minor bump on BinData definition changes)
does not apply here.

Tests

spec/lib/ruby_smb/compatibility_spec.rb covers all three branches:

Verification Steps

  • bundle install

rake spec

  • rake spec
  • VERIFY no failures

Manual scenario

require 'rspec/mocks/standalone'   # adds Object#stub, as `mock_with :rspec` does
require 'ruby_smb'                  # previously raised "field 'stub' shadows an existing method"
puts 'loaded ruby_smb cleanly'

BinData rejects a field name when a method of that name is already
defined on the struct class. The check in DSLFieldValidator used
Module#method_defined? without the second argument, so it also matched
methods inherited from ancestors such as Object, Kernel and Hash.

When a mocking library is loaded before ruby_smb (for example
rspec-mocks adds Object#stub under config.mock_with :rspec), valid
BinData definitions started raising

  SyntaxError: field 'stub' shadows an existing method

even though RubySMB::Dcerpc::Request legitimately defines a :stub field.

Field accessors are installed per instance with define_singleton_method,
so an inherited method named like a field never collides at runtime;
only a method defined directly on the struct class is a real collision.
Passing false to method_defined? restricts the guard to directly-defined
methods. Names that clash with Hash/BinData internals stay covered by the
separate BinData::Struct::RESERVED list, so that protection is unchanged.

The fix is a small compatibility shim required right after bindata, plus
a regression spec covering the inherited-method, direct-method and
reserved-name cases.

Fixes rapid7#261

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
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

Successfully merging this pull request may close these issues.

Field 'stub' shadows an existing method in RubySMB::Dcerpc::Request while unit testing

1 participant