rallhook 0.7.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.
Files changed (50) hide show
  1. data/AUTHORS +3 -0
  2. data/CHANGELOG +82 -0
  3. data/README +207 -0
  4. data/Rakefile +49 -0
  5. data/TODO +8 -0
  6. data/examples/hook/example1.rb +19 -0
  7. data/examples/hook/example2.rb +30 -0
  8. data/examples/hook/example3.rb +24 -0
  9. data/examples/hook/example4.rb +18 -0
  10. data/examples/hook/intercept.rb +41 -0
  11. data/examples/hook/intercept2.rb +49 -0
  12. data/examples/hook/redirect.rb +55 -0
  13. data/examples/hook/redirect_inherited.rb +28 -0
  14. data/examples/hook/shadow.rb +44 -0
  15. data/examples/instrospection/main.rb +13 -0
  16. data/examples/instrospection/source1.rb +4 -0
  17. data/examples/instrospection/source2.rb +4 -0
  18. data/ext/rallhook_base/distorm.h +401 -0
  19. data/ext/rallhook_base/extconf.rb +21 -0
  20. data/ext/rallhook_base/hook.c +165 -0
  21. data/ext/rallhook_base/hook.h +30 -0
  22. data/ext/rallhook_base/hook_rb_call.c +88 -0
  23. data/ext/rallhook_base/hook_rb_call.h +33 -0
  24. data/ext/rallhook_base/method_node.c +212 -0
  25. data/ext/rallhook_base/method_node.h +27 -0
  26. data/ext/rallhook_base/node_defs.h +294 -0
  27. data/ext/rallhook_base/rallhook.c +396 -0
  28. data/ext/rallhook_base/rb_call_fake.c +398 -0
  29. data/ext/rallhook_base/rb_call_fake.h +138 -0
  30. data/ext/rallhook_base/restrict_def.c +176 -0
  31. data/ext/rallhook_base/restrict_def.h +37 -0
  32. data/ext/rallhook_base/ruby_redirect.c +122 -0
  33. data/ext/rallhook_base/ruby_redirect.h +33 -0
  34. data/ext/rallhook_base/ruby_symbols.c +43 -0
  35. data/ext/rallhook_base/ruby_symbols.h +28 -0
  36. data/ext/rallhook_base/ruby_version.h +21 -0
  37. data/lib/rallhook/thread_hook.rb +37 -0
  38. data/lib/rallhook.rb +384 -0
  39. data/test/basic_proc.rb +45 -0
  40. data/test/integrity/test_array.rb +42 -0
  41. data/test/integrity/test_binding.rb +26 -0
  42. data/test/integrity/test_block.rb +37 -0
  43. data/test/integrity/test_call.rb +1 -0
  44. data/test/integrity/test_class_methods.rb +1 -0
  45. data/test/integrity/test_exception.rb +1 -0
  46. data/test/integrity/test_super.rb +34 -0
  47. data/test/introspection/test_call.rb +29 -0
  48. data/test/introspection/test_class_method.rb +41 -0
  49. data/test/introspection/test_file.rb +15 -0
  50. metadata +113 -0
