node-marshal 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cb2222133e284b6420cd51abdcfeb7b7e266e73
4
- data.tar.gz: 864b5b93258b51e1d9a9bbbf309ba655447f091b
3
+ metadata.gz: d564a41c56aa30cec81fe572e069cd4734637995
4
+ data.tar.gz: 28c7a859af9ba4cfa82c2f8138e0a9b1708f3176
5
5
  SHA512:
6
- metadata.gz: 73a4e165ce77ad01f7cc8af2ae257c16f177dc509c78e783e1872fb88495efb33bb409590996d83925f9791adf3dac67bd8614e15394d8d5a6dfd83742bdecb9
7
- data.tar.gz: c653aaf8b6f25e5ce4ab8f6d5c953ae0bd53d89aaf7adeec60b9172072d8430de84676366c65e133789532215986e5c913570f2ab2d3eeed79b1d61788a74985
6
+ metadata.gz: e7a41dbf52db03ccb69a4ccd9641ff740f45c88ba27488e17dea2897655c0920e1880edfcb29ded1801e25287358bd81d77097453e19c97ca2ff55fa46c90fa0
7
+ data.tar.gz: f31215d9e96c760d21927279162f48627d4bbace53ad66fe43d7335f8de403788e77022570a933fb6b4e5fee65cbd829f26ae9c3d5cd8c63903087ca10048fdd
@@ -1,4 +1,4 @@
1
- Copyright (C) 2015 Alexey Voskov. All rights reserved.
1
+ Copyright (C) 2015-2016 Alexey Voskov. All rights reserved.
2
2
  Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
@@ -17,6 +17,15 @@ The key features of node-marshal gem:
17
17
  - 2-clause BSD license suitable for creation of custom source code protection system
18
18
 
19
19
  Changelog:
20
+ - 11.JAN.2016 - 0.2.0
21
+ - Bugfix: || and && in NODE_OP_ASGN1 (e.g. in x['a'] ||= 'b' or x['b'] &&= false)
22
+ (this bug caused segfaults in some cases)
23
+ - Bugfix: NodeMarshal#dump_node_short
24
+ - Format version changed to NODEMARSHAL11 (support of symbols not representable in
25
+ the form of String is added)
26
+ - show_offsets property for controlling verbosity of NodeMarshal#dump_node_short output
27
+ - Improved information about licenses
28
+ - Improved rdoc documentation
20
29
  - 24.DEC.2015 - 0.1.2
21
30
  - Ruby 2.3.x preliminary support (including &. safe navigation operator)
22
31
  - Bugfix: NODE_MATCH3 (a =~ /abc/) issue (reported by Gregory Siehień)
@@ -24,4 +33,4 @@ Changelog:
24
33
  - Bugfix: failure in the case of syntax errors in the input data (now ArgumentError
25
34
  exception will be generated instead of it)
26
35
  - Ability of symbols renaming (for hiding variables and constants name during code obfuscation)
27
- - 04.MAY.2015 - 0.1.1 - first public version
36
+ - 04.MAY.2015 - 0.1.1 - first public version
@@ -2,13 +2,12 @@
2
2
  require_relative '../lib/node-marshal.rb'
3
3
 
4
4
  help = <<-EOS
5
- Ruby source files compiler. It is based on NodeMarshal class.
6
- from NodeDump gem. Source code is transformed to the Ruby node
7
- (syntax tree) serialized into ASCII string. Such transformation
8
- is based on Ruby internal syntax tree, irreversible and can
9
- be used for code obfuscation.
5
+ Ruby source files compiler from node-marshal gem. It is based
6
+ on NodeMarshal class. Source code is irreversibly transformed to the
7
+ Ruby node (syntax tree) serialized into ASCII string. It can be used
8
+ for for code obfuscation.
10
9
 
11
- (C) 2015 Alexey Voskov. License: 2-clause BSD.
10
+ (C) 2015-2016 Alexey Voskov. License: BSD-2-Clause.
12
11
 
13
12
  Usage:
14
13
  noderbc inpfile outfile [options]
@@ -61,5 +60,4 @@ else
61
60
  outfile = ARGV[1]
62
61
  raise 'inpfile and outfile cannot be equal' if inpfile == outfile
63
62
  NodeMarshal.compile_rb_file(outfile, inpfile, opts)
64
-
65
63
  end
@@ -10,8 +10,8 @@
10
10
  * 2) big-endian 5-byte numbers (base 85)
11
11
  * 3) empty string: arbitrary two bytes
12
12
  *
13
- * (C) 2015 Alexey Voskov
14
- * License: 2-clause BSD
13
+ * (C) 2015-2016 Alexey Voskov
14
+ * License: BSD-2-Clause
15
15
  */
16
16
  #include <stdio.h>
17
17
  #include <stdlib.h>
@@ -78,8 +78,10 @@ static int base85_encode_buf_len(int len)
78
78
  return buf_len;
79
79
  }
80
80
 
81
- /* Encode string to modified BASE85 ASCII.
82
- Call base85_init_tables before using of this function */
81
+ /*
82
+ * Encode string to modified BASE85 ASCII.
83
+ * Note: call base85_init_tables before using of this function
84
+ */
83
85
  VALUE base85r_encode(VALUE input)
84
86
  {
85
87
  VALUE output;
@@ -131,8 +133,10 @@ VALUE base85r_encode(VALUE input)
131
133
  }
