PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/test/-ext-/symbol/test_inadvertent_creation.rb

http://github.com/ruby/ruby
Ruby | 495 lines | 414 code | 79 blank | 2 comment | 0 complexity | b9aa5d8337ec83343f4fe9b6c381e172 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # frozen_string_literal: false
  2. require 'test/unit'
  3. require_relative 'noninterned_name'
  4. module Test_Symbol
  5. class TestInadvertent < Test::Unit::TestCase
  6. include NonInterned
  7. def setup
  8. @obj = Object.new
  9. end
  10. def assert_not_pinneddown(name, msg = nil)
  11. assert_not_send([Bug::Symbol, :pinneddown?, name], msg)
  12. end
  13. def assert_not_interned(name, msg = nil)
  14. assert_not_send([Bug::Symbol, :find, name], msg)
  15. end
  16. def assert_not_interned_error(obj, meth, name, msg = nil, &block)
  17. e = assert_raise(NameError, msg) {obj.__send__(meth, name, &block)}
  18. assert_not_pinneddown(name, msg)
  19. e
  20. end
  21. def assert_not_interned_false(obj, meth, name, msg = nil)
  22. assert_not_send([obj, meth, name], msg)
  23. assert_not_pinneddown(name, msg)
  24. end
  25. Feature5072 = '[ruby-core:38367]'
  26. def test_module_const_get
  27. cl = Class.new
  28. name = noninterned_name("A")
  29. assert_not_interned_error(cl, :const_get, name, Feature5072)
  30. assert_not_interned_error(cl, :const_get, name.to_sym)
  31. end
  32. def test_module_const_get_toplevel
  33. bug12089 = '[ruby-dev:49498] [Bug #12089]'
  34. name = noninterned_name("A")
  35. e = assert_not_interned_error(Object, :const_get, name)
  36. assert_equal(name, e.name)
  37. assert_not_match(/Object::/, e.message, bug12089)
  38. end
  39. def test_module_const_defined?
  40. cl = Class.new
  41. name = noninterned_name("A")
  42. assert_not_interned_false(cl, :const_defined?, name, Feature5072)
  43. name = noninterned_name
  44. assert_not_interned_error(cl, :const_defined?, name.to_sym)
  45. end
  46. def test_module_define_method_type_error
  47. cl = Class.new
  48. name = noninterned_name
  49. assert_raise(TypeError) {cl.class_eval {define_method(name, "")}}
  50. assert_not_interned(name)
  51. assert_raise(TypeError) {cl.class_eval {define_method(name.to_sym, "")}}
  52. assert_not_pinneddown(name)
  53. end
  54. def test_module_define_method_argument_error
  55. cl = Class.new
  56. name = noninterned_name
  57. assert_raise(ArgumentError) {cl.class_eval {define_method(name)}}
  58. assert_not_interned(name)
  59. assert_raise(ArgumentError) {cl.class_eval {define_method(name.to_sym)}}
  60. assert_not_pinneddown(name)
  61. end
  62. def test_respond_to_missing
  63. feature5072 = Feature5072
  64. c = Class.new do
  65. def self.respond_to_missing?(*)
  66. super
  67. end
  68. end
  69. s = noninterned_name
  70. # assert_not_interned_false(c, :respond_to?, s, feature5072)
  71. assert_not_interned_false(c, :method_defined?, s, feature5072)
  72. assert_not_interned_false(c, :public_method_defined?, s, feature5072)
  73. assert_not_interned_false(c, :private_method_defined?, s, feature5072)
  74. assert_not_interned_false(c, :protected_method_defined?, s, feature5072)
  75. assert_not_interned_false(c, :const_defined?, noninterned_name("A"), feature5072)
  76. assert_not_interned_false(c, :instance_variable_defined?, noninterned_name("@"), feature5072)
  77. assert_not_interned_false(c, :class_variable_defined?, noninterned_name("@@"), feature5072)
  78. end
  79. def test_missing_method
  80. bug10985 = '[ruby-core:68564] [Bug #10985]'
  81. m = nil
  82. c = Class.new do
  83. def self.respond_to_missing?(*)
  84. true
  85. end
  86. end
  87. s = noninterned_name
  88. assert_nothing_raised(NameError, bug10985) {m = c.method(s)}
  89. assert_raise_with_message(NoMethodError, /#{s}/) {m.call}
  90. s = noninterned_name
  91. assert_nothing_raised(NameError, bug10985) {m = c.public_method(s.to_sym)}
  92. assert_raise_with_message(NoMethodError, /#{s}/) {m.call}
  93. s = noninterned_name
  94. assert_nothing_raised(NameError, bug10985) {m = c.singleton_method(s.to_sym)}
  95. assert_raise_with_message(NoMethodError, /#{s}/) {m.call}
  96. end
  97. Feature5079 = '[ruby-core:38404]'
  98. def test_undefined_instance_variable
  99. feature5079 = Feature5079
  100. c = Class.new
  101. iv = noninterned_name("@")
  102. assert_not_interned_false(c, :instance_variable_get, iv, feature5079)
  103. assert_not_interned_error(c, :remove_instance_variable, iv, feature5079)
  104. end
  105. def test_undefined_class_variable
  106. feature5079 = Feature5079
  107. c = Class.new
  108. cv = noninterned_name("@@")
  109. assert_not_interned_error(c, :class_variable_get, cv, feature5079)
  110. assert_not_interned_error(c, :remove_class_variable, cv, feature5079)
  111. end
  112. def test_undefined_const
  113. feature5079 = Feature5079
  114. c = Class.new
  115. s = noninterned_name("A")
  116. assert_not_interned_error(c, :remove_const, s, feature5079)
  117. end
  118. def test_undefined_method
  119. feature5079 = Feature5079
  120. c = Class.new
  121. s = noninterned_name
  122. assert_not_interned_error(c, :method, s, feature5079)
  123. assert_not_interned_error(c, :public_method, s, feature5079)
  124. assert_not_interned_error(c, :instance_method, s, feature5079)
  125. assert_not_interned_error(c, :public_instance_method, s, feature5079)
  126. assert_not_interned_error(c, :singleton_method, s, feature5079)
  127. end
  128. Feature5089 = '[ruby-core:38447]'
  129. def test_const_missing
  130. feature5089 = Feature5089
  131. c = Class.new do
  132. def self.const_missing(const_name)
  133. raise NameError, const_name.to_s
  134. end
  135. end
  136. s = noninterned_name("A")
  137. assert_not_interned_error(c, :const_get, s.to_sym, feature5089)
  138. assert_not_interned_false(c, :autoload?, s.to_sym, feature5089)
  139. end
  140. def test_aliased_method
  141. feature5089 = Feature5089
  142. c = Class.new do
  143. def self.alias_method(str)
  144. super(:puts, str)
  145. end
  146. end
  147. s = noninterned_name
  148. assert_not_interned_error(c, :alias_method, s, feature5089)
  149. assert_not_interned_error(c, :private_class_method, s, feature5089)
  150. assert_not_interned_error(c, :private_constant, s, feature5089)
  151. assert_not_interned_error(c, :private, s, feature5089)
  152. assert_not_interned_error(c, :protected, s, feature5089)
  153. assert_not_interned_error(c, :public, s, feature5089)
  154. assert_not_interned_error(c, :public_class_method, s, feature5089)
  155. assert_not_interned_error(c, :public_constant, s, feature5089)
  156. assert_not_interned_error(c, :remove_method, s, feature5089)
  157. assert_not_interned_error(c, :undef_method, s, feature5089)
  158. assert_not_interned_error(c, :untrace_var, s, feature5089)
  159. end
  160. Feature5112 = '[ruby-core:38576]'
  161. def test_public_send
  162. name = noninterned_name
  163. e = assert_raise(NoMethodError) {@obj.public_send(name, Feature5112)}
  164. assert_not_interned(name)
  165. assert_equal(name, e.name)
  166. assert_equal([Feature5112], e.args)
  167. end
  168. def test_send
  169. name = noninterned_name
  170. e = assert_raise(NoMethodError) {@obj.send(name, Feature5112)}
  171. assert_not_interned(name)
  172. assert_equal(name, e.name)
  173. assert_equal([Feature5112], e.args)
  174. end
  175. def test___send__
  176. name = noninterned_name
  177. e = assert_raise(NoMethodError) {@obj.__send__(name, Feature5112)}
  178. assert_not_interned(name)
  179. assert_equal(name, e.name)
  180. assert_equal([Feature5112], e.args)
  181. end
  182. def test_thread_aref
  183. Thread.current[:test] = nil
  184. name = noninterned_name
  185. assert_nil(Thread.current[name])
  186. assert_not_interned(name)
  187. end
  188. def test_thread_key?
  189. Thread.current[:test] = nil
  190. name = noninterned_name
  191. assert_not_send([Thread.current, :key?, name])
  192. assert_not_interned(name)
  193. end
  194. def test_thread_variable_get
  195. Thread.current.thread_variable_set(:test, nil)
  196. name = noninterned_name
  197. assert_nil(Thread.current.thread_variable_get(name))
  198. assert_not_pinneddown(name)
  199. end
  200. def test_thread_variable_set
  201. name = noninterned_name
  202. Thread.current.thread_variable_set(name, 42)
  203. assert_not_pinneddown(name)
  204. end
  205. def test_thread_variable?
  206. Thread.current.thread_variable_set(:test, nil)
  207. name = noninterned_name
  208. assert_not_send([Thread.current, :thread_variable?, name])
  209. assert_not_interned(name)
  210. end
  211. def test_enumerable_inject_op
  212. name = noninterned_name
  213. assert_raise(NoMethodError) {[1, 2].inject(name)}
  214. assert_not_interned(name)
  215. end
  216. def test_module_const_set
  217. name = noninterned_name
  218. mod = Module.new
  219. assert_raise(NameError) {mod.const_set(name, true)}
  220. assert_not_interned(name)
  221. assert_raise(NameError) {mod.const_set(name.to_sym, true)}
  222. assert_not_pinneddown(name)
  223. end
  224. def test_module_cvar_set
  225. name = noninterned_name
  226. mod = Module.new
  227. assert_raise(NameError) {mod.class_variable_set(name, true)}
  228. assert_not_interned(name)
  229. assert_raise(NameError) {mod.class_variable_set(name.to_sym, true)}
  230. assert_not_pinneddown(name)
  231. end
  232. def test_object_ivar_set
  233. name = noninterned_name
  234. obj = Object.new
  235. assert_raise(NameError) {obj.instance_variable_set(name, true)}
  236. assert_not_interned(name)
  237. assert_raise(NameError) {obj.instance_variable_set(name.to_sym, true)}
  238. assert_not_pinneddown(name)
  239. end
  240. def test_struct_new
  241. name = noninterned_name
  242. assert_raise(NameError) {Struct.new(name)}
  243. assert_not_interned(name)
  244. end
  245. def test_struct_aref
  246. s = Struct.new(:foo).new
  247. name = noninterned_name
  248. assert_raise(NameError) {s[name]}
  249. assert_not_interned(name)
  250. end
  251. def test_struct_aset
  252. s = Struct.new(:foo).new
  253. name = noninterned_name
  254. assert_raise(NameError) {s[name] = true}
  255. assert_not_interned(name)
  256. end
  257. def test_invalid_attr
  258. name = noninterned_name("*")
  259. mod = Module.new
  260. assert_raise(NameError) {mod.module_eval {attr(name)}}
  261. assert_not_interned(name)
  262. assert_raise(NameError) {mod.module_eval {attr(name.to_sym)}}
  263. assert_not_pinneddown(name)
  264. end
  265. def test_invalid_attr_reader
  266. name = noninterned_name("*")
  267. mod = Module.new
  268. assert_raise(NameError) {mod.module_eval {attr_reader(name)}}
  269. assert_not_interned(name)
  270. assert_raise(NameError) {mod.module_eval {attr_reader(name.to_sym)}}
  271. assert_not_pinneddown(name)
  272. end
  273. def test_invalid_attr_writer
  274. name = noninterned_name("*")
  275. mod = Module.new
  276. assert_raise(NameError) {mod.module_eval {attr_writer(name)}}
  277. assert_not_interned(name)
  278. assert_raise(NameError) {mod.module_eval {attr_writer(name.to_sym)}}
  279. assert_not_pinneddown(name)
  280. end
  281. def test_invalid_attr_accessor
  282. name = noninterned_name("*")
  283. mod = Module.new
  284. assert_raise(NameError) {mod.module_eval {attr_accessor(name)}}
  285. assert_not_interned(name)
  286. assert_raise(NameError) {mod.module_eval {attr_accessor(name.to_sym)}}
  287. assert_not_pinneddown(name)
  288. end
  289. def test_gc_attrset
  290. assert_separately(['-r-test-/symbol', '-r-ext-/symbol/noninterned_name', '-'], "#{<<-'begin;'}\n#{<<-"end;"}")
  291. bug = '[ruby-core:62226] [Bug #9787]'
  292. include Test_Symbol::NonInterned
  293. names = Array.new(1000) {noninterned_name("gc")}
  294. names.each {|n| n.to_sym}
  295. GC.start(immediate_sweep: false)
  296. names.each do |n|
  297. eval(":#{n}=")
  298. assert_nothing_raised(TypeError, bug) {eval("proc{self.#{n} = nil}")}
  299. end
  300. begin;
  301. end;
  302. end
  303. def test_execopt_key
  304. name = noninterned_name.intern
  305. assert_raise(ArgumentError) {
  306. system(".", name => nil)
  307. }
  308. assert_not_pinneddown(name)
  309. end
  310. def test_execopt_redirect_value
  311. name = noninterned_name.intern
  312. assert_raise(ArgumentError) {
  313. system(".", [] => name)
  314. }
  315. assert_not_pinneddown(name)
  316. end
  317. def test_execopt_redirect_path
  318. name = noninterned_name.intern
  319. assert_raise(TypeError) {
  320. system(".", [] => [name, 0])
  321. }
  322. assert_not_pinneddown(name)
  323. end
  324. def test_execopt_redirect_symbol
  325. name = noninterned_name.intern
  326. assert_raise(ArgumentError) {
  327. system(".", in: name)
  328. }
  329. assert_not_pinneddown(name)
  330. end
  331. def assert_no_immortal_symbol_created(name)
  332. name = noninterned_name(name)
  333. yield(name)
  334. assert_not_pinneddown(name)
  335. end
  336. def assert_no_immortal_symbol_in_method_missing(name)
  337. assert_no_immortal_symbol_created("send should not leak - #{name}") do |name|
  338. assert_raise(NoMethodError) {yield(name)}
  339. end
  340. end
  341. def test_send_leak_string
  342. assert_no_immortal_symbol_in_method_missing("str") do |name|
  343. 42.send(name)
  344. end
  345. end
  346. def test_send_leak_symbol
  347. assert_no_immortal_symbol_in_method_missing("sym") do |name|
  348. 42.send(name.to_sym)
  349. end
  350. end
  351. def test_send_leak_string_custom_method_missing
  352. x = Object.new
  353. def x.method_missing(*); super; end
  354. assert_no_immortal_symbol_in_method_missing("str mm") do |name|
  355. x.send(name)
  356. end
  357. end
  358. def test_send_leak_symbol_custom_method_missing
  359. x = Object.new
  360. def x.method_missing(*); super; end
  361. assert_no_immortal_symbol_in_method_missing("sym mm") do |name|
  362. x.send(name.to_sym)
  363. end
  364. end
  365. def test_send_leak_string_no_optimization
  366. assert_no_immortal_symbol_in_method_missing("str slow") do |name|
  367. 42.method(:send).call(name)
  368. end
  369. end
  370. def test_send_leak_symbol_no_optimization
  371. assert_no_immortal_symbol_in_method_missing("sym slow") do |name|
  372. 42.method(:send).call(name.to_sym)
  373. end
  374. end
  375. def test_send_leak_string_custom_method_missing_no_optimization
  376. x = Object.new
  377. def x.method_missing(*); super; end
  378. assert_no_immortal_symbol_in_method_missing("str mm slow") do |name|
  379. x.method(:send).call(name)
  380. end
  381. end
  382. def test_send_leak_symbol_custom_method_missing_no_optimization
  383. x = Object.new
  384. def x.method_missing(*); super; end
  385. assert_no_immortal_symbol_in_method_missing("sym mm slow") do |name|
  386. x.method(:send).call(name.to_sym)
  387. end
  388. end
  389. def test_kwarg_symbol_leak_no_rest
  390. foo = -> (arg: 42) {}
  391. assert_no_immortal_symbol_created("kwarg no rest") do |name|
  392. assert_raise(ArgumentError) { foo.call(name.to_sym => 42) }
  393. end
  394. end
  395. def test_kwarg_symbol_leak_with_rest
  396. foo = -> (arg: 2, **options) {}
  397. assert_no_immortal_symbol_created("kwarg with rest") do |name|
  398. foo.call(name.to_sym => 42)
  399. end
  400. end
  401. def test_kwarg_symbol_leak_just_rest
  402. foo = -> (**options) {}
  403. assert_no_immortal_symbol_created("kwarg just rest") do |name|
  404. foo.call(name.to_sym => 42)
  405. end
  406. end
  407. def test_iv_get
  408. obj = Object.new
  409. assert_warning(/not initialized/) do
  410. assert_no_immortal_symbol_created("rb_iv_get") do |name|
  411. Bug::Symbol.iv_get(obj, name)
  412. end
  413. end
  414. end
  415. end
  416. end