@@ -0,0 +1,398 @@
1
+ /*
2
+
3
+ This file is part of the rallhook project, http://github.com/tario/rallhook
4
+
5
+ Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
6
+
7
+ rallhook is free software: you can redistribute it and/or modify
8
+ it under the terms of the gnu general public license as published by
9
+ the free software foundation, either version 3 of the license, or
10
+ (at your option) any later version.
11
+
12
+ rallhook is distributed in the hope that it will be useful,
13
+ but without any warranty; without even the implied warranty of
14
+ merchantability or fitness for a particular purpose. see the
15
+ gnu general public license for more details.
16
+
17
+ you should have received a copy of the gnu general public license
18
+ along with rallhook. if not, see <http://www.gnu.org/licenses/>.
19
+
20
+ */
21
+
22
+ #include <ruby.h>
23
+
24
+ #ifdef RUBY1_8
25
+ #include <node.h>
26
+ #include <env.h> // from ruby
27
+ #endif
28
+
29
+ #include <dlfcn.h>
30
+ #include <stdarg.h>
31
+ #include "ruby_symbols.h"
32
+ #include "rb_call_fake.h"
33
+ #include "ruby_redirect.h"
34
+
35
+ void* rb_call_copy;
36
+
37
+ extern REDIRECTHANDLER current_redirect_handler;
38
+
39
+ #ifdef __i386__
40
+
41
+ VALUE read_eax( ) {
42
+ }
43
+
44
+ VALUE read_edx( ) {
45
+ __asm__("mov %edx, %eax");
46
+ }
47
+
48
+ VALUE read_ecx( ) {
49
+ __asm__("mov %ecx, %eax");
50
+ }
51
+
52
+ int rb_call_write_eax(int value) {
53
+ return value;
54
+ }
55
+
56
+ int is_fastcall = 1;
57
+ int is_calibrate = 0;
58
+ int vm_is_fastcall = 1;
59
+ int vm_is_calibrate = 0;
60
+ VALUE calibrate_klass;
61
+ VALUE calibrate_recv;
62
+ ID calibrate_mid;
63
+
64
+ #endif
65
+
66
+ #ifdef RUBY1_9
67
+
68
+ VMCALLMETHOD vm_call_method_copy;
69
+
70
+ typedef void rb_vm_t_;
71
+ #endif
72
+
73
+ VALUE rb_call_copy_i(
74
+ VALUE klass, VALUE recv,
75
+ ID mid,
76
+ int argc, /* OK */
77
+ const VALUE *argv, /* OK */
78
+ int scope,
79
+ VALUE self
80
+ ) {
81
+ #ifdef __i386__
82
+ if (is_fastcall == 1) {
83
+
84
+ int array[7] = { (int)klass, (int)recv, mid, argc, (int)argv, scope, (int)self };
85
+ rb_call_write_eax(array);
86
+
87
+ __asm__("push %ebp\n"); // save all registers
88
+ __asm__("push %esi\n");
89
+ __asm__("push %edi\n");
90
+ __asm__("push %ebx\n");
91
+ __asm__("push %edx\n");
92
+ __asm__("push %ecx\n");
93
+ __asm__("mov 0x4(%eax), %edx\n");
94
+ __asm__("mov 0x8(%eax), %ecx\n");
95
+ __asm__("push 0x18(%eax)\n");
96
+ __asm__("push 0x14(%eax)\n");
97
+ __asm__("push 0x10(%eax)\n");
98
+ __asm__("push 0x0c(%eax)\n");
99
+ __asm__("mov (%eax), %eax\n");
100
+ __asm__("call *rb_call_copy\n");
101
+ __asm__("add $0x10, %esp\n");
102
+ __asm__("pop %ecx\n");
103
+ __asm__("pop %edx\n");
104
+ __asm__("pop %ebx\n");
105
+ __asm__("pop %edi\n");
106
+ __asm__("pop %esi\n");
107
+ __asm__("pop %ebp\n");
108
+ return read_eax();
109
+
110
+ } else if ( is_fastcall == 2) {
111
+ int array[7] = { (int)klass, (int)recv, mid, argc, (int)argv, scope, (int)self };
112
+ rb_call_write_eax(array);
113
+
114
+ __asm__("push %ebp\n"); // save all registers
115
+ __asm__("push %esi\n");
116
+ __asm__("push %edi\n");
117
+ __asm__("push %ebx\n");
118
+ __asm__("push %edx\n");
119
+ __asm__("push %ecx\n");
120
+ __asm__("mov 0x4(%eax), %edx\n");
121
+ __asm__("push 0x18(%eax)\n");
122
+ __asm__("push 0x14(%eax)\n");
123
+ __asm__("push 0x10(%eax)\n");
124
+ __asm__("push 0x0c(%eax)\n");
125
+ __asm__("push 0x08(%eax)\n");
126
+ __asm__("mov (%eax), %eax\n");
127
+ __asm__("call *rb_call_copy\n");
128
+ __asm__("add $0x14, %esp\n");
129
+ __asm__("pop %ecx\n");
130
+ __asm__("pop %edx\n");
131
+ __asm__("pop %ebx\n");
132
+ __asm__("pop %edi\n");
133
+ __asm__("pop %esi\n");
134
+ __asm__("pop %ebp\n");
135
+ return read_eax();
136
+
137
+ } else {
138
+ #endif
139
+ return ((RBCALL)rb_call_copy)(klass,recv,mid,argc,argv,scope,self);
140
+ #ifdef __i386__
141
+ }
142
+ #endif
143
+
144
+ }
145
+
146
+ #ifdef RUBY1_9
147
+
148
+ VALUE
149
+ vm_call_method_i(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
150
+ const int num, rb_block_t_ * const blockptr, const VALUE flag,
151
+ const ID id, void * mn, const VALUE recv_, VALUE klass)
152
+ {
153
+
154
+ #ifdef __i386__
155
+ if (vm_is_fastcall == 1) {
156
+
157
+ int array[9] = { (int)th, (int)cfp, num, (int)blockptr, (int)flag, (int)id, (int)mn, (int)recv_, (int)klass };
158
+ rb_call_write_eax(array);
159
+
160
+ __asm__("push %ebp\n"); // save all registers
161
+ __asm__("push %esi\n");
162
+ __asm__("push %edi\n");
163
+ __asm__("push %ebx\n");
164
+ __asm__("push %edx\n");
165
+ __asm__("push %ecx\n");
166
+ __asm__("mov 0x4(%eax), %edx\n");
167
+ __asm__("mov 0x8(%eax), %ecx\n");
168
+ __asm__("push 0x20(%eax)\n");
169
+ __asm__("push 0x1c(%eax)\n");
170
+ __asm__("push 0x18(%eax)\n");
171
+ __asm__("push 0x14(%eax)\n");
172
+ __asm__("push 0x10(%eax)\n");
173
+ __asm__("push 0x0c(%eax)\n");
174
+ __asm__("mov (%eax), %eax\n");
175
+ __asm__("call *vm_call_method_copy\n");
176
+ __asm__("add $0x18, %esp\n");
177
+ __asm__("pop %ecx\n");
178
+ __asm__("pop %edx\n");
179
+ __asm__("pop %ebx\n");
180
+ __asm__("pop %edi\n");
181
+ __asm__("pop %esi\n");
182
+ __asm__("pop %ebp\n");
183
+ return read_eax();
184
+
185
+ } else if ( vm_is_fastcall == 2) {
186
+ int array[9] = { (int)th, (int)cfp, num, (int)blockptr, (int)flag, (int)id, (int)mn, (int)recv_, (int)klass };
187
+ rb_call_write_eax(array);
188
+
189
+ __asm__("push %ebp\n"); // save all registers
190
+ __asm__("push %esi\n");
191
+ __asm__("push %edi\n");
192
+ __asm__("push %ebx\n");
193
+ __asm__("push %edx\n");
194
+ __asm__("push %ecx\n");
195
+ __asm__("mov 0x4(%eax), %edx\n");
196
+ __asm__("push 0x20(%eax)\n");
197
+ __asm__("push 0x1c(%eax)\n");
198
+ __asm__("push 0x18(%eax)\n");
199
+ __asm__("push 0x14(%eax)\n");
200
+ __asm__("push 0x10(%eax)\n");
201
+ __asm__("push 0x0c(%eax)\n");
202
+ __asm__("push 0x08(%eax)\n");
203
+ __asm__("mov (%eax), %eax\n");
204
+ __asm__("call *vm_call_method_copy\n");
205
+ __asm__("add $0x1c, %esp\n");
206
+ __asm__("pop %ecx\n");
207
+ __asm__("pop %edx\n");
208
+ __asm__("pop %ebx\n");
209
+ __asm__("pop %edi\n");
210
+ __asm__("pop %esi\n");
211
+ __asm__("pop %ebp\n");
212
+ return read_eax();
213
+
214
+ } else {
215
+ #endif
216
+ return vm_call_method_copy(th,cfp,num,blockptr,flag,id,mn,recv_,klass);
217
+ #ifdef __i386__
218
+ }
219
+ #endif
220
+
221
+
222
+ }
223
+
224
+ VALUE
225
+ vm_call_method_fake(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
226
+ const int num, rb_block_t_ * const blockptr, const VALUE flag,
227
+ ID id, void * mn, VALUE recv, VALUE klass)
228
+ {
229
+ VALUE klass_copy = klass;
230
+ VALUE recv_copy = recv;
231
+ ID id_copy = id;
232
+
233
+ current_redirect_handler(&klass, &recv, &id);
234
+
235
+ if (id_copy != id || klass_copy != klass || recv_copy != recv) {
236
+ mn = rb_get_method_body(klass, id, 0);
237
+ }
238
+
239
+ return vm_call_method_i(
240
+ th,
241
+ cfp,
242
+ num,
243
+ blockptr,
244
+ flag,
245
+ id,
246
+ mn,
247
+ recv,
248
+ klass);
249
+
250
+
251
+ }
252
+
253
+ #ifdef __i386__
254
+
255
+ VALUE vm_call_method_fake_regs(
256
+ _WORD eax, _WORD edx, _WORD ecx, _WORD* esp
257
+ ) {
258
+
259
+ esp++;
260
+
261
+ if (vm_is_calibrate) {
262
+ if ((VALUE)esp[7] == calibrate_recv && (VALUE)esp[8] == calibrate_klass && (ID)esp[5] == calibrate_mid) {
263
+ vm_is_fastcall = 0;
264
+ } else if ( (VALUE)esp[5] == calibrate_recv ) {
265
+ vm_is_fastcall = 2;
266
+ } else {
267
+ vm_is_fastcall = 1;
268
+ }
269
+ vm_is_calibrate = 0;
270
+ }
271
+
272
+ if (vm_is_fastcall == 0) {
273
+ return vm_call_method_fake(
274
+ (rb_thread_t_*)esp[0],
275
+ (rb_control_frame_t_*)esp[1],
276
+ (int)esp[2],
277
+ (rb_block_t_*)esp[3],
278
+ (VALUE)esp[3],
279
+ (ID)esp[4],
280
+ (void*)esp[5],
281
+ (VALUE)esp[6],
282
+ (VALUE)esp[7]
283
+ );
284
+ } else if (vm_is_fastcall == 2 ) {
285
+ return vm_call_method_fake(
286
+ (rb_thread_t_*)eax,
287
+ (rb_control_frame_t_*)edx,
288
+ (int)esp[0],
289
+ (rb_block_t_*)esp[1],
290
+ (VALUE)esp[2],
291
+ (ID)esp[3],
292
+ (void*)esp[4],
293
+ (VALUE)esp[5],
294
+ (VALUE)esp[6]
295
+ );
296
+
297
+ } else {
298
+ return vm_call_method_fake(
299
+ (rb_thread_t_*)eax,
300
+ (rb_control_frame_t_*)edx,
301
+ (int)ecx,
302
+ (rb_block_t_*)esp[0],
303
+ (VALUE)esp[1],
304
+ (ID)esp[2],
305
+ (void*)esp[3],
306
+ (VALUE)esp[4],
307
+ (VALUE)esp[5]
308
+ );
309
+
310
+ }
311
+
312
+ }
313
+
314
+ #endif
315
+
316
+ #endif
317
+
318
+
319
+ VALUE
320
+ rb_call_fake(
321
+ VALUE klass, VALUE recv,
322
+ ID mid,
323
+ int argc, /* OK */
324
+ const VALUE *argv, /* OK */
325
+ int scope,
326
+ VALUE self
327
+ ) {
328
+
329
+ current_redirect_handler(&klass, &recv, &mid);
330
+ return rb_call_copy_i(klass,recv,mid,argc,argv,scope,self);
331
+
332
+ }
333
+
334
+
335
+ #ifdef __i386__
336
+
337
+ VALUE
338
+ rb_call_fake_regs(
339
+ _WORD eax, _WORD edx, _WORD ecx, _WORD* esp
340
+ ) {
341
+ VALUE klass;
342
+ VALUE recv;
343
+ ID mid;
344
+ int argc; /* OK */
345
+ const VALUE *argv;
346
+ int scope;
347
+ VALUE self;
348
+
349
+ esp++;
350
+
351
+
352
+ if (is_calibrate) {
353
+
354
+ if ((VALUE)edx == calibrate_recv && (VALUE)eax == calibrate_klass && (ID)ecx == calibrate_mid) {
355
+ is_fastcall = 1;
356
+ } else if ( (VALUE)edx == calibrate_recv && (VALUE)eax == calibrate_klass && (ID)esp[0] == calibrate_mid ) {
357
+ is_fastcall = 2;
358
+ } else {
359
+ is_fastcall = 0;
360
+ }
361
+ is_calibrate = 0;
362
+ return Qnil;
363
+ }
364
+
365
+ if (is_fastcall == 0) {
366
+ klass = (VALUE)esp[0];
367
+ recv = (VALUE)esp[1];
368
+ mid = (ID)esp[2];
369
+ argc = (int)esp[3];
370
+ argv = (VALUE*)esp[4];
371
+ scope = (int)esp[5];
372
+ self = (VALUE)esp[6];
373
+ } else if (is_fastcall == 2) {
374
+ klass = (VALUE)eax;
375
+ recv = (VALUE)edx;
376
+ mid = (VALUE)esp[0];
377
+ argc = (int)esp[1];
378
+ argv = (VALUE*)esp[2];
379
+ scope = (int)esp[3];
380
+ self = (VALUE)esp[4];
381
+ } else {
382
+ klass = (VALUE)eax;
383
+ recv = (VALUE)edx;
384
+ mid = (VALUE)ecx;
385
+ argc = (int)esp[0];
386
+ argv = (VALUE*)esp[1];
387
+ scope = (int)esp[2];
388
+ self = (VALUE)esp[3];
389
+ }
390
+ return rb_call_fake(klass,recv,mid,argc,argv,scope,self);
391
+ }
392
+
393
+ #endif
394
+
395
+ void
396
+ rb_call_fake_init() {
397
+
398
+ }
@@ -0,0 +1,138 @@
1
+ /*
2
+
3
+ This file is part of the rallhook project, http://github.com/tario/rallhook
4
+
5
+ Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
6
+
7
+ rallhook is free software: you can redistribute it and/or modify
8
+ it under the terms of the gnu general public license as published by
9
+ the free software foundation, either version 3 of the license, or
10
+ (at your option) any later version.
11
+
12
+ rallhook is distributed in the hope that it will be useful,
13
+ but without any warranty; without even the implied warranty of
14
+ merchantability or fitness for a particular purpose. see the
15
+ gnu general public license for more details.
16
+
17
+ you should have received a copy of the gnu general public license
18
+ along with rallhook. if not, see <http://www.gnu.org/licenses/>.
19
+
20
+ */
21
+
22
+ #ifndef __RB_CALL_FAKE_H
23
+ #define __RB_CALL_FAKE_H
24
+
25
+ #include <ruby.h>
26
+ #include "ruby_version.h"
27
+
28
+ #define FASTCALL
29
+
30
+ void
31
+ rb_call_fake_init();
32
+
33
+ typedef VALUE (*RBCALL_FASTCALL) (
34
+ int argc, /* OK */
35
+ const VALUE *argv, /* OK */
36
+ int scope,
37
+ VALUE self
38
+ ) FASTCALL;
39
+
40
+ typedef VALUE (*RBCALL) (
41
+ VALUE klass, VALUE recv,
42
+ ID mid,
43
+ int argc, /* OK */
44
+ const VALUE *argv, /* OK */
45
+ int scope,
46
+ VALUE self
47
+ );
48
+
49
+ //typedef void rb_control_frame_t;
50
+
51
+
52
+ #ifdef RUBY1_9
53
+
54
+ typedef void rb_block_t_;
55
+ typedef void rb_iseq_t_;
56
+ typedef void rb_thread_t_;
57
+ // from vm_core.h
58
+ typedef struct {
59
+ VALUE *pc;
60
+ VALUE *sp;
61
+ VALUE *bp;
62
+ rb_iseq_t_ *iseq;
63
+ VALUE flag;
64
+ VALUE self;
65
+ VALUE *lfp;
66
+ VALUE *dfp;
67
+ rb_iseq_t_ *block_iseq;
68
+ VALUE proc;
69
+ ID method_id;
70
+ VALUE method_class;
71
+ } rb_control_frame_t_;
72
+
73
+ typedef VALUE (*VMCALLMETHOD) (
74
+ rb_thread_t_ * th, rb_control_frame_t_ *cfp,
75
+ const int num, rb_block_t_ * blockptr, const VALUE flag,
76
+ const ID id, void * mn, const VALUE recv, VALUE klass
77
+ ) ;
78
+ #endif
79
+
80
+ extern void* rb_call_copy;
81
+
82
+ #ifdef RUBY1_9
83
+ extern VMCALLMETHOD vm_call_method_copy;
84
+ VALUE
85
+ vm_call_method_fake(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
86
+ const int num, rb_block_t_ * const blockptr, const VALUE flag,
87
+ const ID id, void * mn, const VALUE recv_, VALUE klass);
88
+ #endif
89
+
90
+ #ifdef __i386__
91
+ #define _WORD int
92
+ #else
93
+ #define _WORD long int
94
+ #endif
95
+
96
+
97
+ VALUE
98
+ rb_call_fake(
99
+ VALUE klass, VALUE recv,
100
+ ID mid,
101
+ int argc, /* OK */
102
+ const VALUE *argv, /* OK */
103
+ int scope,
104
+ VALUE self
105
+ );
106
+
107
+ #ifdef __i386__
108
+
109
+ #ifndef _WORD
110
+ #define _WORD int
111
+ #endif
112
+
113
+ VALUE
114
+ rb_call_fake_regs(
115
+ _WORD eax, _WORD edx, _WORD ecx, _WORD* esp
116
+ );
117
+
118
+ VALUE
119
+ vm_call_method_fake_regs(
120
+ _WORD eax, _WORD edx, _WORD ecx, _WORD* esp
121
+ );
122
+
123
+ #endif
124
+
125
+
126
+ extern void* rb_call_original;
127
+
128
+ #ifdef __i386__
129
+ extern int vm_is_calibrate;
130
+ extern int is_calibrate;
131
+ extern VALUE calibrate_klass;
132
+ extern VALUE calibrate_recv;
133
+ extern ID calibrate_mid;
134
+ #endif
135
+
136
+
137
+
138
+ #endif
@@ -0,0 +1,176 @@
1
+ /*
2
+
3
+ This file is part of the rallhook project, http://github.com/tario/rallhook
4
+
5
+ Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
6
+
7
+ rallhook is free software: you can redistribute it and/or modify
8
+ it under the terms of the gnu general public license as published by
9
+ the free software foundation, either version 3 of the license, or
10
+ (at your option) any later version.
11
+
12
+ rallhook is distributed in the hope that it will be useful,
13
+ but without any warranty; without even the implied warranty of
14
+ merchantability or fitness for a particular purpose. see the
15
+ gnu general public license for more details.
16
+
17
+ you should have received a copy of the gnu general public license
18
+ along with rallhook. if not, see <http://www.gnu.org/licenses/>.
19
+
20
+ */
21
+ #include "ruby.h"
22
+ #include "restrict_def.h"
23
+ #include "ruby_symbols.h"
24
+ #include "hook.h"
25
+
26
+ #ifndef __USE_GNU
27
+ #define __USE_GNU
28
+ #endif
29
+
30
+ #include <dlfcn.h>
31
+
32
+ ID __shadow___id;
33
+ ID __unshadow___id;
34
+ ID shadow_id;
35
+ ID id_restrict_def;
36
+
37
+ typedef void NODE_;
38
+
39
+ typedef void (*RBADDMETHOD) (
40
+ VALUE klass,
41
+ ID id,
42
+ NODE_* node,
43
+ int noex
44
+ );
45
+
46
+ RBADDMETHOD rb_add_method_copy;
47
+
48
+ typedef struct AttachedThreadInfo_ {
49
+ int hook_enabled;
50
+ int hook_enable_left;
51
+ VALUE hook_proc;
52
+ int handle_method_arity;
53
+ } AttachedThreadInfo;
54
+
55
+ AttachedThreadInfo* tinfo_from_thread(VALUE thread);
56
+
57
+ int overwrite_enabled(VALUE current_thread) {
58
+ return tinfo_from_thread(current_thread)->hook_enabled ;
59
+ }
60
+
61
+ VALUE shadow_or_create(VALUE klass);
62
+
63
+ VALUE create_shadow(VALUE klass) {
64
+ if (FL_TEST(klass, FL_SINGLETON)) {
65
+ VALUE obj = rb_iv_get(klass, "__attached__");
66
+ VALUE obj_klass = rb_obj_class(obj);
67
+ VALUE shadow_of_klass = shadow_or_create(obj_klass);
68
+
69
+ VALUE retvalue = rb_class_boot(shadow_of_klass);
70
+ FL_SET(retvalue, FL_SINGLETON);
71
+
72
+ // define as __attached__ of the new singleton class the same object
73
+ rb_iv_set(retvalue, "__attached__", obj);
74
+ return retvalue;
75
+ } else {
76
+ return rb_class_new(klass);
77
+ }
78
+ }
79
+
80
+ VALUE shadow_or_create(VALUE klass) {
81
+
82
+ VALUE shadow_klass = rb_ivar_get(klass, __shadow___id);
83
+ if ( shadow_klass == Qnil ) {
84
+ shadow_klass = create_shadow(klass);
85
+ rb_ivar_set(klass, __shadow___id, shadow_klass );
86
+ rb_ivar_set(shadow_klass, __unshadow___id, klass );
87
+ }
88
+ return shadow_klass;
89
+ }
90
+
91
+ VALUE shadow_or_original(VALUE klass) {
92
+
93
+ VALUE shadow_klass = rb_ivar_get(klass, __shadow___id);
94
+ if ( shadow_klass == Qnil ) {
95
+ return klass;
96
+ }
97
+ return shadow_klass;
98
+
99
+ }
100
+
101
+ VALUE unshadow(VALUE klass) {
102
+ VALUE unshadow_klass = rb_ivar_get(klass, __unshadow___id);
103
+ if (unshadow_klass == Qnil) {
104
+ return klass;
105
+ } else {
106
+ return unshadow_klass;
107
+ }
108
+
109
+ }
110
+
111
+ void rb_add_method_fake(
112
+ VALUE klass,
113
+ ID id,
114
+ NODE_* node,
115
+ int noex
116
+ ) {
117
+ if (overwrite_enabled(rb_thread_current() )) {
118
+ if (FL_TEST(klass, FL_SINGLETON)) {
119
+ // singleton method over classes are illegal
120
+ if ( strcmp( rb_class2name(klass), "Class") == 0) {
121
+ int result;
122
+ if (st_lookup(RCLASS(klass)->m_tbl,id,&result) ) {
123
+ rb_raise(rb_eSecurityError, "Illegal overwrite of singleton method %s", rb_id2name(id) );
124
+ }
125
+ } else {
126
+ rb_add_method_copy(shadow_or_create(klass),id,node,noex);
127
+ }
128
+ } else {
129
+ rb_add_method_copy(shadow_or_create(klass),id,node,noex);
130
+ }
131
+ } else {
132
+ rb_add_method_copy(klass,id,node,noex);
133
+ }
134
+
135
+ }
136
+
137
+ void shadow_redirect(VALUE* klass, VALUE* recv, ID* mid) {
138
+ // shadow redirection if restrict_def (ever)
139
+
140
+ if (overwrite_enabled(rb_thread_current())) {
141
+ *klass = shadow_or_original(*klass);
142
+ }
143
+ }
144
+
145
+ int add_method_code_changed = 0;
146
+
147
+ void init_restrict_def() {
148
+
149
+
150
+ if (!add_method_code_changed) {
151
+
152
+ void* handle = dlopen(current_libruby(),0x101);
153
+ char* rb_funcall = (char*)dlsym(handle, "rb_funcall");
154
+ Dl_info info;
155
+ dladdr(rb_funcall, &info);
156
+
157
+ unsigned char* base = (unsigned char*)info.dli_fbase;
158
+
159
+ void* rb_add_method_original = ruby_resolv(base,"rb_add_method");
160
+
161
+ int inst_size = get_instructions_size(rb_add_method_original, 256);
162
+ rb_add_method_copy = put_jmp_hook(rb_add_method_original, rb_add_method_fake, inst_size);
163
+
164
+ add_method_code_changed = 1;
165
+ }
166
+
167
+ __shadow___id = rb_intern("__shadow__");
168
+ __unshadow___id = rb_intern("__unshadow__");
169
+ shadow_id = rb_intern("shadow");
170
+ id_restrict_def = rb_intern("__restrict_def");
171
+
172
+ rb_define_method(rb_cClass, "shadow", shadow_or_original, 0);
173
+ rb_define_method(rb_cClass, "create_shadow", shadow_or_create, 0);
174
+ rb_define_method(rb_cClass, "unshadow", unshadow, 0);
175
+
176
+ }