rallhook 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }