source: test/pyregfi-smoketest.py @ 255

Last change on this file since 255 was 255, checked in by tim, 13 years ago

fixed error condition deadlock in regfi
prevented early garbage collection of hive file handles
fixed module imports under python3

  • Property svn:executable set to *
File size: 9.5 KB
Line 
1#!/usr/bin/env python3
2
3import sys
4import gc
5import io
6import time
7import threading
8import pyregfi
9
10
11
12pyregfi.setLogMask((pyregfi.LOG_TYPES.INFO, pyregfi.LOG_TYPES.WARN, pyregfi.LOG_TYPES.ERROR))
13
14# Uses the HiveIterator to walk all keys
15# Gathers various (meaningless) statistics to exercise simple attribute access
16# and to hopefully smoke out any bugs that can be identified by changing stats
17def iterTallyNames(hive, fh):
18    key_count = 0
19    key_lens = 0
20    key_rawlens = 0
21    value_count = 0
22    value_lens = 0
23    value_rawlens = 0
24
25    for k in hive:
26        key_count += 1
27        if k.name != None:
28            key_lens += len(k.name)
29        if k.name_raw != None:
30            key_rawlens += len(k.name_raw)
31
32        for v in k.values:
33            value_count += 1
34            if v.name != None:
35                value_lens += len(v.name)
36            if v.name_raw != None:
37                value_rawlens += len(v.name_raw)
38
39    print("  Counts: keys=%d, values=%d" % (key_count, value_count))
40    print("  Total name length: keys=%d, values=%d" % (key_lens, value_lens))
41    print("  Total raw name lengths: keys=%d, values=%d" % (key_rawlens, value_rawlens))
42
43
44# walks up parents to obtain path, rather than using downward links like iterator
45def getCurrentPath(key):
46    if key == None:
47        return ''
48    path = []
49    p = key
50    while p != None:
51        path.append(p.name)
52        p = p.get_parent()
53    path.reverse()
54    del path[0]
55
56    return path
57
58# For each key in the hive, this traverses the parent links up to the root,
59# recording the path as it goes, and then uses the subtree/descend method
60# to find the same key again, verifying it is the same.  This test is currently
61# very slow because no key caching is used.
62def iterParentWalk(hive, fh):
63    i = 1
64    for k in hive:
65        path = getCurrentPath(k)
66        try:
67            hive_iter = hive.subtree(path)
68            if hive_iter.current_key() != k:
69                print("WARNING: k != current_key for path '%s'." % path)
70            else:
71                i += 1
72        except Exception as e:
73            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path,e.args,e))
74    print("   Successfully tested paths on %d keys." % i)
75
76
77# Uses the HiveIterator to walk all keys
78# Gathers various (meaningless) statistics about data/data_raw attributes
79def iterTallyData(hive, fh):
80    data_stat = 0.0
81    dataraw_stat = 0.0
82   
83    for k in hive:
84        for v in k.values:
85            d = v.fetch_data()
86            if d == None:
87                data_stat += 0.1
88            elif hasattr(d, "__len__"):
89                data_stat += len(d)
90            else:
91                data_stat += d/2.0**64
92
93            d = v.fetch_raw_data()
94            if d == None:
95                dataraw_stat += 0.1
96            else:
97                dataraw_stat += len(d)
98
99    print("  Data stat: %f" % data_stat)
100    print("  Raw data stat: %f" % dataraw_stat)
101
102
103recurseKey_stat = 0.0
104recurseValue_stat = 0.0
105def checkValues(key):
106    global recurseKey_stat
107    global recurseValue_stat
108    recurseKey_stat += (key.mtime - key.max_bytes_subkeyname) * key.flags
109    for v in key.values:
110        recurseValue_stat += (v.data_off - v.data_size) / (1.0 + v.flags) + v.data_in_offset
111        try:
112            value = key.values[v.name]
113            if v != value:
114                print("WARNING: iterator value '%s' does not match dictionary value '%s'." 
115                      % (v.name, value.name))
116        except Exception as e:
117                print("WARNING: iterator value name '%s' is not retrievable via value list\n"
118                      % (v.name,))
119       
120
121def recurseTree(cur, operation):
122    for k in cur.subkeys:
123        key = cur.subkeys[k.name]
124        if k != key:
125            print("WARNING: iterator subkey '%s' does not match dictionary subkey '%s'." 
126                  % (k.name, key.name))
127        del key
128        operation(k)
129        recurseTree(k, operation)
130
131# Retrieves all keys by recursion, rather than the iterator, and validates
132# list dictionary access.  Also builds nonsensical statistics as an excuse
133# to access various base structure attributes.
134def recurseKeyTally(hive, fh):
135    checkValues(hive.root)
136    recurseTree(hive.root, checkValues)
137    print("  Key stat: %f" % recurseKey_stat)
138    print("  Value stat: %f" % recurseValue_stat)
139
140
141# Iterates hive gathering stats about security and classname records
142def iterFetchRelated(hive, fh):
143    security_stat = 0.0
144    classname_stat = 0.0
145    modified_stat = 0.0
146
147    for k in hive:
148        cn = k.fetch_classname()
149        if cn == None:
150            classname_stat += 0.000001
151        elif type(cn) == bytearray:
152            classname_stat += len(cn)/2**32
153        else:
154            classname_stat += len(cn)
155
156        modified_stat += k.modified
157       
158    print("  Security stat: %f" % security_stat)
159    print("  Classname stat: %f" % classname_stat)
160    print("  Modified stat: %f" % modified_stat)
161
162
163
164def iterIterWalk(hive, fh):
165    sk_stat = 0.0
166    v_stat = 0.0
167    iter = pyregfi.HiveIterator(hive)
168    for k in iter:
169        path = iter.current_path()
170        try:
171            hive_iter = hive.subtree(path[1:])
172            sk = hive_iter.first_subkey()
173            while sk != None:
174                ssk = hive_iter.find_subkey(sk.name)
175                if ssk != None:
176                    sk_stat += len(ssk.name)
177                else:
178                    print("WARNING: ssk was None")
179                sk = hive_iter.next_subkey()
180
181            v = hive_iter.first_value()
182            while v != None:
183                vv = hive_iter.find_value(v.name)
184                if vv != None:
185                    v_stat += len(vv.name)
186                else:
187                    print("WARNING: vv was None")
188                v = hive_iter.next_value()
189
190        except Exception as e:
191            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path[1:],e.args,e))
192    print("   Subkey stat: %f" % sk_stat)
193    print("   Value stat: %f" % v_stat)
194
195
196def iterCallbackIO(hive, fh):
197    fh.seek(0)
198    new_fh = io.BytesIO(fh.read())
199    new_hive = pyregfi.Hive(new_fh)
200    for k in new_hive:
201        pass
202
203
204def threadIterMain(iter):
205    x = 0
206    try:
207        for k in iter:
208            #x += len(k.name) + len(k.subkeys)
209            pass
210    except Exception as e:
211        print("%s dying young: %s" % (threading.current_thread().name, repr(e)))
212        # Exceptions are thrown on iteration because python state gets out of
213        # whack.  That's fine, because we're really just interested in finding
214        # segfaults.  People should not use iterators without locks, but it
215        # should at least not segfault on them.
216        pass
217    print("%s finished" % threading.current_thread().name)
218
219def iterMultithread(hive, fh):
220    num_threads = 10
221    iter = pyregfi.HiveIterator(hive)
222    threads = []
223    for t in range(0,num_threads):
224        threads.append(threading.Thread(target=threadIterMain, args=(iter,)))
225    for t in threads:
226        t.start()
227    for t in threads:
228        t.join()
229
230
231def loopSecurity(hive, fh):
232    start = hive.root.fetch_security()
233    print(start.descriptor.group)
234    cur = start.next_security()
235
236    while cur != start:
237        print(start.descriptor.group)
238        cur = cur.next_security()
239
240   
241def iterSecurity(hive, fh):
242    stat = 0
243    for k in hive:
244        security = k.fetch_security()
245        stat += security.ref_count
246        stat += len(security.descriptor.owner)
247        stat += len(security.descriptor.group)
248        if security.descriptor.sacl:
249            for ace in security.descriptor.sacl:
250                stat += ace.flags
251                if ace.object:
252                    stat += ace.object.int
253                if ace.inherited_object:
254                    stat += ace.inherited_object.int
255
256        if security.descriptor.dacl:
257            for ace in security.descriptor.dacl:
258                stat += ace.flags
259                if ace.object:
260                    stat += ace.object.int
261                if ace.inherited_object:
262                    stat += ace.inherited_object.int
263    print("  Security stat: %d" % stat)
264
265
266tests = {
267    "iterTallyNames":iterTallyNames,
268    "iterParentWalk":iterParentWalk,
269    "iterTallyData":iterTallyData,
270    "recurseKeyTally":recurseKeyTally,
271    "iterFetchRelated":iterFetchRelated,
272    "iterIterWalk":iterIterWalk,
273    "iterCallbackIO":iterCallbackIO,
274    "iterMultithread":iterMultithread,
275    "loopSecurity":loopSecurity,
276    "iterSecurity":iterSecurity,
277    }
278
279def usage():
280    sys.stderr.write("USAGE: pyregfi-smoketest.py test1[,test2[,...]] hive1 [hive2 ...]\n")
281    sys.stderr.write("\tAvailable tests:\n")
282    for t in tests.keys():
283        sys.stderr.write("\t\t%s\n" % t)
284
285
286if len(sys.argv) < 3:
287    usage()
288    sys.exit(1)
289
290selected_tests = sys.argv[1].split(',')
291for st in selected_tests:
292    if st not in tests:
293        usage()
294        sys.stderr.write("ERROR: %s not a valid test type\n\n" % st)
295        sys.exit(1)
296
297files = []
298for f in sys.argv[2:]:
299    files.append((f, open(f,"rb")))
300
301
302start_time = time.time()
303for hname,fh in files:
304    #hive = pyregfi.Hive(fh)
305    hive = pyregfi.openHive(hname)
306    for tname in selected_tests:
307        t = tests[tname]
308        teststart = time.time()
309        tstr = "'%s' on '%s'" % (tname,hname)
310        print("##BEGIN %s:" % tstr)
311        t(hive, fh)
312        print("##END %s; runtime=%f; messages:" % (tstr, time.time() - teststart))
313        print(pyregfi.getLogMessages())
314        print
315        sys.stdout.flush()
316    fh.close()
317
318hive = None
319files = None
320tests = None
321gc.collect()
322print("### Tests Completed, runtime: %f ###" % (time.time() -  start_time))
323#print(gc.garbage)
Note: See TracBrowser for help on using the repository browser.