summaryrefslogtreecommitdiff
path: root/test/ruby/test_marshal.rb
blob: e51e5a5417257bc7cd7ae34af88f681d699763b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
require 'test/unit'
dir = File.dirname(File.expand_path(__FILE__))
orgpath = $:.dup
begin
  $:.push(dir)
  require 'marshaltestlib'
ensure
  $:.replace(orgpath)
end

class TestMarshal < Test::Unit::TestCase
  include MarshalTestLib

  def encode(o)
    stress, GC.stress = GC.stress, true
    Marshal.dump(o)
  ensure
    GC.stress = stress
  end

  def decode(s)
    stress, GC.stress = GC.stress, true
    Marshal.load(s)
  ensure
    GC.stress = stress
  end

  def fact(n)
    return 1 if n == 0
    f = 1
    while n>0
      f *= n
      n -= 1
    end
    return f
  end

  StrClone=String.clone;

  def test_marshal
    $x = [1,2,3,[4,5,"foo"],{1=>"bar"},2.5,fact(30)]
    $y = Marshal.dump($x)
    assert_equal($x, Marshal.load($y))

    assert_instance_of(StrClone, Marshal.load(Marshal.dump(StrClone.new("abc"))))

    [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z|
      a = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f))
      ma = Marshal.dump(a)
      b = Marshal.load(ma)
      assert_equal(a, b)
    }
  end

  class C
    def initialize(str)
      @str = str
    end
    def _dump(limit)
      @str
    end
    def self._load(s)
      new(s)
    end
  end

  def test_too_long_string
    (data = Marshal.dump(C.new("a")))[-2, 1] = "\003\377\377\377"
    e = assert_raise(ArgumentError, "[ruby-dev:32054]") {
      Marshal.load(data)
    }
    assert_equal("marshal data too short", e.message)
  end

  class DumpTest
    def marshal_dump
      loop { Thread.pass }
    end
  end

  class LoadTest
    def marshal_dump
      nil
    end
    def marshal_load(obj)
      loop { Thread.pass }
    end
  end

  def test_context_switch
    o = DumpTest.new
    Thread.new { Marshal.dump(o) }
    GC.start
    assert(true, '[ruby-dev:39425]')

    o = LoadTest.new
    m = Marshal.dump(o)
    Thread.new { Marshal.load(m) }
    GC.start
    assert(true, '[ruby-dev:39425]')
  end

  def test_taint
    x = Object.new
    x.taint
    s = Marshal.dump(x)
    assert_equal(true, s.tainted?)
    y = Marshal.load(s)
    assert_equal(true, y.tainted?)
  end

  def test_taint_each_object
    x = Object.new
    obj = [[x]]

    # clean object causes crean stream
    assert_equal(false, obj.tainted?)
    assert_equal(false, obj.first.tainted?)
    assert_equal(false, obj.first.first.tainted?)
    s = Marshal.dump(obj)
    assert_equal(false, s.tainted?)

    # tainted object causes tainted stream
    x.taint
    assert_equal(false, obj.tainted?)
    assert_equal(false, obj.first.tainted?)
    assert_equal(true, obj.first.first.tainted?)
    t = Marshal.dump(obj)
    assert_equal(true, t.tainted?)

    # clean stream causes clean objects
    assert_equal(false, s.tainted?)
    y = Marshal.load(s)
    assert_equal(false, y.tainted?)
    assert_equal(false, y.first.tainted?)
    assert_equal(false, y.first.first.tainted?)

    # tainted stream causes tainted objects
    assert_equal(true, t.tainted?)
    y = Marshal.load(t)
    assert_equal(true, y.tainted?)
    assert_equal(true, y.first.tainted?)
    assert_equal(true, y.first.first.tainted?)

    # same tests by different senario
    s.taint
    assert_equal(true, s.tainted?)
    y = Marshal.load(s)
    assert_equal(true, y.tainted?)
    assert_equal(true, y.first.tainted?)
    assert_equal(true, y.first.first.tainted?)
  end
end