google-cloud-debugger 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +111 -75
- data/ext/google/cloud/debugger/debugger_c/evaluator.c +14 -9
- data/lib/google-cloud-debugger.rb +55 -0
- data/lib/google/cloud/debugger.rb +140 -22
- data/lib/google/cloud/debugger/agent.rb +4 -4
- data/lib/google/cloud/debugger/breakpoint.rb +2 -2
- data/lib/google/cloud/debugger/breakpoint/evaluator.rb +885 -828
- data/lib/google/cloud/debugger/breakpoint/source_location.rb +1 -2
- data/lib/google/cloud/debugger/breakpoint/validator.rb +6 -6
- data/lib/google/cloud/debugger/breakpoint/variable.rb +7 -8
- data/lib/google/cloud/debugger/breakpoint_manager.rb +1 -1
- data/lib/google/cloud/debugger/credentials.rb +7 -7
- data/lib/google/cloud/debugger/debuggee.rb +4 -8
- data/lib/google/cloud/debugger/debuggee/app_uniquifier_generator.rb +0 -2
- data/lib/google/cloud/debugger/logpoint.rb +1 -1
- data/lib/google/cloud/debugger/middleware.rb +16 -18
- data/lib/google/cloud/debugger/project.rb +2 -28
- data/lib/google/cloud/debugger/rails.rb +21 -9
- data/lib/google/cloud/debugger/service.rb +4 -2
- data/lib/google/cloud/debugger/snappoint.rb +1 -1
- data/lib/google/cloud/debugger/tracer.rb +2 -1
- data/lib/google/cloud/debugger/transmitter.rb +1 -1
- data/lib/google/cloud/debugger/version.rb +1 -1
- metadata +11 -11
@@ -49,7 +49,7 @@ module Google
|
|
49
49
|
class Agent
|
50
50
|
##
|
51
51
|
# Name of the logpoints log file.
|
52
|
-
DEFAULT_LOG_NAME = "debugger_logpoints"
|
52
|
+
DEFAULT_LOG_NAME = "debugger_logpoints".freeze
|
53
53
|
|
54
54
|
##
|
55
55
|
# @private Debugger Agent is an asynchronous actor
|
@@ -182,7 +182,7 @@ module Google
|
|
182
182
|
breakpoint_manager.sync_active_breakpoints debuggee.id
|
183
183
|
debuggee.revoke_registration unless sync_result
|
184
184
|
end
|
185
|
-
rescue => e
|
185
|
+
rescue StandardError => e
|
186
186
|
warn ["#{e.class}: #{e.message}", e.backtrace].join("\n\t")
|
187
187
|
@last_exception = e
|
188
188
|
end
|
@@ -242,8 +242,8 @@ module Google
|
|
242
242
|
project_id = @service.project
|
243
243
|
credentials = @service.credentials
|
244
244
|
logging = Google::Cloud::Logging::Project.new(
|
245
|
-
Google::Cloud::Logging::Service.new(
|
246
|
-
|
245
|
+
Google::Cloud::Logging::Service.new(project_id, credentials)
|
246
|
+
)
|
247
247
|
resource =
|
248
248
|
Google::Cloud::Logging::Middleware.build_monitored_resource
|
249
249
|
|
@@ -315,7 +315,7 @@ module Google
|
|
315
315
|
|
316
316
|
|
317
317
|
condition_result ? true : false
|
318
|
-
rescue => e
|
318
|
+
rescue StandardError => e
|
319
319
|
set_error_state "Error: #{e.message}",
|
320
320
|
refers_to: StatusMessage::BREAKPOINT_CONDITION
|
321
321
|
false
|
@@ -424,7 +424,7 @@ module Google
|
|
424
424
|
# @private Exports Breakpoint status to
|
425
425
|
# Google::Devtools::Clouddebugger::V2::StatusMessage object
|
426
426
|
def status_to_grpc
|
427
|
-
status.nil? ? nil: status.to_grpc
|
427
|
+
status.nil? ? nil : status.to_grpc
|
428
428
|
end
|
429
429
|
|
430
430
|
##
|
@@ -37,13 +37,13 @@ module Google
|
|
37
37
|
# Doc](https://cloud.google.com/debugger/api/reference/rpc/google.devtools.clouddebugger.v2#google.devtools.clouddebugger.v2.Breakpoint)
|
38
38
|
# for details.
|
39
39
|
#
|
40
|
-
|
40
|
+
class Evaluator
|
41
41
|
##
|
42
42
|
# @private YARV bytecode that the evaluator blocks during expression
|
43
43
|
# evaluation. If the breakpoint contains expressions that uses the
|
44
44
|
# following bytecode, the evaluator will block the expression
|
45
45
|
# evaluation from execusion.
|
46
|
-
BYTE_CODE_BLACKLIST = %w
|
46
|
+
BYTE_CODE_BLACKLIST = %w[
|
47
47
|
setinstancevariable
|
48
48
|
setclassvariable
|
49
49
|
setconstant
|
@@ -52,28 +52,28 @@ module Google
|
|
52
52
|
opt_ltlt
|
53
53
|
opt_aset
|
54
54
|
opt_aset_with
|
55
|
-
|
55
|
+
].freeze
|
56
56
|
|
57
57
|
##
|
58
58
|
# @private YARV bytecode that the evaluator blocks during expression
|
59
59
|
# evaluation on the top level. (not from within by predefined methods)
|
60
|
-
LOCAL_BYTE_CODE_BLACKLIST = %w
|
60
|
+
LOCAL_BYTE_CODE_BLACKLIST = %w[
|
61
61
|
setlocal
|
62
|
-
|
62
|
+
].freeze
|
63
63
|
|
64
64
|
##
|
65
65
|
# @private YARV bytecode call flags that the evaluator blocks during
|
66
66
|
# expression evaluation
|
67
|
-
FUNC_CALL_FLAG_BLACKLIST = %w
|
67
|
+
FUNC_CALL_FLAG_BLACKLIST = %w[
|
68
68
|
ARGS_BLOCKARG
|
69
|
-
|
69
|
+
].freeze
|
70
70
|
|
71
71
|
##
|
72
72
|
# @private YARV instructions catch table type that the evaluator
|
73
73
|
# blocks during expression evaluation
|
74
|
-
CATCH_TABLE_TYPE_BLACKLIST = %w
|
75
|
-
rescue
|
76
|
-
|
74
|
+
CATCH_TABLE_TYPE_BLACKLIST = %w[
|
75
|
+
rescue StandardError
|
76
|
+
].freeze
|
77
77
|
|
78
78
|
##
|
79
79
|
# @private Predefined regex. Saves time during runtime.
|
@@ -136,638 +136,596 @@ module Google
|
|
136
136
|
# during expression evaluation
|
137
137
|
C_CLASS_METHOD_WHITELIST = {
|
138
138
|
# Classes
|
139
|
-
ArgumentError => hashify(%I
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
}).freeze,
|
196
|
-
Object => hashify(%I{
|
197
|
-
new
|
198
|
-
}).freeze,
|
199
|
-
RangeError => hashify(%I{
|
200
|
-
new
|
201
|
-
}).freeze,
|
202
|
-
RegexpError => hashify(%I{
|
203
|
-
new
|
204
|
-
}).freeze,
|
205
|
-
RuntimeError => hashify(%I{
|
206
|
-
new
|
207
|
-
}).freeze,
|
208
|
-
String => hashify(%I{
|
209
|
-
new
|
210
|
-
try_convert
|
211
|
-
}).freeze,
|
212
|
-
Thread => hashify(%I{
|
213
|
-
DEBUG
|
214
|
-
abort_on_exception
|
215
|
-
current
|
216
|
-
list
|
217
|
-
main
|
218
|
-
pending_interrupt?
|
219
|
-
report_on_exception
|
220
|
-
}).freeze,
|
221
|
-
Time => hashify(%I{
|
222
|
-
at
|
223
|
-
gm
|
224
|
-
local
|
225
|
-
mktime
|
226
|
-
new
|
227
|
-
now
|
228
|
-
utc
|
229
|
-
}).freeze,
|
230
|
-
TypeError => hashify(%I{
|
231
|
-
new
|
232
|
-
}).freeze,
|
233
|
-
Google::Cloud::Debugger::Breakpoint::Evaluator => hashify(%I{
|
234
|
-
disable_method_trace_for_thread
|
235
|
-
}).freeze,
|
236
|
-
ZeroDivisionError => hashify(%I{
|
237
|
-
new
|
238
|
-
}).freeze
|
139
|
+
ArgumentError => hashify(%I[new]).freeze,
|
140
|
+
Array => hashify(%I[new [] try_convert]).freeze,
|
141
|
+
BasicObject => hashify(%I[new]).freeze,
|
142
|
+
Exception => hashify(%I[exception new]).freeze,
|
143
|
+
Enumerator => hashify(%I[new]).freeze,
|
144
|
+
Fiber => hashify(%I[current]).freeze,
|
145
|
+
FiberError => hashify(%I[new]).freeze,
|
146
|
+
File => hashify(
|
147
|
+
%I[
|
148
|
+
basename
|
149
|
+
dirname
|
150
|
+
extname
|
151
|
+
join
|
152
|
+
path
|
153
|
+
split
|
154
|
+
]
|
155
|
+
).freeze,
|
156
|
+
FloatDomainError => hashify(%I[new]).freeze,
|
157
|
+
Hash => hashify(%I[new [] try_convert]).freeze,
|
158
|
+
IndexError => hashify(%I[new]).freeze,
|
159
|
+
KeyError => hashify(%I[new]).freeze,
|
160
|
+
Module => hashify(%I[constants nesting used_modules]).freeze,
|
161
|
+
NameError => hashify(%I[new]).freeze,
|
162
|
+
NoMethodError => hashify(%I[new]).freeze,
|
163
|
+
Object => hashify(%I[new]).freeze,
|
164
|
+
RangeError => hashify(%I[new]).freeze,
|
165
|
+
RegexpError => hashify(%I[new]).freeze,
|
166
|
+
RuntimeError => hashify(%I[new]).freeze,
|
167
|
+
String => hashify(%I[new try_convert]).freeze,
|
168
|
+
Thread => hashify(
|
169
|
+
%I[
|
170
|
+
DEBUG
|
171
|
+
abort_on_exception
|
172
|
+
current
|
173
|
+
list
|
174
|
+
main
|
175
|
+
pending_interrupt?
|
176
|
+
report_on_exception
|
177
|
+
]
|
178
|
+
).freeze,
|
179
|
+
Time => hashify(
|
180
|
+
%I[
|
181
|
+
at
|
182
|
+
gm
|
183
|
+
local
|
184
|
+
mktime
|
185
|
+
new
|
186
|
+
now
|
187
|
+
utc
|
188
|
+
]
|
189
|
+
).freeze,
|
190
|
+
TypeError => hashify(%I[new]).freeze,
|
191
|
+
Google::Cloud::Debugger::Breakpoint::Evaluator => hashify(
|
192
|
+
%I[disable_method_trace_for_thread]
|
193
|
+
).freeze,
|
194
|
+
ZeroDivisionError => hashify(%I[new]).freeze
|
239
195
|
}.freeze
|
240
196
|
|
241
197
|
##
|
242
198
|
# @private List of C level instance methods that the evaluator allows
|
243
199
|
# during expression evaluation
|
244
200
|
C_INSTANCE_METHOD_WHITELIST = {
|
245
|
-
ArgumentError => hashify(%I
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
BasicObject => hashify(
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
Enumerator => hashify(
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
FiberError => hashify(%I
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
clone
|
691
|
-
eql?
|
692
|
-
hash
|
693
|
-
inspect
|
694
|
-
name
|
695
|
-
original_name
|
696
|
-
owner
|
697
|
-
parameters
|
698
|
-
source_location
|
699
|
-
super_method
|
700
|
-
to_s
|
701
|
-
}).freeze,
|
702
|
-
ZeroDivisionError => hashify(%I{
|
703
|
-
initialize
|
704
|
-
}).freeze,
|
201
|
+
ArgumentError => hashify(%I[initialize]).freeze,
|
202
|
+
Array => hashify(
|
203
|
+
%I[
|
204
|
+
initialize
|
205
|
+
&
|
206
|
+
*
|
207
|
+
+
|
208
|
+
-
|
209
|
+
<=>
|
210
|
+
==
|
211
|
+
any?
|
212
|
+
assoc
|
213
|
+
at
|
214
|
+
bsearch
|
215
|
+
bsearch_index
|
216
|
+
collect
|
217
|
+
combination
|
218
|
+
compact
|
219
|
+
[]
|
220
|
+
count
|
221
|
+
cycle
|
222
|
+
dig
|
223
|
+
drop
|
224
|
+
drop_while
|
225
|
+
each
|
226
|
+
each_index
|
227
|
+
empty?
|
228
|
+
eql?
|
229
|
+
fetch
|
230
|
+
find_index
|
231
|
+
first
|
232
|
+
flatten
|
233
|
+
frozen?
|
234
|
+
hash
|
235
|
+
include?
|
236
|
+
index
|
237
|
+
inspect
|
238
|
+
to_s
|
239
|
+
join
|
240
|
+
last
|
241
|
+
length
|
242
|
+
map
|
243
|
+
max
|
244
|
+
min
|
245
|
+
pack
|
246
|
+
permutation
|
247
|
+
product
|
248
|
+
rassoc
|
249
|
+
reject
|
250
|
+
repeated_combination
|
251
|
+
repeated_permutation
|
252
|
+
reverse
|
253
|
+
reverse_each
|
254
|
+
rindex
|
255
|
+
rotate
|
256
|
+
sample
|
257
|
+
select
|
258
|
+
shuffle
|
259
|
+
size
|
260
|
+
slice
|
261
|
+
sort
|
262
|
+
sum
|
263
|
+
take
|
264
|
+
take_while
|
265
|
+
to_a
|
266
|
+
to_ary
|
267
|
+
to_h
|
268
|
+
transpose
|
269
|
+
uniq
|
270
|
+
values_at
|
271
|
+
zip
|
272
|
+
|
|
273
|
+
]
|
274
|
+
).freeze,
|
275
|
+
BasicObject => hashify(
|
276
|
+
%I[
|
277
|
+
initialize
|
278
|
+
!
|
279
|
+
!=
|
280
|
+
==
|
281
|
+
__id__
|
282
|
+
method_missing
|
283
|
+
object_id
|
284
|
+
send
|
285
|
+
__send__
|
286
|
+
equal?
|
287
|
+
]
|
288
|
+
).freeze,
|
289
|
+
Binding => hashify(
|
290
|
+
%I[
|
291
|
+
local_variable_defined?
|
292
|
+
local_variable_get
|
293
|
+
local_variables
|
294
|
+
receiver
|
295
|
+
]
|
296
|
+
).freeze,
|
297
|
+
Class => hashify(%I[superclass]).freeze,
|
298
|
+
Dir => hashify(%I[inspect path to_path]).freeze,
|
299
|
+
Exception => hashify(
|
300
|
+
%I[
|
301
|
+
initialize
|
302
|
+
==
|
303
|
+
backtrace
|
304
|
+
backtrace_locations
|
305
|
+
cause
|
306
|
+
exception
|
307
|
+
inspect
|
308
|
+
message
|
309
|
+
to_s
|
310
|
+
]
|
311
|
+
).freeze,
|
312
|
+
Enumerator => hashify(
|
313
|
+
%I[
|
314
|
+
initialize
|
315
|
+
each
|
316
|
+
each_with_index
|
317
|
+
each_with_object
|
318
|
+
inspect
|
319
|
+
size
|
320
|
+
with_index
|
321
|
+
with_object
|
322
|
+
]
|
323
|
+
).freeze,
|
324
|
+
Fiber => hashify(%I[alive?]).freeze,
|
325
|
+
FiberError => hashify(%I[initialize]).freeze,
|
326
|
+
File => hashify(%I[path to_path]).freeze,
|
327
|
+
FloatDomainError => hashify(%I[initialize]).freeze,
|
328
|
+
Hash => hashify(
|
329
|
+
%I[
|
330
|
+
initialize
|
331
|
+
<
|
332
|
+
<=
|
333
|
+
==
|
334
|
+
>
|
335
|
+
>=
|
336
|
+
[]
|
337
|
+
any?
|
338
|
+
assoc
|
339
|
+
compact
|
340
|
+
compare_by_identity?
|
341
|
+
default_proc
|
342
|
+
dig
|
343
|
+
each
|
344
|
+
each_key
|
345
|
+
each_pair
|
346
|
+
each_value
|
347
|
+
empty?
|
348
|
+
eql?
|
349
|
+
fetch
|
350
|
+
fetch_values
|
351
|
+
flatten
|
352
|
+
has_key?
|
353
|
+
has_value?
|
354
|
+
hash
|
355
|
+
include?
|
356
|
+
to_s
|
357
|
+
inspect
|
358
|
+
invert
|
359
|
+
key
|
360
|
+
key?
|
361
|
+
keys
|
362
|
+
length
|
363
|
+
member?
|
364
|
+
merge
|
365
|
+
rassoc
|
366
|
+
reject
|
367
|
+
select
|
368
|
+
size
|
369
|
+
to_a
|
370
|
+
to_h
|
371
|
+
to_hash
|
372
|
+
to_proc
|
373
|
+
transform_values
|
374
|
+
value?
|
375
|
+
values
|
376
|
+
value_at
|
377
|
+
]
|
378
|
+
).freeze,
|
379
|
+
IndexError => hashify(%I[initialize]).freeze,
|
380
|
+
IO => hashify(
|
381
|
+
%I[
|
382
|
+
autoclose?
|
383
|
+
binmode?
|
384
|
+
close_on_exec?
|
385
|
+
closed?
|
386
|
+
encoding
|
387
|
+
inspect
|
388
|
+
internal_encoding
|
389
|
+
sync
|
390
|
+
]
|
391
|
+
).freeze,
|
392
|
+
KeyError => hashify(%I[initialize]).freeze,
|
393
|
+
Method => hashify(
|
394
|
+
%I[
|
395
|
+
==
|
396
|
+
[]
|
397
|
+
arity
|
398
|
+
call
|
399
|
+
clone
|
400
|
+
curry
|
401
|
+
eql?
|
402
|
+
hash
|
403
|
+
inspect
|
404
|
+
name
|
405
|
+
original_name
|
406
|
+
owner
|
407
|
+
parameters
|
408
|
+
receiver
|
409
|
+
source_location
|
410
|
+
super_method
|
411
|
+
to_proc
|
412
|
+
to_s
|
413
|
+
]
|
414
|
+
).freeze,
|
415
|
+
Module => hashify(
|
416
|
+
%I[
|
417
|
+
<
|
418
|
+
<=
|
419
|
+
<=>
|
420
|
+
==
|
421
|
+
===
|
422
|
+
>
|
423
|
+
>=
|
424
|
+
ancestors
|
425
|
+
autoload?
|
426
|
+
class_variable_defined?
|
427
|
+
class_variable_get
|
428
|
+
class_variables
|
429
|
+
const_defined?
|
430
|
+
const_get
|
431
|
+
constants
|
432
|
+
include?
|
433
|
+
included_modules
|
434
|
+
inspect
|
435
|
+
instance_method
|
436
|
+
instance_methods
|
437
|
+
method_defined?
|
438
|
+
name
|
439
|
+
private_instance_methods
|
440
|
+
private_method_defined?
|
441
|
+
protected_instance_methods
|
442
|
+
protected_method_defined?
|
443
|
+
public_instance_method
|
444
|
+
public_instance_methods
|
445
|
+
public_method_defined?
|
446
|
+
singleton_class?
|
447
|
+
to_s
|
448
|
+
]
|
449
|
+
).freeze,
|
450
|
+
Mutex => hashify(%I[locked? owned?]).freeze,
|
451
|
+
NameError => hashify(%I[initialize]).freeze,
|
452
|
+
NoMethodError => hashify(%I[initialize]).freeze,
|
453
|
+
RangeError => hashify(%I[initialize]).freeze,
|
454
|
+
RegexpError => hashify(%I[initialize]).freeze,
|
455
|
+
RuntimeError => hashify(%I[initialize]).freeze,
|
456
|
+
String => hashify(
|
457
|
+
%I[
|
458
|
+
initialize
|
459
|
+
%
|
460
|
+
*
|
461
|
+
+
|
462
|
+
+@
|
463
|
+
-@
|
464
|
+
<=>
|
465
|
+
==
|
466
|
+
===
|
467
|
+
=~
|
468
|
+
[]
|
469
|
+
ascii_only?
|
470
|
+
b
|
471
|
+
bytes
|
472
|
+
bytesize
|
473
|
+
byteslice
|
474
|
+
capitalize
|
475
|
+
casecmp
|
476
|
+
casecmp?
|
477
|
+
center
|
478
|
+
chars
|
479
|
+
chomp
|
480
|
+
chop
|
481
|
+
chr
|
482
|
+
codepoints
|
483
|
+
count
|
484
|
+
crypt
|
485
|
+
delete
|
486
|
+
downcase
|
487
|
+
dump
|
488
|
+
each_byte
|
489
|
+
each_char
|
490
|
+
each_codepoint
|
491
|
+
each_line
|
492
|
+
empty?
|
493
|
+
encoding
|
494
|
+
end_with?
|
495
|
+
eql?
|
496
|
+
getbyte
|
497
|
+
gsub
|
498
|
+
hash
|
499
|
+
hex
|
500
|
+
include?
|
501
|
+
index
|
502
|
+
inspect
|
503
|
+
intern
|
504
|
+
length
|
505
|
+
lines
|
506
|
+
ljust
|
507
|
+
lstrip
|
508
|
+
match
|
509
|
+
match?
|
510
|
+
next
|
511
|
+
oct
|
512
|
+
ord
|
513
|
+
partition
|
514
|
+
reverse
|
515
|
+
rindex
|
516
|
+
rjust
|
517
|
+
rpartition
|
518
|
+
rstrip
|
519
|
+
scan
|
520
|
+
scrub
|
521
|
+
size
|
522
|
+
slice
|
523
|
+
split
|
524
|
+
squeeze
|
525
|
+
start_with?
|
526
|
+
strip
|
527
|
+
sub
|
528
|
+
succ
|
529
|
+
sum
|
530
|
+
swapcase
|
531
|
+
to_c
|
532
|
+
to_f
|
533
|
+
to_i
|
534
|
+
to_r
|
535
|
+
to_s
|
536
|
+
to_str
|
537
|
+
to_sym
|
538
|
+
tr
|
539
|
+
tr_s
|
540
|
+
unpack
|
541
|
+
unpack1
|
542
|
+
upcase
|
543
|
+
upto
|
544
|
+
valid_encoding?
|
545
|
+
]
|
546
|
+
).freeze,
|
547
|
+
ThreadGroup => hashify(%I[enclosed? list]).freeze,
|
548
|
+
Thread => hashify(
|
549
|
+
%I[
|
550
|
+
[]
|
551
|
+
abort_on_exception
|
552
|
+
alive?
|
553
|
+
backtrace
|
554
|
+
backtrace_locations
|
555
|
+
group
|
556
|
+
inspect
|
557
|
+
key?
|
558
|
+
keys
|
559
|
+
name
|
560
|
+
pending_interrupt?
|
561
|
+
priority
|
562
|
+
report_on_exception
|
563
|
+
safe_level
|
564
|
+
status
|
565
|
+
stop?
|
566
|
+
thread_variable?
|
567
|
+
thread_variable_get
|
568
|
+
thread_variables
|
569
|
+
]
|
570
|
+
).freeze,
|
571
|
+
Time => hashify(
|
572
|
+
%I[
|
573
|
+
initialize
|
574
|
+
+
|
575
|
+
-
|
576
|
+
<=>
|
577
|
+
asctime
|
578
|
+
ctime
|
579
|
+
day
|
580
|
+
dst?
|
581
|
+
eql?
|
582
|
+
friday?
|
583
|
+
getgm
|
584
|
+
getlocal
|
585
|
+
getuc
|
586
|
+
gmt
|
587
|
+
gmt_offset
|
588
|
+
gmtoff
|
589
|
+
hash
|
590
|
+
hour
|
591
|
+
inspect
|
592
|
+
isdst
|
593
|
+
mday
|
594
|
+
min
|
595
|
+
mon
|
596
|
+
month
|
597
|
+
monday?
|
598
|
+
month
|
599
|
+
nsec
|
600
|
+
round
|
601
|
+
saturday?
|
602
|
+
sec
|
603
|
+
strftime
|
604
|
+
subsec
|
605
|
+
succ
|
606
|
+
sunday?
|
607
|
+
thursday?
|
608
|
+
to_a
|
609
|
+
to_f
|
610
|
+
to_i
|
611
|
+
to_r
|
612
|
+
to_s
|
613
|
+
tuesday?
|
614
|
+
tv_nsec
|
615
|
+
tv_sec
|
616
|
+
tv_usec
|
617
|
+
usec
|
618
|
+
utc?
|
619
|
+
utc_offset
|
620
|
+
wday
|
621
|
+
wednesday?
|
622
|
+
yday
|
623
|
+
year
|
624
|
+
zone
|
625
|
+
]
|
626
|
+
).freeze,
|
627
|
+
TypeError => hashify(%I[initialize]).freeze,
|
628
|
+
UnboundMethod => hashify(
|
629
|
+
%I[
|
630
|
+
==
|
631
|
+
arity
|
632
|
+
clone
|
633
|
+
eql?
|
634
|
+
hash
|
635
|
+
inspect
|
636
|
+
name
|
637
|
+
original_name
|
638
|
+
owner
|
639
|
+
parameters
|
640
|
+
source_location
|
641
|
+
super_method
|
642
|
+
to_s
|
643
|
+
]
|
644
|
+
).freeze,
|
645
|
+
ZeroDivisionError => hashify(%I[initialize]).freeze,
|
705
646
|
# Modules
|
706
|
-
Kernel => hashify(
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
647
|
+
Kernel => hashify(
|
648
|
+
%I[
|
649
|
+
Array
|
650
|
+
Complex
|
651
|
+
Float
|
652
|
+
Hash
|
653
|
+
Integer
|
654
|
+
Rational
|
655
|
+
String
|
656
|
+
__callee__
|
657
|
+
__dir__
|
658
|
+
__method__
|
659
|
+
autoload?
|
660
|
+
block_given?
|
661
|
+
caller
|
662
|
+
caller_locations
|
663
|
+
catch
|
664
|
+
format
|
665
|
+
global_variables
|
666
|
+
iterator?
|
667
|
+
lambda
|
668
|
+
local_variables
|
669
|
+
loop
|
670
|
+
method
|
671
|
+
methods
|
672
|
+
proc
|
673
|
+
rand
|
674
|
+
!~
|
675
|
+
<=>
|
676
|
+
===
|
677
|
+
=~
|
678
|
+
class
|
679
|
+
clone
|
680
|
+
dup
|
681
|
+
enum_for
|
682
|
+
eql?
|
683
|
+
frozen?
|
684
|
+
hash
|
685
|
+
inspect
|
686
|
+
instance_of?
|
687
|
+
instance_variable_defined?
|
688
|
+
instance_variable_get
|
689
|
+
instance_variables
|
690
|
+
is_a?
|
691
|
+
itself
|
692
|
+
kind_of?
|
693
|
+
nil?
|
694
|
+
object_id
|
695
|
+
private_methods
|
696
|
+
protected_methods
|
697
|
+
public_method
|
698
|
+
public_methods
|
699
|
+
public_send
|
700
|
+
respond_to?
|
701
|
+
respond_to_missing?
|
702
|
+
__send__
|
703
|
+
send
|
704
|
+
singleton_class
|
705
|
+
singleton_method
|
706
|
+
singleton_methods
|
707
|
+
tainted?
|
708
|
+
tap
|
709
|
+
to_enum
|
710
|
+
to_s
|
711
|
+
untrusted?
|
712
|
+
]
|
713
|
+
).freeze
|
714
|
+
}.freeze
|
715
|
+
|
716
|
+
##
|
717
|
+
# @private List of Ruby class methods that the evaluator allows
|
718
|
+
# during expression evaluation
|
719
|
+
RUBY_CLASS_METHOD_WHITELIST = {
|
720
|
+
# Classes
|
721
|
+
Debugger => hashify(%I[allow_mutating_methods!]).freeze
|
722
|
+
}.freeze
|
723
|
+
|
724
|
+
##
|
725
|
+
# @private List of Ruby instance methods that the evaluator allows
|
726
|
+
# during expression evaluation
|
727
|
+
RUBY_INSTANCE_METHOD_WHITELIST = {
|
728
|
+
Evaluator => hashify(%I[allow_mutating_methods!]).freeze
|
771
729
|
}.freeze
|
772
730
|
|
773
731
|
PROHIBITED_OPERATION_MSG = "Prohibited operation detected".freeze
|
@@ -775,230 +733,329 @@ module Google
|
|
775
733
|
COMPILATION_FAIL_MSG = "Unable to compile expression".freeze
|
776
734
|
LONG_EVAL_MSG = "Evaluation exceeded time limit".freeze
|
777
735
|
|
778
|
-
|
736
|
+
EVALUATOR_REFERENCE = :__evaluator__
|
779
737
|
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
738
|
+
##
|
739
|
+
# @private
|
740
|
+
# Read-only evaluates a single expression in a given
|
741
|
+
# context binding. Handles any exceptions raised.
|
742
|
+
#
|
743
|
+
# @param [Binding] binding The binding object from the context
|
744
|
+
# @param [String] expression A string of code to be evaluated
|
745
|
+
#
|
746
|
+
# @return [Object] The result Ruby object from evaluating the
|
747
|
+
# expression. If the expression is blocked from mutating
|
748
|
+
# the state of program. A
|
749
|
+
# {Google::Cloud::Debugger::MutationError} will be returned.
|
750
|
+
#
|
751
|
+
def self.readonly_eval_expression binding, expression
|
752
|
+
new.readonly_eval_expression binding, expression
|
753
|
+
end
|
796
754
|
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
755
|
+
##
|
756
|
+
# @private
|
757
|
+
# Returns the evaluator currently running, or nil if an evaluation
|
758
|
+
# is not currently running.
|
759
|
+
#
|
760
|
+
# @return [Evaluator, nil]
|
761
|
+
#
|
762
|
+
def self.current
|
763
|
+
Thread.current.thread_variable_get EVALUATOR_REFERENCE
|
764
|
+
end
|
801
765
|
|
802
|
-
|
766
|
+
##
|
767
|
+
# Create a new Evaluator.
|
768
|
+
# @private
|
769
|
+
#
|
770
|
+
# @param [boolean, nil] allow_mutating_methods whether to allow
|
771
|
+
# calling of potentially mutating methods, or nil to default to
|
772
|
+
# the current configuration setting.
|
773
|
+
# @param [Numeric, nil] time_limit the time limit in seconds, or nil
|
774
|
+
# to default to the current configuration setting.
|
775
|
+
#
|
776
|
+
def initialize allow_mutating_methods: nil, time_limit: nil
|
777
|
+
@allow_mutating_methods =
|
778
|
+
if allow_mutating_methods.nil?
|
779
|
+
Debugger.configure.allow_mutating_methods
|
780
|
+
else
|
781
|
+
allow_mutating_methods
|
782
|
+
end
|
783
|
+
@time_limit = time_limit ||
|
784
|
+
Debugger.configure.evaluation_time_limit
|
785
|
+
end
|
803
786
|
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
# where addtional nested tracing is disabled by VM. So we need to
|
820
|
-
# do evaluation in a new thread, where function calls can be
|
821
|
-
# traced.
|
822
|
-
thr = Thread.new do
|
823
|
-
begin
|
824
|
-
binding.eval wrap_expression(expression)
|
825
|
-
rescue => e
|
826
|
-
# Treat all StandardError as mutation and set @mutation_cause
|
827
|
-
unless e.instance_variable_get :@mutation_cause
|
828
|
-
e.instance_variable_set(
|
829
|
-
:@mutation_cause,
|
830
|
-
Google::Cloud::Debugger::EvaluationError::UNKNOWN_CAUSE)
|
831
|
-
end
|
787
|
+
##
|
788
|
+
# Allow calling of mutating methods even if mutation detection is
|
789
|
+
# configured to be active. This may be called only during debugger
|
790
|
+
# condition or expression evaluation.
|
791
|
+
#
|
792
|
+
# If you pass in a block, it will be evaluated with mutation
|
793
|
+
# detection disabled, and the original setting will be restored
|
794
|
+
# afterward. If you do not pass a block, this evaluator will
|
795
|
+
# permanently allow mutating methods.
|
796
|
+
# @private
|
797
|
+
#
|
798
|
+
def allow_mutating_methods!
|
799
|
+
old = @allow_mutating_methods
|
800
|
+
@allow_mutating_methods = true
|
801
|
+
return unless block_given?
|
832
802
|
|
833
|
-
|
834
|
-
|
835
|
-
|
803
|
+
result = yield
|
804
|
+
@allow_mutating_methods = old
|
805
|
+
result
|
806
|
+
end
|
836
807
|
|
837
|
-
|
808
|
+
##
|
809
|
+
# Read-only evaluates a single expression in a given
|
810
|
+
# context binding. Handles any exceptions raised.
|
811
|
+
# @private
|
812
|
+
#
|
813
|
+
# @param [Binding] binding The binding object from the context
|
814
|
+
# @param [String] expression A string of code to be evaluates
|
815
|
+
#
|
816
|
+
# @return [Object] The result Ruby object from evaluating the
|
817
|
+
# expression. If the expression is blocked from mutating
|
818
|
+
# the state of program. A
|
819
|
+
# {Google::Cloud::Debugger::MutationError} will be returned.
|
820
|
+
#
|
821
|
+
def readonly_eval_expression binding, expression
|
822
|
+
compilation_result = validate_compiled_expression expression
|
823
|
+
return compilation_result if compilation_result.is_a?(Exception)
|
838
824
|
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
825
|
+
readonly_eval_expression_exec binding, expression
|
826
|
+
rescue StandardError => e
|
827
|
+
"Unable to evaluate expression: #{e.message}"
|
828
|
+
end
|
843
829
|
|
844
|
-
|
845
|
-
else
|
846
|
-
thr.value
|
847
|
-
end
|
848
|
-
end
|
830
|
+
private
|
849
831
|
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
832
|
+
##
|
833
|
+
# @private Actually read-only evaluates an expression in a given
|
834
|
+
# context binding. The evaluation is done in a separate thread due
|
835
|
+
# to this method may be run from Ruby Trace call back, where
|
836
|
+
# addtional code tracing is disabled in original thread.
|
837
|
+
#
|
838
|
+
# @param [Binding] binding The binding object from the context
|
839
|
+
# @param [String] expression A string of code to be evaluates
|
840
|
+
#
|
841
|
+
# @return [Object] The result Ruby object from evaluating the
|
842
|
+
# expression. It returns Google::Cloud::Debugger::MutationError
|
843
|
+
# if a mutation is caught.
|
844
|
+
#
|
845
|
+
def readonly_eval_expression_exec binding, expression
|
846
|
+
# The evaluation is most likely triggered from a trace callback,
|
847
|
+
# where addtional nested tracing is disabled by VM. So we need to
|
848
|
+
# do evaluation in a new thread, where function calls can be
|
849
|
+
# traced.
|
850
|
+
thr = Thread.new do
|
862
851
|
begin
|
863
|
-
|
864
|
-
|
865
|
-
rescue
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
852
|
+
Thread.current.thread_variable_set EVALUATOR_REFERENCE, self
|
853
|
+
binding.eval wrap_expression(expression)
|
854
|
+
rescue StandardError, EvaluationError => e
|
855
|
+
# Treat all StandardError as mutation and set @mutation_cause
|
856
|
+
unless e.instance_variable_get :@mutation_cause
|
857
|
+
e.instance_variable_set(
|
858
|
+
:@mutation_cause,
|
859
|
+
Google::Cloud::Debugger::EvaluationError::UNKNOWN_CAUSE
|
860
|
+
)
|
861
|
+
end
|
871
862
|
|
872
|
-
|
873
|
-
return Google::Cloud::Debugger::MutationError.new(
|
874
|
-
MUTATION_DETECTED_MSG,
|
875
|
-
Google::Cloud::Debugger::EvaluationError::PROHIBITED_YARV
|
876
|
-
)
|
863
|
+
e
|
877
864
|
end
|
878
|
-
|
879
|
-
yarv_instructions
|
880
865
|
end
|
881
866
|
|
882
|
-
|
883
|
-
# @private Helps checking if a given set of YARV instructions
|
884
|
-
# contains any prohibited bytecode or instructions.
|
885
|
-
#
|
886
|
-
# @param [String] yarv_instructions Compiled YARV instructions
|
887
|
-
# string
|
888
|
-
# @param [Boolean] allow_localops Whether allows local variable
|
889
|
-
# write operations
|
890
|
-
#
|
891
|
-
# @return [Boolean] True if the YARV instructions don't contain any
|
892
|
-
# prohibited operations. Otherwise false.
|
893
|
-
#
|
894
|
-
def immutable_yarv_instructions? yarv_instructions,
|
895
|
-
allow_localops: false
|
896
|
-
if allow_localops
|
897
|
-
byte_code_blacklist_regex = BYTE_CODE_BLACKLIST_REGEX
|
898
|
-
else
|
899
|
-
byte_code_blacklist_regex = FULL_BYTE_CODE_BLACKLIST_REGEX
|
900
|
-
end
|
867
|
+
thr.join @time_limit
|
901
868
|
|
902
|
-
|
869
|
+
# Force terminate evaluation thread if not finished already and
|
870
|
+
# return an Exception
|
871
|
+
if thr.alive?
|
872
|
+
thr.kill
|
903
873
|
|
904
|
-
|
874
|
+
Google::Cloud::Debugger::EvaluationError.new LONG_EVAL_MSG
|
875
|
+
else
|
876
|
+
thr.value
|
877
|
+
end
|
878
|
+
end
|
905
879
|
|
906
|
-
|
907
|
-
|
908
|
-
|
880
|
+
##
|
881
|
+
# @private Compile the expression into YARV instructions. Return
|
882
|
+
# Google::Cloud::Debugger::MutationError if any prohibited YARV
|
883
|
+
# instructions are found.
|
884
|
+
#
|
885
|
+
# @param [String] expression String of code expression
|
886
|
+
#
|
887
|
+
# @return [String,Google::Cloud::Debugger::MutationError] It returns
|
888
|
+
# the compile YARV instructions if no prohibited bytecodes are
|
889
|
+
# found. Otherwise return Google::Cloud::Debugger::MutationError.
|
890
|
+
#
|
891
|
+
def validate_compiled_expression expression
|
892
|
+
begin
|
893
|
+
yarv_instructions =
|
894
|
+
RubyVM::InstructionSequence.compile(expression).disasm
|
895
|
+
rescue ScriptError
|
896
|
+
return Google::Cloud::Debugger::MutationError.new(
|
897
|
+
COMPILATION_FAIL_MSG,
|
898
|
+
Google::Cloud::Debugger::EvaluationError::PROHIBITED_YARV
|
899
|
+
)
|
909
900
|
end
|
910
901
|
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
Google::Cloud::Debugger::Breakpoint::Evaluator.send(
|
917
|
-
:enable_method_trace_for_thread)
|
918
|
-
#{expression}
|
919
|
-
ensure
|
920
|
-
Google::Cloud::Debugger::Breakpoint::Evaluator.send(
|
921
|
-
:disable_method_trace_for_thread)
|
922
|
-
end
|
923
|
-
"""
|
902
|
+
unless immutable_yarv_instructions? yarv_instructions
|
903
|
+
return Google::Cloud::Debugger::MutationError.new(
|
904
|
+
MUTATION_DETECTED_MSG,
|
905
|
+
Google::Cloud::Debugger::EvaluationError::PROHIBITED_YARV
|
906
|
+
)
|
924
907
|
end
|
925
908
|
|
926
|
-
|
927
|
-
|
928
|
-
# everytime a Ruby function is called during evaluation of
|
929
|
-
# an expression.
|
930
|
-
#
|
931
|
-
# @param [Object] receiver The receiver of the function being called
|
932
|
-
# @param [Symbol] mid The method name
|
933
|
-
#
|
934
|
-
# @return [NilClass] Nil if no prohibited operations are found.
|
935
|
-
# Otherwise raise Google::Cloud::Debugger::MutationError error.
|
936
|
-
#
|
937
|
-
def trace_func_callback receiver, mid
|
938
|
-
meth = nil
|
939
|
-
begin
|
940
|
-
meth = receiver.method mid
|
941
|
-
rescue
|
942
|
-
raise Google::Cloud::Debugger::EvaluationError.new(
|
943
|
-
PROHIBITED_OPERATION_MSG,
|
944
|
-
Google::Cloud::Debugger::EvaluationError::META_PROGRAMMING)
|
945
|
-
end
|
909
|
+
yarv_instructions
|
910
|
+
end
|
946
911
|
|
947
|
-
|
912
|
+
##
|
913
|
+
# @private Helps checking if a given set of YARV instructions
|
914
|
+
# contains any prohibited bytecode or instructions.
|
915
|
+
#
|
916
|
+
# @param [String] yarv_instructions Compiled YARV instructions
|
917
|
+
# string
|
918
|
+
# @param [Boolean] allow_localops Whether allows local variable
|
919
|
+
# write operations
|
920
|
+
#
|
921
|
+
# @return [Boolean] True if the YARV instructions don't contain any
|
922
|
+
# prohibited operations. Otherwise false.
|
923
|
+
#
|
924
|
+
def immutable_yarv_instructions? yarv_instructions,
|
925
|
+
allow_localops: false
|
926
|
+
byte_code_blacklist_regex = if allow_localops
|
927
|
+
BYTE_CODE_BLACKLIST_REGEX
|
928
|
+
else
|
929
|
+
FULL_BYTE_CODE_BLACKLIST_REGEX
|
930
|
+
end
|
948
931
|
|
949
|
-
|
950
|
-
allow_localops: true)
|
951
|
-
fail Google::Cloud::Debugger::MutationError.new(
|
952
|
-
MUTATION_DETECTED_MSG,
|
953
|
-
Google::Cloud::Debugger::EvaluationError::PROHIBITED_YARV)
|
954
|
-
end
|
932
|
+
func_call_flag_blacklist_regex = FUNC_CALL_FLAG_BLACKLIST_REGEX
|
955
933
|
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
invalid_op = !validate_c_instance_method(defined_class, mid)
|
934
|
+
catch_table_type_blacklist_regex = CATCH_TABLE_BLACKLIST_REGEX
|
935
|
+
|
936
|
+
!(yarv_instructions.match(func_call_flag_blacklist_regex) ||
|
937
|
+
yarv_instructions.match(byte_code_blacklist_regex) ||
|
938
|
+
yarv_instructions.match(catch_table_type_blacklist_regex))
|
939
|
+
end
|
940
|
+
|
941
|
+
##
|
942
|
+
# @private Wraps expression with tracing code
|
943
|
+
def wrap_expression expression
|
944
|
+
"""
|
945
|
+
begin
|
946
|
+
::Google::Cloud::Debugger::Breakpoint::Evaluator.send(
|
947
|
+
:enable_method_trace_for_thread)
|
948
|
+
#{expression}
|
949
|
+
ensure
|
950
|
+
::Google::Cloud::Debugger::Breakpoint::Evaluator.send(
|
951
|
+
:disable_method_trace_for_thread)
|
975
952
|
end
|
953
|
+
"""
|
954
|
+
end
|
976
955
|
|
977
|
-
|
956
|
+
##
|
957
|
+
# @private Evaluation tracing callback function. This is called
|
958
|
+
# everytime a Ruby function is called during evaluation of
|
959
|
+
# an expression.
|
960
|
+
#
|
961
|
+
# @param [Object] receiver The receiver of the function being called
|
962
|
+
# @param [Symbol] mid The method name
|
963
|
+
#
|
964
|
+
# @return [NilClass] Nil if no prohibited operations are found.
|
965
|
+
# Otherwise raise Google::Cloud::Debugger::MutationError error.
|
966
|
+
#
|
967
|
+
def trace_func_callback receiver, defined_class, mid
|
968
|
+
return if @allow_mutating_methods
|
969
|
+
if receiver.is_a?(Class) || receiver.is_a?(Module)
|
970
|
+
if whitelisted_ruby_class_method? defined_class, receiver, mid
|
971
|
+
return
|
972
|
+
end
|
973
|
+
elsif whitelisted_ruby_instance_method? defined_class, mid
|
974
|
+
return
|
975
|
+
end
|
978
976
|
|
979
|
-
|
980
|
-
|
981
|
-
|
977
|
+
yarv_instructions = begin
|
978
|
+
RubyVM::InstructionSequence.disasm receiver.method mid
|
979
|
+
rescue StandardError
|
980
|
+
raise Google::Cloud::Debugger::EvaluationError.new(
|
982
981
|
PROHIBITED_OPERATION_MSG,
|
983
|
-
Google::Cloud::Debugger::EvaluationError::
|
982
|
+
Google::Cloud::Debugger::EvaluationError::META_PROGRAMMING
|
983
|
+
)
|
984
984
|
end
|
985
985
|
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
end
|
986
|
+
return if immutable_yarv_instructions?(yarv_instructions,
|
987
|
+
allow_localops: true)
|
988
|
+
raise Google::Cloud::Debugger::MutationError.new(
|
989
|
+
MUTATION_DETECTED_MSG,
|
990
|
+
Google::Cloud::Debugger::EvaluationError::PROHIBITED_YARV
|
991
|
+
)
|
992
|
+
end
|
994
993
|
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
994
|
+
##
|
995
|
+
# @private Evaluation tracing callback function. This is called
|
996
|
+
# everytime a C function is called during evaluation of
|
997
|
+
# an expression.
|
998
|
+
#
|
999
|
+
# @param [Object] receiver The receiver of the function being called
|
1000
|
+
# @param [Class] defined_class The Class of where the function is
|
1001
|
+
# defined
|
1002
|
+
# @param [Symbol] mid The method name
|
1003
|
+
#
|
1004
|
+
# @return [NilClass] Nil if no prohibited operations are found.
|
1005
|
+
# Otherwise raise Google::Cloud::Debugger::MutationError error.
|
1006
|
+
#
|
1007
|
+
def trace_c_func_callback receiver, defined_class, mid
|
1008
|
+
return if @allow_mutating_methods
|
1009
|
+
if receiver.is_a?(Class) || receiver.is_a?(Module)
|
1010
|
+
invalid_op =
|
1011
|
+
!validate_c_class_method(defined_class, receiver, mid)
|
1012
|
+
else
|
1013
|
+
invalid_op = !validate_c_instance_method(defined_class, mid)
|
1001
1014
|
end
|
1015
|
+
|
1016
|
+
return unless invalid_op
|
1017
|
+
|
1018
|
+
Google::Cloud::Debugger::Breakpoint::Evaluator.send(
|
1019
|
+
:disable_method_trace_for_thread
|
1020
|
+
)
|
1021
|
+
raise Google::Cloud::Debugger::MutationError.new(
|
1022
|
+
PROHIBITED_OPERATION_MSG,
|
1023
|
+
Google::Cloud::Debugger::EvaluationError::PROHIBITED_C_FUNC
|
1024
|
+
)
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
##
|
1028
|
+
# @private Helper method to verify whether a C level class method
|
1029
|
+
# is allowed or not.
|
1030
|
+
def validate_c_class_method klass, receiver, mid
|
1031
|
+
IMMUTABLE_CLASSES.include?(receiver) ||
|
1032
|
+
(C_CLASS_METHOD_WHITELIST[receiver] || {})[mid] ||
|
1033
|
+
(C_INSTANCE_METHOD_WHITELIST[klass] || {})[mid]
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
##
|
1037
|
+
# @private Helper method to verify whether a C level instance method
|
1038
|
+
# is allowed or not.
|
1039
|
+
def validate_c_instance_method klass, mid
|
1040
|
+
IMMUTABLE_CLASSES.include?(klass) ||
|
1041
|
+
(C_INSTANCE_METHOD_WHITELIST[klass] || {})[mid]
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
##
|
1045
|
+
# @private Helper method to verify whether a ruby class method
|
1046
|
+
# is allowed or not.
|
1047
|
+
def whitelisted_ruby_class_method? klass, receiver, mid
|
1048
|
+
IMMUTABLE_CLASSES.include?(klass) ||
|
1049
|
+
(RUBY_CLASS_METHOD_WHITELIST[receiver] || {})[mid] ||
|
1050
|
+
(RUBY_INSTANCE_METHOD_WHITELIST[klass] || {})[mid]
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
##
|
1054
|
+
# @private Helper method to verify whether a ruby instance method
|
1055
|
+
# is allowed or not.
|
1056
|
+
def whitelisted_ruby_instance_method? klass, mid
|
1057
|
+
IMMUTABLE_CLASSES.include?(klass) ||
|
1058
|
+
(RUBY_INSTANCE_METHOD_WHITELIST[klass] || {})[mid]
|
1002
1059
|
end
|
1003
1060
|
end
|
1004
1061
|
end
|
@@ -1006,7 +1063,7 @@ module Google
|
|
1006
1063
|
##
|
1007
1064
|
# @private Custom error type used to identify evaluation error during
|
1008
1065
|
# breakpoint expression evaluation.
|
1009
|
-
class EvaluationError <
|
1066
|
+
class EvaluationError < Exception
|
1010
1067
|
UNKNOWN_CAUSE = :unknown_cause
|
1011
1068
|
PROHIBITED_YARV = :prohibited_yarv
|
1012
1069
|
PROHIBITED_C_FUNC = :prohibited_c_func
|