132
134
 
133
135
 
134
- /* Decode string in modified BASE85 ASCII format.
135
- Call base85_init_tables before using of this function */
136
+ /*
137
+ * Decode string in modified BASE85 ASCII format.
138
+ * Note: call base85_init_tables before using of this function
139
+ */
136
140
  VALUE base85r_decode(VALUE input)
137
141
  {
138
142
  int inp_len, out_len, pos, shift;
@@ -2,8 +2,8 @@
2
2
  * This file contains implementation of classes for Ruby nodes
3
3
  * marshalization (i.e. loading and saving them from disk)
4
4
  *
5
- * (C) 2015 Alexey Voskov
6
- * License: 2-clause BSD
5
+ * (C) 2015-2016 Alexey Voskov
6
+ * License: BSD-2-Clause
7
7
  */
8
8
  #define __STDC_FORMAT_MACROS
9
9
  #include <stdio.h>
@@ -204,6 +204,23 @@ int LeafTableInfo_addEntry(LeafTableInfo *lti, VALUE key, VALUE value)
204
204
  }
205
205
  }
206
206
 
207
+ /*
208
+ * Adds Ruby ID data type as the entry to the LeafTableInfo struct.
209
+ * Main features:
210
+ * 1) ID will be converted to Fixnum
211
+ * 2) If ID can be converted to string by rb_id2str it will be saved as
212
+ String object. Otherwise it will be converted to Fixnum.
213
+ */
214
+ int LeafTableInfo_addIDEntry(LeafTableInfo *lti, ID id)
215
+ {
216
+ VALUE r_idval = rb_id2str(id);
217
+ if (TYPE(r_idval) != T_STRING)
218
+ {
219
+ r_idval = INT2FIX(id);
220
+ }
221
+ return LeafTableInfo_addEntry(lti, INT2FIX(id), r_idval);
222
+ }
223
+
207
224
  VALUE LeafTableInfo_getLeavesTable(LeafTableInfo *lti)
208
225
  {
209
226
  VALUE key, keys = rb_funcall(lti->vals, rb_intern("keys"), 0);
@@ -389,7 +406,6 @@ static int dump_node_value(NODEInfo *info, char *ptr, NODE *node, int type, VALU
389
406
  }
390
407
  else
391
408
  {
392
- //memcpy(ptr, &id, sizeof(VALUE));
393
409
  switch(type)
394
410
  {
395
411
  case NT_ENTRY: return DUMP_RAW_VALUE(VL_GVAR, id);
@@ -422,7 +438,7 @@ static VALUE dump_nodes(NODEInfo *info)
422
438
  nt = nd_type(node);
423
439
  rtypes = (char *) ptr; ptr += sizeof(int);
424
440
  flags_len = value_to_bin(node->flags >> 5, (unsigned char *) ptr); ptr += flags_len;
425
- //memcpy(ptr, &(node->flags), sizeof(VALUE)); ptr += sizeof(VALUE);
441
+
426
442
  ut[0] = nodes_ctbl[nt * 3];
427
443
  ut[1] = nodes_ctbl[nt * 3 + 1];
428
444
  ut[2] = nodes_ctbl[nt * 3 + 2];
@@ -456,7 +472,6 @@ static VALUE dump_nodes(NODEInfo *info)
456
472
  rtypes[3] = flags_len;
457
473
  }
458
474
  rb_str_resize(nodes_bin, (int) (ptr - bin) + 1);
459
- //printf("%d", ptr - bin);
460
475
  return nodes_bin;
461
476
  }
462
477
 
@@ -475,7 +490,7 @@ VALUE NODEInfo_toHash(NODEInfo *info)
475
490
  VALUE args;
476
491
  int i, j, id;
477
492
  // Add some signatures
478
- rb_hash_aset(ans, ID2SYM(rb_intern("MAGIC")), rb_str_new2("NODEMARSHAL10"));
493
+ rb_hash_aset(ans, ID2SYM(rb_intern("MAGIC")), rb_str_new2(NODEMARSHAL_MAGIC));
479
494
  rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_PLATFORM")),
480
495
  rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM")));
481
496
  rb_hash_aset(ans, ID2SYM(rb_intern("RUBY_VERSION")),
@@ -573,7 +588,7 @@ static void NODEInfo_addValue(NODEInfo *info, VALUE value)
573
588
  * Function counts number of nodes and fills NODEInfo struct
574
589
  * that is neccessary for the node saving to the HDD
575
590
  */
576
- int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
591
+ static int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
577
592
  {
578
593
  int ut[3], num, offset;
579
594
  if (node == 0)
@@ -632,7 +647,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
632
647
  }
633
648
  else if (ut[0] == NT_ID)
634
649
  {
635
- LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u1.id), rb_id2str(node->u1.id));
650
+ LeafTableInfo_addIDEntry(&info->syms, node->u1.id);
636
651
  }
637
652
  else if (ut[0] == NT_VALUE)
638
653
  {
@@ -650,7 +665,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
650
665
  {
651
666
  ID sym = *idtbl++;
652
667
  rb_ary_push(idtbl_ary, INT2FIX(sym));
653
- LeafTableInfo_addEntry(&info->syms, INT2FIX(sym), rb_id2str(sym));
668
+ LeafTableInfo_addIDEntry(&info->syms, sym);
654
669
  }
655
670
  LeafTableInfo_addEntry(&info->idtabs, tkey, idtbl_ary);
656
671
  }
