Class: RubyMemcheck::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_memcheck/configuration.rb

Constant Summary collapse

DEFAULT_VALGRIND =
"valgrind"
DEFAULT_VALGRIND_OPTIONS =
[
  "--num-callers=50",
  "--error-limit=no",
  "--trace-children=yes",
  "--undef-value-errors=no",
  "--leak-check=full",
  "--show-leak-kinds=definite",
].freeze
DEFAULT_VALGRIND_SUPPRESSIONS_DIR =
"suppressions"
DEFAULT_SKIPPED_RUBY_FUNCTIONS =
[
  /\Aeval_string_with_cref\z/,
  /\Aintern_str\z/, # Same as rb_intern, but sometimes rb_intern is optimized out
  /\Arb_add_method_cfunc\z/,
  /\Arb_check_funcall/,
  /\Arb_class_boot\z/, # Called for all the different ways to create a Class
  /\Arb_enc_raise\z/,
  /\Arb_exc_raise\z/,
  /\Arb_extend_object\z/,
  /\Arb_funcall/,
  /\Arb_intern/,
  /\Arb_ivar_set\z/,
  /\Arb_module_new\z/,
  /\Arb_raise\z/,
  /\Arb_rescue/,
  /\Arb_respond_to\z/,
  /\Arb_thread_create\z/, # Threads are relased to a cache, so they may be reported as a leak
  /\Arb_vm_exec\z/,
  /\Arb_yield/,
].freeze
RUBY_FREE_AT_EXIT_SUPPORTED =
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(binary_name: nil, ruby: FileUtils::RUBY, valgrind: DEFAULT_VALGRIND, valgrind_options: DEFAULT_VALGRIND_OPTIONS, valgrind_suppressions_dir: DEFAULT_VALGRIND_SUPPRESSIONS_DIR, valgrind_generate_suppressions: false, skipped_ruby_functions: DEFAULT_SKIPPED_RUBY_FUNCTIONS, temp_dir: Dir.mktmpdir, output_io: $stderr, filter_all_errors: false, use_only_ruby_free_at_exit: RUBY_FREE_AT_EXIT_SUPPORTED) ⇒ Configuration

Returns a new instance of Configuration.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/ruby_memcheck/configuration.rb', line 54

def initialize(
  binary_name: nil,
  ruby: FileUtils::RUBY,
  valgrind: DEFAULT_VALGRIND,
  valgrind_options: DEFAULT_VALGRIND_OPTIONS,
  valgrind_suppressions_dir: DEFAULT_VALGRIND_SUPPRESSIONS_DIR,
  valgrind_generate_suppressions: false,
  skipped_ruby_functions: DEFAULT_SKIPPED_RUBY_FUNCTIONS,
  temp_dir: Dir.mktmpdir,
  output_io: $stderr,
  filter_all_errors: false,
  use_only_ruby_free_at_exit: RUBY_FREE_AT_EXIT_SUPPORTED
)
  @binary_name = binary_name
  @ruby = ruby
  @valgrind = valgrind
  @valgrind_options = valgrind_options
  @valgrind_suppression_files =
    get_valgrind_suppression_files(File.join(__dir__, "../../suppressions")) +
    get_valgrind_suppression_files(valgrind_suppressions_dir)
  @valgrind_generate_suppressions = valgrind_generate_suppressions
  @skipped_ruby_functions = skipped_ruby_functions
  @output_io = output_io
  @filter_all_errors = filter_all_errors

  temp_dir = File.expand_path(temp_dir)
  FileUtils.mkdir_p(temp_dir)
  @temp_dir = temp_dir
  @valgrind_options += [
    "--xml=yes",
    # %p will be replaced with the PID
    # This prevents forking and shelling out from generating a corrupted XML
    # See --log-file from https://valgrind.org/docs/manual/manual-core.html
    "--xml-file=#{File.join(temp_dir, "%p.xml")}",
  ]

  @loaded_features_file = Tempfile.create("", @temp_dir)

  @use_only_ruby_free_at_exit = use_only_ruby_free_at_exit
end

Instance Attribute Details

#binary_nameObject (readonly)

Returns the value of attribute binary_name.



37
38
39
# File 'lib/ruby_memcheck/configuration.rb', line 37

def binary_name
  @binary_name
end

#filter_all_errorsObject (readonly) Also known as: filter_all_errors?

Returns the value of attribute filter_all_errors.



47
48
49
# File 'lib/ruby_memcheck/configuration.rb', line 47

def filter_all_errors
  @filter_all_errors
end

#loaded_features_fileObject (readonly)

Returns the value of attribute loaded_features_file.



45
46
47
# File 'lib/ruby_memcheck/configuration.rb', line 45

def loaded_features_file
  @loaded_features_file
end

#output_ioObject (readonly)

Returns the value of attribute output_io.



46
47
48
# File 'lib/ruby_memcheck/configuration.rb', line 46

def output_io
  @output_io
end

#rubyObject (readonly)

Returns the value of attribute ruby.



38
39
40
# File 'lib/ruby_memcheck/configuration.rb', line 38

def ruby
  @ruby
end

#skipped_ruby_functionsObject (readonly)

Returns the value of attribute skipped_ruby_functions.



43
44
45
# File 'lib/ruby_memcheck/configuration.rb', line 43

def skipped_ruby_functions
  @skipped_ruby_functions
end

#temp_dirObject (readonly)

Returns the value of attribute temp_dir.



44
45
46
# File 'lib/ruby_memcheck/configuration.rb', line 44

def temp_dir
  @temp_dir
end

#use_only_ruby_free_at_exitObject (readonly) Also known as: use_only_ruby_free_at_exit?

Returns the value of attribute use_only_ruby_free_at_exit.



48
49
50
# File 'lib/ruby_memcheck/configuration.rb', line 48

def use_only_ruby_free_at_exit
  @use_only_ruby_free_at_exit
end

#valgrindObject (readonly)

Returns the value of attribute valgrind.



39
40
41
# File 'lib/ruby_memcheck/configuration.rb', line 39

def valgrind
  @valgrind
end

#valgrind_generate_suppressionsObject (readonly) Also known as: valgrind_generate_suppressions?

Returns the value of attribute valgrind_generate_suppressions.



42
43
44
# File 'lib/ruby_memcheck/configuration.rb', line 42

def valgrind_generate_suppressions
  @valgrind_generate_suppressions
end

#valgrind_optionsObject (readonly)

Returns the value of attribute valgrind_options.



40
41
42
# File 'lib/ruby_memcheck/configuration.rb', line 40

def valgrind_options
  @valgrind_options
end

#valgrind_suppression_filesObject (readonly)

Returns the value of attribute valgrind_suppression_files.



41
42
43
# File 'lib/ruby_memcheck/configuration.rb', line 41

def valgrind_suppression_files
  @valgrind_suppression_files
end

Instance Method Details

#command(*args) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ruby_memcheck/configuration.rb', line 95

def command(*args)
  [
    # On some Rubies, not setting the stack size to be ulimited causes
    # Valgrind to report the following error:
    #   Invalid write of size 1
    #     reserve_stack (thread_pthread.c:845)
    #     ruby_init_stack (thread_pthread.c:871)
    #     main (main.c:48)
    "ulimit -s unlimited && ",
    # On some distros, and in some Docker containers, the number of file descriptors is set to a
    # very high number like 1073741816 that valgrind >= 3.21.0 will error out on:
    #   --184100:0:libcfile Valgrind: FATAL: Private file creation failed.
    #      The current file descriptor limit is 1073741804.
    #      If you are running in Docker please consider
    #      lowering this limit with the shell built-in limit command.
    #   --184100:0:libcfile Exiting now.
    # See https://bugs.kde.org/show_bug.cgi?id=465435 for background information.
    "ulimit -n 8192 && ",
    valgrind,
    valgrind_options,
    valgrind_suppression_files.map { |f| "--suppressions=#{f}" },
    valgrind_generate_suppressions ? "--gen-suppressions=all" : "",
    ruby,
    "-r" + File.expand_path(File.join(__dir__, "test_helper.rb")),
    args,
  ].flatten.join(" ")
end