source: test/pyregfi-smoketest.py @ 262

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

changed regfi_conv_charset to handle memory allocation
tweaked test cases
corrected some documentation

  • Property svn:executable set to *
File size: 9.9 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            print(repr(path))
68            hive_iter = hive.subtree(path)
69            if hive_iter.current_key() != k:
70                print("WARNING: k != current_key for path '%s'." % path)
71            else:
72                i += 1
73        except Exception as e:
74            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path,e.args,e))
75    print("   Successfully tested paths on %d keys." % i)
76
77
78# Uses the HiveIterator to walk all keys
79# Gathers various (meaningless) statistics about data/data_raw attributes
80def iterTallyData(hive, fh):
81    data_stat = 0.0
82    dataraw_stat = 0.0
83   
84    for k in hive:
85        for v in k.values:
86            d = v.fetch_data()
87            if d == None:
88                data_stat += 0.1
89            elif hasattr(d, "__len__"):
90                data_stat += len(d)
91            else:
92                data_stat += d/2.0**64
93
94            d = v.fetch_raw_data()
95            if d == None:
96                dataraw_stat += 0.1
97            else:
98                dataraw_stat += len(d)
99
100    print("  Data stat: %f" % data_stat)
101    print("  Raw data stat: %f" % dataraw_stat)
102
103
104recurseKey_stat = 0.0
105recurseValue_stat = 0.0
106def checkValues(key):
107    global recurseKey_stat
108    global recurseValue_stat
109    recurseKey_stat += (key.mtime - key.max_bytes_subkeyname) * key.flags
110    for v in key.values:
111        recurseValue_stat += (v.data_off - v.data_size) / (1.0 + v.flags) + v.data_in_offset
112        try:
113            value = key.values[v.name]
114            if v != value:
115                print("WARNING: iterator value '%s' does not match dictionary value '%s'." 
116                      % (v.name, value.name))
117        except Exception as e:
118                print("WARNING: iterator value name '%s' is not retrievable via value list\n"
119                      % (v.name,))
120       
121
122def recurseTree(cur, operation):
123    for k in cur.subkeys:
124        key = cur.subkeys[k.name]
125        if k != key:
126            print("WARNING: iterator subkey '%s' does not match dictionary subkey '%s'." 
127                  % (k.name, key.name))
128        del key
129        operation(k)
130        recurseTree(k, operation)
131
132# Retrieves all keys by recursion, rather than the iterator, and validates
133# list dictionary access.  Also builds nonsensical statistics as an excuse
134# to access various base structure attributes.
135def recurseKeyTally(hive, fh):
136    checkValues(hive.root)
137    recurseTree(hive.root, checkValues)
138    print("  Key stat: %f" % recurseKey_stat)
139    print("  Value stat: %f" % recurseValue_stat)
140
141
142# Iterates hive gathering stats about security and classname records
143def iterFetchRelated(hive, fh):
144    security_stat = 0.0
145    classname_stat = 0.0
146    modified_stat = 0.0
147
148    for k in hive:
149        cn = k.fetch_classname()
150        if cn == None:
151            classname_stat += 0.000001
152        elif type(cn) == bytearray:
153            classname_stat += len(cn)/2**32
154        else:
155            classname_stat += len(cn)
156
157        modified_stat += k.modified
158       
159    print("  Security stat: %f" % security_stat)
160    print("  Classname stat: %f" % classname_stat)
161    print("  Modified stat: %f" % modified_stat)
162
163
164
165def iterIterWalk(hive, fh):
166    sk_stat = 0.0
167    v_stat = 0.0
168    iter = pyregfi.HiveIterator(hive)
169    for k in iter:
170        path = iter.current_path()
171        try:
172            hive_iter = hive.subtree(path[1:])
173            sk = hive_iter.first_subkey()
174            while sk != None:
175                ssk = hive_iter.find_subkey(sk.name)
176                if ssk != None:
177                    if ssk.name != None:
178                        sk_stat += len(ssk.name)
179                else:
180                    print("WARNING: ssk was None")
181                sk = hive_iter.next_subkey()
182
183            v = hive_iter.first_value()
184            while v != None:
185                vv = hive_iter.find_value(v.name)
186                if vv != None:
187                    if vv.name != None:
188                        v_stat += len(vv.name)
189                else:
190                    print("WARNING: vv was None")
191                v = hive_iter.next_value()
192
193        except Exception as e:
194            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path[1:],e.args,e))
195    print("   Subkey stat: %f" % sk_stat)
196    print("   Value stat: %f" % v_stat)
197
198
199def iterCallbackIO(hive, fh):
200    fh.seek(0)
201    new_fh = io.BytesIO(fh.read())
202    new_hive = pyregfi.Hive(new_fh)
203    for k in new_hive:
204        pass
205
206
207def threadIterMain(iter):
208    x = 0
209    try:
210        for k in iter:
211            #x += len(k.name) + len(k.subkeys)
212            pass
213    except Exception as e:
214        print("%s dying young: %s" % (threading.current_thread().name, repr(e)))
215        # Exceptions are thrown on iteration because python state gets out of
216        # whack.  That's fine, because we're really just interested in finding
217        # segfaults.  People should not use iterators without locks, but it
218        # should at least not segfault on them.
219        pass
220    print("%s finished" % threading.current_thread().name)
221
222def iterMultithread(hive, fh):
223    num_threads = 10
224    iter = pyregfi.HiveIterator(hive)
225    threads = []
226    for t in range(0,num_threads):
227        threads.append(threading.Thread(target=threadIterMain, args=(iter,)))
228    for t in threads:
229        t.start()
230    for t in threads:
231        t.join()
232
233
234def loopSecurity(hive, fh):
235    cur = hive.root.fetch_security()
236    while True:
237        stat += len(cur.descriptor.owner)
238        stat += len(cur.descriptor.group)
239        if cur.descriptor.sacl:
240            stat += len(cur.descriptor.sacl)
241        if cur.descriptor.dacl:
242            stat += len(cur.descriptor.dacl)
243       
244        nxt = cur.next_security()
245        if cur == nxt:
246            break
247
248   
249def iterSecurity(hive, fh):
250    stat = 0
251    for k in hive:
252        security = k.fetch_security()
253        stat += security.ref_count
254        stat += len(security.descriptor.owner)
255        stat += len(security.descriptor.group)
256        if security.descriptor.sacl:
257            for ace in security.descriptor.sacl:
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
264        if security.descriptor.dacl:
265            for ace in security.descriptor.dacl:
266                stat += ace.flags
267                if ace.object:
268                    stat += ace.object.int
269                if ace.inherited_object:
270                    stat += ace.inherited_object.int
271    print("  Security stat: %d" % stat)
272
273
274tests = {
275    "iterTallyNames":iterTallyNames,
276    "iterParentWalk":iterParentWalk,
277    "iterTallyData":iterTallyData,
278    "recurseKeyTally":recurseKeyTally,
279    "iterFetchRelated":iterFetchRelated,
280    "iterIterWalk":iterIterWalk,
281    "iterCallbackIO":iterCallbackIO,
282    "iterMultithread":iterMultithread,
283    "loopSecurity":loopSecurity,
284    "iterSecurity":iterSecurity,
285    }
286
287def usage():
288    sys.stderr.write("USAGE: pyregfi-smoketest.py { test1[,test2[,...]] | * } hive1 [hive2 ...]\n")
289    sys.stderr.write("\tAvailable tests:\n")
290    for t in tests.keys():
291        sys.stderr.write("\t\t%s\n" % t)
292
293
294if len(sys.argv) < 3:
295    usage()
296    sys.exit(1)
297
298if sys.argv[1] == '*':
299    selected_tests = tests.keys()
300else:
301    selected_tests = sys.argv[1].split(',')
302    for st in selected_tests:
303        if st not in tests:
304            usage()
305            sys.stderr.write("ERROR: %s not a valid test type\n\n" % st)
306            sys.exit(1)
307
308files = []
309for f in sys.argv[2:]:
310    files.append((f, open(f,"rb")))
311
312
313start_time = time.time()
314for hname,fh in files:
315    #hive = pyregfi.Hive(fh)
316    hive = pyregfi.openHive(hname)
317    for tname in selected_tests:
318        t = tests[tname]
319        teststart = time.time()
320        tstr = "'%s' on '%s'" % (tname,hname)
321        print("##BEGIN %s:" % tstr)
322        t(hive, fh)
323        print("##END %s; runtime=%f; messages:" % (tstr, time.time() - teststart))
324        print(pyregfi.getLogMessages())
325        print
326        sys.stdout.flush()
327    fh.close()
328
329hive = None
330files = None
331tests = None
332gc.collect()
333print("### Tests Completed, runtime: %f ###" % (time.time() -  start_time))
334#print(gc.garbage)
Note: See TracBrowser for help on using the repository browser.