Top Level Namespace

Defined Under Namespace

Modules: Contrast, ContrastThread, DummyMod, ERBPropagator, ForcePrepend, Funchook Classes: Class, Delegator, Hash, Module, Object, String, Thread

Constant Summary collapse

FUNCHOOK_DIR_NAME =
'funchook'
FUNCHOOK_DIR =
File.expand_path(File.join(File.dirname(File.expand_path(__FILE__)), '..', FUNCHOOK_DIR_NAME))
COMMANDS =
['./autogen.sh', './configure', 'make clean', 'make'].freeze
SOURCE_PATHS =
[
  File.join('include', 'funchook.h'), File.join('src', 'libfunchook.dylib'),
  File.join('src', 'libfunchook.so')
].freeze
TARGET_PATHS =
([
  File.expand_path(File.join(File.expand_path(__dir__), '..', 'shared_libraries')),
  File.expand_path(__dir__)
] + bundler_install_target_paths).freeze
SYMS =

Create explicit symbol list, that will be set as promise to be loaded dynamic on run time.

%w[
  _assess
  _policy
  _assess_policy
  _assess_propagator
  _core_assess
  _contrast_patcher
  _contrast_check_prepended
  _contrast_check_and_register_instance_patch
  _contrast_register_singleton_prepend_patch
  _contrast_register_patch
  _contrast_register_singleton_patch
  _inst_methods_enter_cntr_scope
  _inst_methods_enter_method_scope
  _inst_methods_exit_cntr_scope
  _inst_methods_exit_method_scope
  _inst_methods_in_cntr_scope
  _rb_sym_method
  _rb_sym_hash_tracked
  _rb_sym_skip_assess_analysis
  _rb_sym_skip_contrast_analysis
  _patch_via_funchook
].freeze
STANDARD_FLAGS =

The mkmf.rb file uses all passed flags from Ruby configuration (RbConfig::CONFIG) on Ruby build time. Problem with Clang and GCC is that it do not keep up with c89 and finds error on including <ryby.h> as not allowing inline variables.

Ruby inlining is a C99 feature that is allowed to be used, because the Ruby configure script can work around the absence of the inline feature with a simple #define:

ifndef __cplusplus define inline endif

There is difference between using c89 and gnu89, as the latter is extended version of the 1989 standard allowing features like // comments for example. This makes the use of the gnu not favorable since it will skip some checks and would make wholes in the c89 standard support.

We can directly append the CFLAGS we need with ENV variable used to create the makefile. MAKEFILE_CONFIG is extension of the RbConfig::CONFIG used to build the Ruby itself. So if we try to run c89 on clang it will brake because of detecting errors from external library used - Ruby itself build with different standard as it seems. This means the Ruby must be compiled beforehand with the compiler forced to C89.

This makes the C dialect of choice to be gnu89 with strict pedantic warnings reported as errors, and making the compiler configurable by flags:

'-std=gnu89'
CLANG =
'clang'
WARNING_FLAGS =

Adding -pedantic could raise <ruby.h> warnings, and we are not in control of that code. e.g. error: ‘_Bool’ is a C99 extension [-Werror,-Wc99-extensions] ; empty macros and etc.

-Wno-int-conversion => Passing VALUEs as function args but required as unsigned long parameters. -Werror => report all warnings as errors -Wshorten-64-to-32 => is recognized by clang but not in gcc.

Use alternative if viable. [Wno-narrowing]

-Wno-maybe-uninitialized is used by clang but not gcc

Note: Clang supports old style function definition e.g. void func () {}
but the gcc is not.
make sure to add parameters type => void func (void) {}.
All Changes must be tested against both clang and gcc.
%w[
  -Wno-language-extension-token -Wno-incompatible-function-pointer-types
  -Wno-declaration-after-statement -Wno-variadic-macros -Wno-int-conversion
  -Wno-incompatible-pointer-types -Wno-narrowing
].freeze
GCC_FLAGS =

Flags that are only recognized by gcc:

%w[-Wno-maybe-uninitialized].freeze

Instance Method Summary collapse

Instance Method Details

#darwin?Boolean

rubocop:disable Security/Object/Freeze

