source: test/pyregfi-smoketest.py @ 252

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

updated pyregfi to work with regfi changes
renamed some functions for more clarity
fixed some issues related to talloc_reference

  • Property svn:executable set to *
File size: 8.2 KB
RevLine 
[213]1#!/usr/bin/env python3
[197]2
3import sys
[213]4import gc
[225]5import io
[215]6import time
[228]7import threading
[197]8import pyregfi
9
[225]10
[197]11
[232]12pyregfi.setLogMask((pyregfi.LOG_TYPES.INFO, pyregfi.LOG_TYPES.WARN, pyregfi.LOG_TYPES.ERROR))
[197]13
[213]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
[225]17def iterTallyNames(hive, fh):
[213]18    key_count = 0
19    key_lens = 0
20    key_rawlens = 0
21    value_count = 0
22    value_lens = 0
23    value_rawlens = 0
[197]24
[213]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)
[199]31
[213]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)
[200]38
[214]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))
[200]42
[209]43
[252]44# walks up parents to obtain path, rather than using downward links like iterator
[220]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
[215]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.
[225]62def iterParentWalk(hive, fh):
[215]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:
[252]73            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path,e.args,e))
[215]74    print("   Successfully tested paths on %d keys." % i)
[209]75
[215]76
[216]77# Uses the HiveIterator to walk all keys
78# Gathers various (meaningless) statistics about data/data_raw attributes
[225]79def iterTallyData(hive, fh):
[216]80    data_stat = 0.0
81    dataraw_stat = 0.0
82   
83    for k in hive:
84        for v in k.values:
[219]85            d = v.fetch_data()
[216]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
[219]93            d = v.fetch_raw_data()
[216]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
[217]103recurseKey_stat = 0.0
104recurseValue_stat = 0.0
105def checkValues(key):
106    global recurseKey_stat
107    global recurseValue_stat
108    recurseKey_stat += (key.mtime.low^key.mtime.high - 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        value = key.values[v.name]
112        if v != value:
113            print("WARNING: iterator value '%s' does not match dictionary value '%s'." 
114                  % (v.name, value.name))
[216]115
[217]116def recurseTree(cur, operation):
117    for k in cur.subkeys:
118        key = cur.subkeys[k.name]
119        if k != key:
120            print("WARNING: iterator subkey '%s' does not match dictionary subkey '%s'." 
121                  % (k.name, key.name))
122        del key
123        operation(k)
124        recurseTree(k, operation)
125
126# Retrieves all keys by recursion, rather than the iterator, and validates
127# list dictionary access.  Also builds nonsensical statistics as an excuse
128# to access various base structure attributes.
[225]129def recurseKeyTally(hive, fh):
[218]130    checkValues(hive.root)
131    recurseTree(hive.root, checkValues)
[217]132    print("  Key stat: %f" % recurseKey_stat)
133    print("  Value stat: %f" % recurseValue_stat)
134
135
[219]136# Iterates hive gathering stats about security and classname records
[225]137def iterFetchRelated(hive, fh):
[219]138    security_stat = 0.0
139    classname_stat = 0.0
140    modified_stat = 0.0
141
142    for k in hive:
143        cn = k.fetch_classname()
144        if cn == None:
145            classname_stat += 0.000001
146        elif type(cn) == bytearray:
147            classname_stat += len(cn)/2**32
148        else:
149            classname_stat += len(cn)
150
151        modified_stat += k.modified
152       
153    print("  Security stat: %f" % security_stat)
154    print("  Classname stat: %f" % classname_stat)
155    print("  Modified stat: %f" % modified_stat)
156
[220]157
158
[225]159def iterIterWalk(hive, fh):
[220]160    sk_stat = 0.0
161    v_stat = 0.0
162    iter = pyregfi.HiveIterator(hive)
163    for k in iter:
[252]164        path = iter.current_path()
[220]165        try:
[252]166            hive_iter = hive.subtree(path[1:])
[220]167            sk = hive_iter.first_subkey()
168            while sk != None:
169                ssk = hive_iter.find_subkey(sk.name)
[252]170                if ssk != None:
171                    sk_stat += len(ssk.name)
172                else:
173                    print("WARNING: ssk was None")
[220]174                sk = hive_iter.next_subkey()
175
176            v = hive_iter.first_value()
177            while v != None:
178                vv = hive_iter.find_value(v.name)
[252]179                if vv != None:
180                    v_stat += len(vv.name)
181                else:
182                    print("WARNING: vv was None")
[220]183                v = hive_iter.next_value()
184
185        except Exception as e:
[252]186            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path[1:],e.args,e))
[220]187    print("   Subkey stat: %f" % sk_stat)
188    print("   Value stat: %f" % v_stat)
189
190
[225]191def iterCallbackIO(hive, fh):
192    fh.seek(0)
193    new_fh = io.BytesIO(fh.read())
194    new_hive = pyregfi.Hive(new_fh)
195    for k in new_hive:
196        pass
[220]197
[228]198
199def threadIterMain(iter):
200    x = 0
201    try:
202        for k in iter:
203            #x += len(k.name) + len(k.subkeys)
204            pass
205    except Exception as e:
206        print("%s dying young: %s" % (threading.current_thread().name, repr(e)))
207        # Exceptions are thrown on iteration because python state gets out of
208        # whack.  That's fine, because we're really just interested in finding
209        # segfaults.  People should not use iterators without locks, but it
210        # should at least not segfault on them.
211        pass
212    print("%s finished" % threading.current_thread().name)
213
214def iterMultithread(hive, fh):
215    num_threads = 10
216    iter = pyregfi.HiveIterator(hive)
217    threads = []
218    for t in range(0,num_threads):
219        threads.append(threading.Thread(target=threadIterMain, args=(iter,)))
220    for t in threads:
221        t.start()
222    for t in threads:
223        t.join()
224   
225
[227]226tests = {
227    "iterTallyNames":iterTallyNames,
228    "iterParentWalk":iterParentWalk,
229    "iterTallyData":iterTallyData,
230    "recurseKeyTally":recurseKeyTally,
231    "iterFetchRelated":iterFetchRelated,
232    "iterIterWalk":iterIterWalk,
233    "iterCallbackIO":iterCallbackIO,
[228]234    "iterMultithread":iterMultithread,
[227]235    }
[209]236
[227]237def usage():
238    sys.stderr.write("USAGE: pyregfi-smoketest.py test1[,test2[,...]] hive1 [hive2 ...]\n")
239    sys.stderr.write("\tAvailable tests:\n")
240    for t in tests.keys():
241        sys.stderr.write("\t\t%s\n" % t)
[215]242
243
[227]244if len(sys.argv) < 3:
245    usage()
246    sys.exit(1)
[220]247
[227]248selected_tests = sys.argv[1].split(',')
249for st in selected_tests:
250    if st not in tests:
251        usage()
252        sys.stderr.write("ERROR: %s not a valid test type" % st)
253        sys.exit(1)
[220]254
[213]255files = []
[227]256for f in sys.argv[2:]:
[224]257    files.append((f, open(f,"rb")))
[213]258
259
[215]260start_time = time.time()
[213]261for hname,fh in files:
262    hive = pyregfi.Hive(fh)
[227]263    for tname in selected_tests:
264        t = tests[tname]
[215]265        teststart = time.time()
[213]266        tstr = "'%s' on '%s'" % (tname,hname)
267        print("##BEGIN %s:" % tstr)
[225]268        t(hive, fh)
[215]269        print("##END %s; runtime=%f; messages:" % (tstr, time.time() - teststart))
[232]270        print(pyregfi.getLogMessages())
[213]271        print
[215]272        sys.stdout.flush()
[224]273    fh.close()
[213]274
[215]275hive = None
[213]276files = None
277tests = None
278gc.collect()
[215]279print("### Tests Completed, runtime: %f ###" % (time.time() -  start_time))
[214]280#print(gc.garbage)
Note: See TracBrowser for help on using the repository browser.