@@ -665,7 +680,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
665
680
  }
666
681
  else if (ut[1] == NT_ID)
667
682
  {
668
- LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u2.id), rb_id2str(node->u2.id));
683
+ LeafTableInfo_addIDEntry(&info->syms, node->u2.id);
669
684
  }
670
685
  else if (ut[1] == NT_VALUE)
671
686
  {
@@ -685,7 +700,7 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
685
700
  }
686
701
  else if (ut[2] == NT_ID)
687
702
  {
688
- LeafTableInfo_addEntry(&info->syms, INT2FIX(node->u3.id), rb_id2str(node->u3.id));
703
+ LeafTableInfo_addIDEntry(&info->syms, node->u3.id);
689
704
  }
690
705
  else if (ut[2] == NT_ARGS)
691
706
  {
@@ -709,29 +724,29 @@ int count_num_of_nodes(NODE *node, NODE *parent, NODEInfo *info)
709
724
 
710
725
  asym = ainfo->first_post_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
711
726
  if (asym != 0)
712
- LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
727
+ LeafTableInfo_addIDEntry(&info->syms, asym);
713
728
 
714
729
  asym = ainfo->rest_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
715
730
  if (asym != 0)
716
- LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
731
+ LeafTableInfo_addIDEntry(&info->syms, asym);
717
732
 
718
733
  asym = ainfo->block_arg; rb_ary_push(varg, INT2FIX(asym)); // ID
719
734
  if (asym != 0)
720
- LeafTableInfo_addEntry(&info->syms, INT2FIX(asym), rb_id2str(asym));
735
+ LeafTableInfo_addIDEntry(&info->syms, asym);
721
736
  rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_args));
722
737
  rb_ary_push(varg, value_to_str((VALUE) ainfo->kw_rest_arg));
723
738
  rb_ary_push(varg, value_to_str((VALUE) ainfo->opt_args));
724
739
 
725
740
  LeafTableInfo_addEntry(&info->args, value_to_str((VALUE) ainfo), varg);
726
741
  #else
727
- rb_raise(rb_eArgError, "NT_ARGS entry withour USE_RB_ARGS_INFO");
742
+ rb_raise(rb_eArgError, "NT_ARGS entry without USE_RB_ARGS_INFO");
728
743
  #endif
729
744
  }
730
745
  else if (ut[2] == NT_ENTRY)
731
746
  {
732
747
  ID gsym = node->u3.entry->id;
733
748
  // Save symbol to the symbol table
734
- int newid = LeafTableInfo_addEntry(&info->syms, INT2FIX(gsym), rb_id2str(gsym));
749
+ int newid = LeafTableInfo_addIDEntry(&info->syms, gsym);
735
750
  LeafTableInfo_addEntry(&info->gentries, value_to_str(node->u3.value), INT2FIX(newid));
736
751
  }
737
752
  else if (ut[2] != NT_LONG && ut[2] != NT_NULL)
@@ -799,10 +814,16 @@ void rbstr_printf(VALUE str, const char *fmt, ...)
799
814
  }
800
815
 
801
816
  #define PRINT_NODE_TAB for (j = 0; j < tab; j++) rbstr_printf(str, " ");