Returns:

  • (Boolean)


82
83
84
# File 'ext/extconf_common.rb', line 82

def darwin?
  RbConfig::CONFIG['target_os'].include?('darwin')
end

#enable_env_ccObject

use C compiler if set.



106
107
108
# File 'ext/extconf_common.rb', line 106

def enable_env_cc
  RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
end

#ext_pathObject

__dir__ is relative to the file you’re reading. this file you’re reading is presently within $APP_ROOT/ext/.



161
162
163
# File 'ext/extconf_common.rb', line 161

def ext_path
  __dir__
end

#extend_cflagsObject

Extend $CFLAGS passed directly to compiler in ruby mkmf

Extended flags are mainly tested with clang and gcc. Experience with other compilers may vary. To that end if something brakes on client side we must have a mechanism to go back to previous non strict gnu89 standard and be able to maintain the build. We can disable newly added changes with this setting CONTRAST_USE_C89=false.



92
93
94
95
96
97
98
99
100
101
102
103
# File 'ext/extconf_common.rb', line 92

def extend_cflags
  return if ENV['CONTRAST__USE_GNU89'] == 'false'

  $CFLAGS += " #{ [STANDARD_FLAGS, WARNING_FLAGS].flatten.join(' ') }"
  # Extend with GCC specific flags:
  unless RbConfig::MAKEFILE_CONFIG['CC'].downcase.include?(CLANG) ||
        RbConfig::MAKEFILE_CONFIG['CPP'].downcase.include?(CLANG) ||
        RbConfig::CONFIG['CC'].downcase.include?(CLANG)

    $CFLAGS += " #{ GCC_FLAGS.flatten.join(' ') }"
  end
end

#mac_symbol_resolveObject

Since we cannot link directly the bundles created after the extensions being build, we can pass flags to the linker to resolve symbols not being found during compilation, since they are going to be available on load time. Ruby first is loaded then the extensions. MacOS introduced new fixups with Xcode 14. This causes the issue of symbols not being linked during compilation for the Agent, and other ruby related issues with objective C objects being used, bigdecimal being different and so on.

Ruby itself is build on MacOS with ‘–enabled-shared’ flag, also Ruby interpreters compiled under Xcode14 no longer specify by default in DLDFLAGS this flag:

'-undefined dynamic_lookup'

( As of Xcode14.3 behavior of dynamic_lookup is reverted back.)

This simply is telling the linker that any unknown symbols will be resolved dynamic on extension load. However with the new fixup chain introduced an warning may be produced: ld: warning: -undefined dynamic_lookup may not work with chained fixups. The fixups are responsible for the dynamic linking of the dylibs.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'ext/extconf_common.rb', line 127

def mac_symbol_resolve
  # If this is braking the build, it can be disabled.
  return if ENV['CONTRAST__NO_MAC_LD_FIX'] == 'true'
  return unless darwin?

  # Disabled as of the unknown changes to newly ruby interpreter builds:
  # RbConfig::CONFIG['EXTDLDFLAGS'] = "-bundle_loader #{ RbConfig::CONFIG['EXTDLDFLAGS'] }"

  # Avoid using this, as not desirable:
  #
  # Adding -no_fixup_chains will brake older compilers but will work on newer.
  # This flag solves the problem but on the long run might not be the solution needed, now not being default,
  # any new feature changes on Mac or Ruby side might brake things again.
  # Use this only if explicitly set as ENV var,as a backup on client's end.
  #
  # $LDFLAGS << " " << flag
  append_ldflags('-Wl,-no_fixup_chains -undefined dynamic_lookup') if ENV['CONTRAST__MAC_LD_USE_ALT'] == 'true'

  # Another alternative is to use -Wl,-U with explicit listed depending symbols.
  # Append the symfile:
  SYMS.each { |sym| $DLDFLAGS << " -Wl,-U,#{ sym }" } unless ENV['CONTRAST__MAC_LD_USE_ALT'] == 'true'
end

#make!Object

Generate Makefile.



151
152
153
# File 'ext/extconf_common.rb', line 151

def make!
  create_makefile("#{ $TO_MAKE }/#{ $TO_MAKE }")
end