802
- void print_node(VALUE str, NODE *node, int tab)
817
+ /*
818
+ * Recursively transforms node into Ruby string
819
+ * str -- output Ruby string
820
+ * node -- input Ruby NODE
821
+ * tab -- number of tabulations during print
822
+ * show_offsets -- 0/1 show/hide addresses and symbol IDs
823
+ */
824
+ static void print_node(VALUE str, NODE *node, int tab, int show_offsets)
803
825
  {
804
826
  int i, j, type, ut[3];
805
- int show_offsets = 0;
806
827
  VALUE uref[3];
807
828
 
808
829
  PRINT_NODE_TAB
@@ -815,12 +836,14 @@ void print_node(VALUE str, NODE *node, int tab)
815
836
 
816
837
  if (show_offsets)
817
838
  {
818
- rbstr_printf(str, "@ %s | %16"PRIxPTR " %16"PRIxPTR " %16"PRIxPTR "\n", ruby_node_name(type),
819
- (intptr_t) node->u1.value, (intptr_t) node->u2.value, (intptr_t) node->u3.value);
839
+ rbstr_printf(str, "@ %s | %16"PRIxPTR " %16"PRIxPTR " %16"PRIxPTR " (line %d)\n",
840
+ ruby_node_name(type),
841
+ (intptr_t) node->u1.value, (intptr_t) node->u2.value, (intptr_t) node->u3.value,
842
+ nd_line(node));
820
843
  }
821
844
  else
822
845
  {
823
- rbstr_printf(str, "@ %s\n", ruby_node_name(type));
846
+ rbstr_printf(str, "@ %s (line %d)\n", ruby_node_name(type), nd_line(node));
824
847
  }
825
848
 
826
849
  ut[0] = nodes_ctbl[type * 3];
@@ -837,7 +860,7 @@ void print_node(VALUE str, NODE *node, int tab)
837
860
  if (ut[i] == NT_NODE)
838
861
  {
839
862
  if (nd_type(node) != NODE_OP_ASGN2 || i != 2)
840
- print_node(str, RNODE(uref[i]), tab + 1);
863
+ print_node(str, RNODE(uref[i]), tab + 1, show_offsets);
841
864
  else
842
865
  {
843
866
  if (ut[i] != 0 && TYPE(ut[i]) != T_NODE)
@@ -855,7 +878,7 @@ void print_node(VALUE str, NODE *node, int tab)
855
878
  PRINT_NODE_TAB; rbstr_printf(str, " ");
856
879
  if (show_offsets)
857
880
  {
858
- rbstr_printf(str, ">| ADR: %"PRIxPTR" TYPE: %d TEXT: %s\n",
881
+ rbstr_printf(str, ">| ADR: %"PRIxPTR"; CLASS: %s (TYPE %d); VALUE: %s\n",
859
882
  (intptr_t) uref[i],
860
883
  class_name, TYPE(uref[i]),
861
884
  RSTRING_PTR(rb_funcall(uref[i], rb_intern("to_s"), 0)));
@@ -869,11 +892,25 @@ void print_node(VALUE str, NODE *node, int tab)
869
892
  }
870
893
  else if (ut[i] == NT_ID)
871
894
  {
895
+ const char *str_null = "<NULL>", *str_intern = "<NONAME>";
896
+ const char *str_sym;
872
897
  PRINT_NODE_TAB; rbstr_printf(str, " ");
898
+
899
+ if (uref[i] == 0)
900
+ str_sym = str_null;
901
+ else
902
+ {
903
+ VALUE rbstr_sym = rb_id2str(uref[i]);
904
+ if (TYPE(rbstr_sym) == T_STRING)
905
+ str_sym = RSTRING_PTR(rb_id2str(uref[i]));
906
+ else
907
+ str_sym = str_intern;
908
+ }
909
+
873
910
  if (show_offsets)
874
- rbstr_printf(str, ">| ID: %d; SYMBOL: %s\n", (ID) uref[i], RSTRING_PTR(rb_id2str(uref[i])));
911
+ rbstr_printf(str, ">| ID: %d; SYMBOL: :%s\n", (ID) uref[i], str_sym);
875
912
  else
876
- rbstr_printf(str, ">| SYMBOL: :%s\n", RSTRING_PTR(rb_id2str(uref[i])));
913
+ rbstr_printf(str, ">| SYMBOL: :%s\n", str_sym);
877
914
  }
878
915
  else if (ut[i] == NT_LONG)
879
916
  {
@@ -927,7 +964,21 @@ void resolve_syms_ords(VALUE data, NODEObjAddresses *relocs)
927
964
  relocs->syms_len = RARRAY_LEN(tbl_val);
928
965
  relocs->syms_adr = ALLOC_N(ID, relocs->syms_len);
929
966
  for (i = 0; i < relocs->syms_len; i++)
930
- relocs->syms_adr[i] = rb_intern(RSTRING_PTR(RARRAY_PTR(tbl_val)[i]));
967
+ {
968
+ VALUE r_sym = RARRAY_PTR(tbl_val)[i];
969
+ if (TYPE(r_sym) == T_STRING)
970
+ {
971
+ relocs->syms_adr[i] = rb_intern(RSTRING_PTR(r_sym));
972
+ }
973
+ else if (TYPE(r_sym) == T_FIXNUM)
974
+ {
975
+ relocs->syms_adr[i] = (ID) FIX2INT(r_sym);
976
+ }
977
+ else
978
+ {
979
+ rb_raise(rb_eArgError, "Symbols table is corrupted");
980
+ }
981
+ }
931
982
  }
932
983
 
933
984
  void resolve_lits_ords(VALUE data, NODEObjAddresses *relocs)
@@ -1053,16 +1104,16 @@ void resolve_args_ords(VALUE data, NODEObjAddresses *relocs)
1053
1104
  rb_raise(rb_eArgError, "args entry %d is corrupted", i);
1054
1105
  }
1055
1106
  // Load unresolved values
1056
- ainfo->pre_init = (NODE *) FIX2LONG(aiptr[0]); // Node ordinal
1057
- ainfo->post_init = (NODE *) FIX2LONG(aiptr[1]); // Node ordinal
1107
+ ainfo->pre_init = (NODE *) (uintptr_t) FIX2LONG(aiptr[0]); // Node ordinal
1108
+ ainfo->post_init = (NODE *) (uintptr_t) FIX2LONG(aiptr[1]); // Node ordinal
1058
1109
  ainfo->pre_args_num = FIX2INT(aiptr[2]); // No ordinal resolving
1059
1110
  ainfo->post_args_num = FIX2INT(aiptr[3]); // No ordinal resolving
1060
1111
  ainfo->first_post_arg = FIX2INT(aiptr[4]); // Symbolic ordinal
1061
1112
  ainfo->rest_arg = FIX2INT(aiptr[5]); // Symbolic ordinal
1062
1113
  ainfo->block_arg = FIX2INT(aiptr[6]); // Symbolic ordinal
1063
- ainfo->kw_args = (NODE *) FIX2LONG(aiptr[7]); // Node ordinal
1064
- ainfo->kw_rest_arg = (NODE *) FIX2LONG(aiptr[8]); // Node ordinal
1065
- ainfo->opt_args = (NODE *) FIX2LONG(aiptr[9]); // Node ordinal
1114
+ ainfo->kw_args = (NODE *) (uintptr_t) FIX2LONG(aiptr[7]); // Node ordinal
1115
+ ainfo->kw_rest_arg = (NODE *) (uintptr_t) FIX2LONG(aiptr[8]); // Node ordinal
1116
+ ainfo->opt_args = (NODE *) (uintptr_t) FIX2LONG(aiptr[9]); // Node ordinal
1066
1117
  // Resolve nodes
1067
1118
  ord = (int) (((VALUE) ainfo->pre_init) & 0xFFFFFFFF);
1068
1119
  if (ord < -1 || ord >= relocs->nodes_len)
@@ -1107,6 +1158,23 @@ void resolve_args_ords(VALUE data, NODEObjAddresses *relocs)
1107
1158
  }
1108
1159
  #endif
1109
1160
 
1161
+ /*
1162
+ * Transforms binary data with nodes descriptions into Ruby AST (i.e.
1163
+ * ternary tree of nodes). Each node is represented in the next binary format:
1164
+ *
1165
+ * [4 bytes -- pointers info] [node flags] [child ORD1] [child ORD2] [child ORD3]
1166
+ *
1167
+ * Pointers info:
1168
+ * BYTE -- child 1 info (bits 7..4 -- ordinal type, bits 3..0 -- ordinal size, bytes)
1169
+ * BYTE -- child 2 info
1170
+ * BYTE -- child 3 info
1171
+ * BYTE -- node flags length, bytes
1172
+ * Node flags:
1173
+ * node->flags field packed by bin_to_value function
1174
+ * child ORDi Ordinal of ith node child packed by bin_to_value_function
1175
+ * (it will be transformed to the real address in memory, i.e. pointer
1176
+ * or symbol ID during data loading)
1177
+ */
1110
1178
  void load_nodes_from_str(VALUE data, NODEObjAddresses *relocs)
1111
1179
  {
1112
1180
  int i, j;
@@ -1215,7 +1283,7 @@ static VALUE check_hash_magic(VALUE data)
1215
1283
  VALUE val, refval;
1216
1284
  // MAGIC signature must be valid
1217
1285
  val = get_hash_strfield(data, "MAGIC");
1218
- if (strcmp("NODEMARSHAL10", RSTRING_PTR(val)))
1286
+ if (strcmp(NODEMARSHAL_MAGIC, RSTRING_PTR(val)))
1219
1287
  rb_raise(rb_eArgError, "Bad value of MAGIC signature");
1220
1288
  // RUBY_PLATFORM signature must match the current platform
1221
1289
  val = get_hash_strfield(data, "RUBY_PLATFORM");
@@ -1307,6 +1375,9 @@ static VALUE m_nodedump_from_memory(VALUE self, VALUE dump)
1307
1375
 
1308
1376
 
1309
1377
  /*
1378
+ * call-seq:
1379
+ * obj.symbols
1380
+ *
1310
1381
  * Return array with the list of symbols
1311
1382
  */
1312
1383
  static VALUE m_nodedump_symbols(VALUE self)
@@ -1343,8 +1414,12 @@ static VALUE m_nodedump_symbols(VALUE self)
1343
1414
  }
1344
1415
 
1345
1416
  /*
1346
- * Replace one symbol by another
1347
- * (to be used for code obfuscation)
1417
+ * call-seq:
1418
+ * obj.change_symbol(old_sym, new_sym)
1419
+ *
1420
+ * Replace one symbol by another (to be used for code obfuscation)
1421
+ * - +old_sym+ -- String that contains symbol name to be replaced
1422
+ * - +new_sym+ -- String that contains new name of the symbol
1348
1423
  */
1349
1424
  static VALUE m_nodedump_change_symbol(VALUE self, VALUE old_sym, VALUE new_sym)
1350
1425
  {
@@ -1540,6 +1615,7 @@ static VALUE m_nodedump_from_string(VALUE self, VALUE str)
1540
1615
  static VALUE m_nodedump_init(VALUE self, VALUE source, VALUE info)
1541
1616
  {
1542
1617
  ID id_usr;
1618
+ rb_iv_set(self, "@show_offsets", Qfalse);
1543
1619
  Check_Type(source, T_SYMBOL);
1544
1620
  id_usr = SYM2ID(source);
1545
1621
  if (id_usr == rb_intern("srcfile"))
@@ -1571,8 +1647,8 @@ static VALUE m_nodedump_init(VALUE self, VALUE source, VALUE info)
1571
1647
  * call-seq:
1572
1648
  * obj.dump_tree
1573
1649
  *
1574
- * Transforms Ruby syntax tree (NODE) to the text string using
1575
- * rb_parser_dump_tree function from node.c (see Ruby source code).
1650
+ * Transforms Ruby syntax tree (NODE) to the String using
1651
+ * +rb_parser_dump_tree+ function from +node.c+ (see Ruby source code).
1576
1652
  */
1577
1653
  static VALUE m_nodedump_parser_dump_tree(VALUE self)
1578
1654
  {
@@ -1581,16 +1657,52 @@ static VALUE m_nodedump_parser_dump_tree(VALUE self)
1581
1657
  }
1582
1658
 
1583
1659
  /*
1584
- * Prints the node tree in the short variant
1660
+ * call-seq:
1661
+ * obj.dump_tree_short
1662
+ *
1663
+ * Transforms Ruby syntax tree (NODE) to the String using custom function
1664
+ * instead of +rb_parser_dump_tree+ function.
1665
+ *
1666
+ * See also #show_offsets, #show_offsets=
1585
1667
  */
1586
1668
  static VALUE m_nodedump_dump_tree_short(VALUE self)
1587
1669
  {
1588
1670
  VALUE str = rb_str_new2(""); // Output string
1589
1671
  NODE *node = RNODE(rb_iv_get(self, "@node"));
1590
- print_node(str, node, 0);
1672
+ int show_offsets = (rb_iv_get(self, "@show_offsets") == Qtrue) ? 1 : 0;
1673
+ print_node(str, node, 0, show_offsets);
1591
1674
  return str;
1592
1675
  }
1593
1676
 
1677
+ /*
1678
+ * call-seq:
1679
+ * obj.show_offsets
1680
+ *
1681
+ * Returns show_offsets property (used by NodeMarshal#dump_tree_short)
1682
+ * It can be either true or false
1683
+ */
1684
+ static VALUE m_nodedump_show_offsets(VALUE self)
1685
+ {
1686
+ return rb_iv_get(self, "@show_offsets");
1687
+ }
1688
+
1689
+ /*
1690
+ * call-seq:
1691
+ * obj.show_offsets=
1692
+ *
1693
+ * Sets show_offsets property (used by NodeMarshal#dump_tree_short)
1694
+ * It can be either true or false
1695
+ */
1696
+ static VALUE m_nodedump_set_show_offsets(VALUE self, VALUE value)
1697
+ {
1698
+ if (value != Qtrue && value != Qfalse)
1699
+ {
1700
+ rb_raise(rb_eArgError, "show_offsets property must be either true or false");
1701
+ }
1702
+ return rb_iv_set(self, "@show_offsets", value);
1703
+ }
1704
+
1705
+
1594
1706
  /*
1595
1707
  * call-seq:
1596
1708
  * obj.to_hash
@@ -1604,7 +1716,7 @@ static VALUE m_nodedump_dump_tree_short(VALUE self)
1604
1716
  *
1605
1717
  * <i>Part 1: Signatures</i>
1606
1718
  *
1607
- * - <tt>MAGIC</tt> -- NODEMARSHAL10
1719
+ * - <tt>MAGIC</tt> -- NODEMARSHAL11
1608
1720
  * - <tt>RUBY_PLATFORM</tt> -- saved <tt>RUBY_PLATFORM</tt> constant value
1609
1721
  * - <tt>RUBY_VERSION</tt> -- saved <tt>RUBY_VERSION</tt> constant value
1610
1722
  *
@@ -1614,7 +1726,8 @@ static VALUE m_nodedump_dump_tree_short(VALUE self)
1614
1726
  * its identifier that is used in the node tree.
1615
1727
  *
1616
1728
  * - <tt>literals</tt> -- program literals (strings, ranges etc.)
1617
- * - <tt>symbols</tt> -- program symbols
1729
+ * - <tt>symbols</tt> -- program symbols (values have either String or Fixnum
1730
+ * data type; numbers are used for symbols that cannot be represented as strings)
1618
1731
  * - <tt>global_entries</tt> -- global variables information
1619
1732
  * - <tt>id_tables</tt> -- array of arrays. Each array contains symbols IDs
1620
1733
  * - <tt>args</tt> -- information about code block argument(s)
@@ -1867,7 +1980,7 @@ static VALUE m_base85r_decode(VALUE obj, VALUE input)
1867
1980
  }
1868
1981
 
1869
1982
  /* call-seq:
1870
- * obj.to_bin
1983
+ * obj.to_text
1871
1984
  *
1872
1985
  * Converts NodeMarshal class example to the text string (modified Base85 encoding) that
1873
1986
  * can be saved to the file and used for loading the node from the file.
@@ -1888,7 +2001,6 @@ static VALUE m_nodedump_node(VALUE self)
1888
2001
  return rb_iv_get(self, "@node");
1889
2002
  }
1890
2003
 
1891
-
1892
2004
  /*
1893
2005
  * This class can load and save Ruby code in the form of the
1894
2006
  * platform-dependent syntax tree (made of NODEs). Such function
@@ -1917,6 +2029,8 @@ void Init_nodemarshal()
1917
2029
  rb_define_method(cNodeMarshal, "dump_tree", RUBY_METHOD_FUNC(m_nodedump_parser_dump_tree), 0);
1918
2030
  rb_define_method(cNodeMarshal, "dump_tree_short", RUBY_METHOD_FUNC(m_nodedump_dump_tree_short), 0);
1919
2031
  rb_define_method(cNodeMarshal, "compile", RUBY_METHOD_FUNC(m_nodedump_compile), 0);
2032
+ rb_define_method(cNodeMarshal, "show_offsets", RUBY_METHOD_FUNC(m_nodedump_show_offsets), 0);
2033
+ rb_define_method(cNodeMarshal, "show_offsets=", RUBY_METHOD_FUNC(m_nodedump_set_show_offsets), 1);
1920
2034
  // Methods for working with the information about the node
1921
2035
  // a) literals, symbols, generic information
1922
2036
  rb_define_method(cNodeMarshal, "symbols", RUBY_METHOD_FUNC(m_nodedump_symbols), 0);
@@ -14,6 +14,8 @@
14
14
 
15
15
 
16
16
  /* Some constants */
17
+ // Magic value with the version of the format
18
+ #define NODEMARSHAL_MAGIC "NODEMARSHAL11"
17
19
  // Type of the node "Child"
18
20
  #define NT_NULL 0
19
21
  #define NT_UNKNOWN 1
@@ -8,7 +8,7 @@
8
8
  * Fragments from Ruby source code are used here
9
9
  * (mainly from node.c, gc.c)
10
10
  *
11
- * License: 2-clause BSD
11
+ * License: BSD-2-Clause
12
12
  *
13
13
  */
14
14
  #include <stdio.h>
@@ -165,9 +165,10 @@ static int nodes_child_info[][4] =
165
165
 
166
166
 
167
167
 
168
- /**
169
- * @brief Check the correctness of nodes table from the viewpoint
170
- * This function is based on Ruby 2.2.1 source code (node.c) */
168
+ /*
169
+ * Check the correctness of nodes table from the viewpoint
170
+ * This function is based on Ruby source code (node.c)
171
+ */
171
172
  void check_nodes_child_info(int pos)
172
173
  {
173
174
  int type = nodes_child_info[pos][0];
@@ -565,22 +566,36 @@ void check_nodes_child_info(int pos)
565
566
 
566
567
  }
567
568
 
568
-
569
+ /*
570
+ * Converts nodes_child_info 2D array of int into nodes_ctbl 1D array of int
571
+ *
572
+ * nodes_child_info is similar to hash by the structure: each 1D subarray
573
+ * has the next structure:
574
+ * {NODE_ID, NT_CHILD1_TYPE, NT_CHILD2_TYPE, NT_CHILD3_TYPE}
575
+ */
569
576
  void init_nodes_table(int *nodes_ctbl, int num_of_entries)
570
577
  {
571
- int pos, offset, i;
578
+ int pos, i;
579
+ /* Check the input array using information from Ruby source code */
572
580
  for (pos = 0; nodes_child_info[pos][0] != -1; pos++)
573
581
  {
574
582
  check_nodes_child_info(pos);
575
583
  }
576
-
584
+ /* Initialize output array by NT_UNKNOWN (if node is not defined
585
+ in the input table the types of its childs are unknown) */
577
586
  for (i = 0; i < num_of_entries * 3; i++)
578
587
  {
579
588
  nodes_ctbl[i] = NT_UNKNOWN;
580
589
  }
590
+ /* Fill output array */
581
591
  for (pos = 0; nodes_child_info[pos][0] != -1; pos++)
582
592
  {
583
- offset = (nodes_child_info[pos][0]) * 3;
593
+ int index = nodes_child_info[pos][0], offset;
594
+ if (index < 0 || index > num_of_entries)
595
+ {
596
+ rb_raise(rb_eArgError, "NODE ID %d is out or nodes_ctbl array boundaries", index);
597
+ }
598
+ offset = index * 3;
584
599
  nodes_ctbl[offset++] = nodes_child_info[pos][1];
585
600
  nodes_ctbl[offset++] = nodes_child_info[pos][2];
586
601
  nodes_ctbl[offset++] = nodes_child_info[pos][3];
@@ -31,7 +31,9 @@ class NodeMarshal
31
31
  # - +opts+ -- Hash with options (+:compress+, +:so_path+)
32
32
  # +:compress+ can be +true+ or +false+, +:so_path+ is a test string
33
33
  # with the command for nodemarshal.so inclusion (default is
34
- # require_relative '../ext/node-marshal/nodemarshal.so')
34
+ # <tt>require_relative '../ext/node-marshal/nodemarshal.so'</tt>)
35
+ #
36
+ # See also NodeMarshal::compile_rb_file
35
37
  def to_compiled_rb(outfile, *args)
36
38
  compress = true
37
39
  so_path = "require_relative '../ext/node-marshal/nodemarshal.so'"
@@ -80,6 +82,12 @@ EOS
80
82
  return txt
81
83
  end
82
84
 
85
+ # call-seq:
86
+ # NodeMarshal::compile_rb_file(outfile, inpfile, opts)
87
+ #
88
+ # Reads +.rb+ file (Ruby source) and compiles it to .rb file containing
89
+ # compressed AST node and its loader. This functions is an envelope for
90
+ # NodeMarshal#to_compiled_rb
83
91
  def self.compile_rb_file(outfile, inpfile, *args)
84
92
  node = NodeMarshal.new(:srcfile, inpfile)
85
93
  node.to_compiled_rb(outfile, *args)
@@ -117,7 +125,7 @@ EOS
117
125
  end
118
126
 
119
127
  # call-seq:
120
- # obj.get_safe_symbols
128
+ # obj.get_safe_symbols(our_symbols)
121
129
  #
122
130
  # Returns an array that contains strings with the names of symbols that are safe
123
131
  # to change. It excludes symbols that are present in the table of literals (and their derivatives
@@ -189,7 +197,7 @@ EOS
189
197
  end
190
198
 
191
199
  # call-seq:
192
- # obj.rebuld
200
+ # obj.rebuild
193
201
  #
194
202
  # Rebuilds the node by converting it to the binary dump and further restoring
195
203
  # of it from this dump. It doesn't change the original node and returns rebuilt
@@ -37,7 +37,6 @@ end
37
37
  ni.map {|x| fact(x) }
38
38
  EOS
39
39
  assert_node_compiler(program)
40
- # test_string_eval(program, [1, 2, 6, 24, 120, 720, 5040, 40320, 362880], "Factorial");
41
40
  end
42
41
 
43
42
  # Simple ROT13 task that combines several language construction
@@ -163,6 +162,27 @@ EOS
163
162
  assert_node_compiler(program)
164
163
  end
165
164
 
165
+ # Test expressions like x['a'] &&= true or x['b'] ||= false
166
+ # (they use NODE_OP_ASGN1 node and symbols that cannot be represented
167
+ # by String value)
168
+ def test_node_op_asgn1
169
+ program = <<EOS
170
+ x = {a: [1234], b: [5678, 2],
171
+ and1: true, and2: true, and3: false, and4: false,
172
+ or1: true, or2: true, or3: false, or4: false}
173
+ x[:a] &&= 'test'
174
+ x[:b] ||= 'qqq'
175
+
176
+ x[:and1] &&= false; x[:and2] &&= true
177
+ x[:and3] &&= false; x[:and4] &&= true
178
+
179
+ x[:or1] ||= false; x[:or2] ||= true
180
+ x[:or3] ||= false; x[:or4] ||= true
181
+ x
182
+ EOS
183
+ assert_node_compiler(program)
184
+ end
185
+
166
186
  # Check the reaction on the parsing errors during the node creation
167
187
  # In the case of syntax error ArgumentError exception should be generated
168
188
  def test_syntax_error
@@ -35,7 +35,7 @@ class TestHashTree
35
35
  @depth = depth
36
36
  @value = {:depth => depth, :data => [], :leaves =>[] }
37
37
  data_size.times do
38
- case rnd.rand(30000) % 6
38
+ case rnd.rand(30000) % 7
39
39
  when 0
40
40
  @value[:data] << 10**(rnd.rand(600000) * 0.001 - 300)
41
41
  when 1
@@ -51,6 +51,9 @@ class TestHashTree
51
51
  when 5
52
52
  a, b = rnd.rand(100), rnd.rand(10)
53
53
  @value[:data] << (a...(a + b))
54
+ when 6
55
+ rndsym = (Random.rand(1_000_000_000).to_s(36)).to_sym
56
+ @value[:data] << rndsym
54
57
  else
55
58
  nil
56
59
  end
@@ -122,7 +125,7 @@ class TestComplex < Test::Unit::TestCase
122
125
  puts " Source code size: %d bytes" % tree_str.length
123
126
  puts " Binary data size: %d bytes" % tree_bin.length
124
127
  # Clear the memory
125
- node = nil; GC.start
128
+ node = nil; GC.enable; GC.start
126
129
  # Load the node from the disk and turn it to tree
127
130
  puts 'Loading the node...'
128
131
  node = NodeMarshal.new(:binfile, 'node.bin')
@@ -35,12 +35,17 @@ puts "'#{b&.owner_name}'"
35
35
  puts "'#{b&.owner_info&.address}'"
36
36
  [a&.owner_name, a&.owner_info&.address, b&.owner_name, b&.owner_info&.address]
37
37
  }
38
-
39
- node = NodeMarshal.new(:srcmemory, qcall_program)
40
- bindump = node.to_bin
41
- node = NodeMarshal.new(:binmemory, bindump)
42
- res_node = node.compile.eval
43
- res_text = eval(qcall_program)
44
- assert_equal(res_text, res_node)
38
+ ver = RUBY_VERSION
39
+ ver = (ver[0] + ver[2] + ver[4]).to_i
40
+ if ver >= 230
41
+ node = NodeMarshal.new(:srcmemory, qcall_program)
42
+ bindump = node.to_bin
43
+ node = NodeMarshal.new(:binmemory, bindump)
44
+ res_node = node.compile.eval
45
+ res_text = eval(qcall_program)
46
+ assert_equal(res_text, res_node)
47
+ else
48
+ assert_true(false, "Ruby 2.3 or higher is required for &. operator test")
49
+ end
45
50
  end
46
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: node-marshal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Voskov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir:
10
10
  - bin
11
11
  cert_chain: []
12
- date: 2015-12-24 00:00:00.000000000 Z
12
+ date: 2016-01-11 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: "This gem is designed for transformation of Ruby source code (eiher in
15
15
  the form of files or strings) to the \nRuby nodes (syntax trees) used by Ruby MRI
@@ -25,10 +25,10 @@ extensions:
25
25
  extra_rdoc_files:
26
26
  - README.rdoc
27
27
  files:
28
+ - COPYING
28
29
  - README.rdoc
29
30
  - bin/noderbc
30
31
  - bin/noderbc.bat
31
- - ext/node-marshal/COPYING
32
32
  - ext/node-marshal/base85r.c
33
33
  - ext/node-marshal/extconf.rb
34
34
  - ext/node-marshal/libobj/readme.txt
@@ -46,9 +46,9 @@ files:
46
46
  - test/test_obfuscator.rb
47
47
  - test/test_qcall.rb
48
48
  - test/tinytet.rb
49
- homepage:
49
+ homepage: https://github.com/dig386/node-marshal
50
50
  licenses:
51
- - 2-clause BSD
51
+ - BSD-2-Clause
52
52
  metadata: {}
53
53
  post_install_message:
54
54
  rdoc_options: