Package Peach :: Module group
[hide private]

Source Code for Module Peach.group

  1   
  2  ''' 
  3  Default included Group implementations. 
  4   
  5  @author: Michael Eddington 
  6  @version: $Id: Peach.group-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $ 
  7  ''' 
  8   
  9  # 
 10  # Copyright (c) 2005-2007 Michael Eddington 
 11  # Copyright (c) 2004-2005 IOActive Inc. 
 12  # 
 13  # Permission is hereby granted, free of charge, to any person obtaining a copy  
 14  # of this software and associated documentation files (the "Software"), to deal 
 15  # in the Software without restriction, including without limitation the rights  
 16  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
 17  # copies of the Software, and to permit persons to whom the Software is  
 18  # furnished to do so, subject to the following conditions: 
 19  # 
 20  # The above copyright notice and this permission notice shall be included in     
 21  # all copies or substantial portions of the Software. 
 22  # 
 23  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
 24  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
 25  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
 26  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 27  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 28  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 29  # SOFTWARE. 
 30  # 
 31   
 32  # Authors: 
 33  #   Michael Eddington (mike@phed.org) 
 34   
 35  # $Id: Peach.group-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $ 
 36   
 37  import sys, traceback 
 38  from Peach import generator 
 39   
 40  #__all__ = ["Group", "GroupFixed", "GroupSequence", "GroupForeachDo"] 
 41   
42 -class Group:
43 ''' 44 Groups allow for performing a C{next()} call on a specific set of 45 Generators allowing for more complex Fuzzing setups. This default group 46 object will iterate an infinit amount of times. 47 48 Group objects implement the iterator protocol. 49 ''' 50 51 _name = None 52 _generators = [] 53 _identity = "" 54
55 - def __init__(self, name = None):
56 ''' 57 Create a new Group object. 58 59 @type name: string 60 @param name: Name of Group object. Not currently used. 61 ''' 62 self._name = name 63 self._generators = [] 64 65 # For debugging. This is slow (0.02 sec), if things are slow 66 # you can comment this line out safely. 67 self._identity = traceback.format_stack()
68
69 - def getName(self):
70 ''' 71 Get current name of Group. Not currently used. 72 73 @rtype: string 74 @return: name of Group 75 ''' 76 return self._name
77 - def setName(self, name):
78 ''' 79 Set name of Group. Not currently used. 80 81 @type name: string 82 @param name: Name of Group 83 ''' 84 self._name = name
85
86 - def addGenerator(self, gen):
87 ''' 88 Add Generator to Group. This should almost never be called 89 directly. Generators will call this when you set there Group. 90 However, you can do some crazy stuff by adding a Generator into 91 multiple Groups so they iterate themselves in strange ways. 92 93 @type gen: Generator 94 @param gen: Generator to add 95 ''' 96 self._generators.append(gen)
97
98 - def addGenerators(self, gens):
99 ''' 100 Add Generators to Group. This should almost never be called 101 directly. Generators will call this when you set there Group. 102 However, you can do some crazy stuff by adding a Generator into 103 multiple Groups so they iterate themselves in strange ways. 104 105 @type gens: Array of Generators 106 @param gens: Generatorsto add 107 ''' 108 for g in gens: 109 self._generators.append(g)
110
111 - def removeGenerator(self, gen):
112 ''' 113 Remove Generator from Group. 114 115 @type gen: Generator 116 @param gen: Generator to remove 117 ''' 118 self._generators.remove(gen)
119
120 - def getAllGenerators(self):
121 ''' 122 Returns list of all generators in Group. This is a reference 123 to our internal list so any changes will also affect the Group. 124 125 @rtype: Array 126 @return: Returns Array of strings 127 ''' 128 return self._generators
129
130 - def __iter__(self):
131 return self
132
133 - def next(self):
134 ''' 135 Iterate all Generators to next value. 136 137 From Python docs on next(): 138 139 I{The intention of the protocol is that once an iterator's next() method 140 raises StopIteration, it will continue to do so on subsequent calls. 141 Implementations that do not obey this property are deemed broken. (This 142 constraint was added in Python 2.3; in Python 2.2, various iterators are 143 broken according to this rule.)} 144 145 For Groups, please use the GroupCompleted exception instead of 146 StopIteration (its a subclass). 147 ''' 148 149 # We will continue until all of our generators are 150 # returning GeneratorCompleted exceptions 151 152 if len(self._generators) < 1: 153 print "Identity of Group: ", self._identity 154 raise Exception("Error: Group does not contain any generators. This is probably not a good thing.") 155 156 done = 1 157 158 for i in range(len(self._generators)): 159 try: 160 self._generators[i].next() 161 done = 0 162 except generator.GeneratorCompleted: 163 pass 164 165 if done == 1: 166 raise GroupCompleted()
167
168 - def reset(self):
169 ''' 170 Resets all Generators to there initial state. 171 ''' 172 for i in self._generators: 173 i.reset()
174 175
176 -class GroupCompleted(StopIteration):
177 ''' 178 Raised when group has completed all iterations. This exception is a 179 sub class of StopIteration. 180 ''' 181 pass
182 183
184 -class GroupSequence(Group):
185 ''' 186 A sequence of groups. Each group will be iterated until they are 187 completed in sequence. 188 189 This is also a container type and can be used as such to gain 190 access to the contained groups. 191 192 HINT: If groups param is an integer it will create an array of 193 Group() objects of that length that can be accessed using 194 the array specifier groupSequence[x]. 195 ''' 196
197 - def __init__(self, groups = None, name = None):
198 ''' 199 Create a GroupSequence object. 200 201 @type groups: list 202 @param groups: Optional list of Groups to use 203 ''' 204 205 self._slackerCount = 0 206 207 if name is None: 208 self._name = "" 209 else: 210 self._name = name 211 212 self._generators = [] 213 214 # Hack allert! 215 if str(type(groups)) == "<type 'int'>": 216 self._groups = [] 217 for i in range(groups): 218 self._groups.append(Group()) 219 220 elif groups != None: 221 self._groups = groups 222 223 else: 224 self._groups = [] 225 self._position = 0 226 self._count = 1
227
228 - def getNextGroup(self):
229 ''' 230 This is a function for slackers that allows access to the next group 231 without having to specify an index. 232 233 @rtype: Group 234 @return: Returns the next Group in the list 235 ''' 236 if self._slackerCount >= len(self._groups): 237 raise Exception("GroupSequence: getNextGroup() ran past end of array.") 238 self._slackerCount += 1 239 return self._groups[self._slackerCount -1]
240
241 - def addNewGroup(self, newGroup = None):
242 ''' 243 Will add a new Group to sequence of groups and then return that group. 244 245 @type newGroup: Group 246 @param newGroup: [optional] Group to append, or if not given add Group() 247 @rtype: Group 248 @return: Returns appended Group 249 ''' 250 if newGroup == None: 251 newGroup = Group() 252 253 self._groups.append(newGroup) 254 return newGroup
255
256 - def append(self, group = None):
257 ''' 258 Append a Group. 259 260 @type group: Group 261 @param group: Group to append 262 @rtype: Group 263 @return: Returns appended Group 264 ''' 265 return self.addNewGroup(group)
266
267 - def remove(self, group):
268 ''' 269 Remove a Group. 270 271 @type group: Group 272 @param group: Group to remove 273 ''' 274 self._groups.remove(group)
275
276 - def next(self):
277 if self._position < len(self._groups): 278 try: 279 self._groups[self._position].next() 280 self._count += 1 281 except GroupCompleted: 282 #sys.stderr.write('%s: GroupSequence.next(): GroupCompleted [%d]\n' % (self._name, self._count)) 283 self._count = 1 284 self._groups[self._position].reset() 285 self._position += 1 286 if self._position >= len(self._groups): 287 raise GroupCompleted() 288 else: 289 raise GroupCompleted()
290
291 - def reset(self):
292 for group in self._groups: 293 group.reset(); 294 self._position = 0
295 296 297 # Container emulation methods ############################ 298
299 - def __len__(self):
300 return self._groups.__len__()
301 - def __getitem__(self, key):
302 return self._groups.__getitem__(key)
303 - def __setitem__(self, key, value):
304 return self._groups.__setitem(key, value)
305 - def __delitem__(self, key):
306 return self._groups.__delitem__(key)
307 - def __iter__(self):
308 return self._groups.__iter__()
309 - def __contains__(self, item):
310 return self._groups.__contains__(item)
311 312 import inspect, pyclbr, random 313
314 -class GroupForever(Group):
315 ''' 316 This group will take a GroupSequence and perform random mutations 317 on how generators are incremented. This group understands that a 318 GroupSequence can have other GroupSequences in it. 319 ''' 320
321 - def __init__(self, groupSequence):
322 323 self.groupSequence = groupSequence 324 self.groups = self._findAllGroups(groupSequence) 325 self.count = len(self.groups) 326 327 self._resetAll() 328 self._pickStuff()
329
330 - def addGroup(self, group):
331 self.groups.append(group) 332 333 for g in self._findAllGroups(group): 334 self.groups.append(g)
335
336 - def _resetAll(self):
337 338 print "len: %d" % len(self.groups) 339 for group in self.groups: 340 group.reset()
341
342 - def _pickStuff(self):
343 '''Pick some groups to play with 344 ''' 345 346 # Types of mutations 347 # 348 # 1. Bunch at once 349 # 2. A for each 350 351 type = random.randint(0, 1) 352 353 if type == 0: 354 # bunch at once 355 groupsDo = [] 356 picks = random.sample(xrange(self.count), random.randint(0, self.count-1)) 357 for pick in picks: 358 groupsDo.append(self.groups[pick]) 359 360 self.currentGroup = GroupSequence(groupsDo, "GroupForever") 361 362 elif type == 1: 363 # a for each 364 groupEach = groupFor = self.groups[ random.randint(0, self.count-1) ] 365 groupsDo = [] 366 367 picks = random.sample(xrange(self.count), random.randint(0, self.count-1)) 368 for pick in picks: 369 groupsDo.append(self.groups[pick]) 370 371 try: 372 groupsDo.remove(groupEach) 373 except: 374 pass 375 376 groupDo = GroupSequence(groupsDo, "GroupForever") 377 378 self.currentGroup = GroupForeachDo(groupEach, groupDo) 379 380 else: 381 raise Exception("GroupForever._pickStuff(): Should not be here!!") 382 383 self.isCompleted = False
384
385 - def _findAllGroups(self, groupSequence):
386 387 if hasattr(groupSequence, 'next') and hasattr(groupSequence, '__iter__'): 388 groups = [] 389 390 for group in groupSequence: 391 if group == None: 392 continue 393 394 groups.append(group) 395 396 if hasattr(group, 'next') and hasattr(group, '__iter__'): 397 for g in self._findAllGroups(group): 398 if g == None: 399 continue 400 401 groups.append(g) 402 403 return groups 404 405 if hasattr(groupSequence, "getForeachGroup"): 406 return [group.getForeachGroup(), group.getDoGroup()] 407 408 return []
409
410 - def next(self):
411 412 try: 413 self.currentGroup.next() 414 except GroupCompleted: 415 self._resetAll() 416 self._pickStuff()
417
418 - def reset(self):
419 self._resetAll() 420 self._pickStuff()
421 422
423 -class GroupFixed(Group):
424 ''' 425 Group object with a fixed number of iterations. 426 ''' 427 428 _max = 0 429 _current = 0 430
431 - def __init__(self, maxIterations = 0):
432 ''' 433 Create GroupFixed object. 434 435 @type maxIterations: number 436 @param maxIterations: Maximum number of iterations. 437 ''' 438 self._max = maxIterations 439 Group.__init__(self)
440
441 - def getMaxIterations(self):
442 ''' 443 Get the maximum iterations to perform. 444 445 @rtype: number 446 @return the maximum iterations 447 ''' 448 return self._max
449 - def setMaxIterations(self, maxIterations):
450 ''' 451 Set the maximum iterations to perform. 452 453 @type maxIterations: number 454 @param maxIterations: Maximum number of iterations. 455 ''' 456 self._max = maxIterations
457
458 - def next(self):
459 if self._current < self._max: 460 self._current += 1 461 try: 462 Group.next(self) 463 except generator.GeneratorCompleted: 464 raise GroupCompleted("Peach.group.GroupFixed") 465 else: 466 raise GroupCompleted("Peach.group.GroupFixed")
467 468
469 -class GroupForeachDo(Group):
470 ''' 471 Foreach iteration of group A do group B 472 ''' 473 474 #_groupA = None 475 #_groupB = None 476
477 - def __init__(self, groupA, groupB, verbose = True, name = ""):
478 ''' 479 Foreach interation of group A do group B 480 481 @type groupA: Group 482 @param groupA: The for each of group 483 @type groupB: Group 484 @param groupB: The Do group 485 @type verbose: Boolean 486 @param verbose: [optional] Control printing of group completed message, enabled by default. 487 ''' 488 self._generators = [] 489 self._groupA = groupA 490 self._groupB = groupB 491 self._count = 1 492 self._name = name 493 self._verbose = verbose 494 self._isCompleted = False
495
496 - def next(self):
497 498 if self._isCompleted: 499 raise GroupCompleted("We are done") 500 501 try: 502 self._groupB.next() 503 self._count += 1 504 except GroupCompleted: 505 if self._verbose: 506 print "%s: GroupForeachDo.GroupCompleted -- [%d]" % (self._name, self._count) 507 508 self._count = 1 509 self._groupB.reset() 510 511 try: 512 self._groupA.next() 513 except GroupCompleted: 514 self._isCompleted = True
515
516 - def reset(self):
517 self._groupA.reset() 518 self._groupB.reset() 519 self._count = 1 520 self._isCompleted = False
521
522 - def getForeachGroup(self):
523 ''' 524 Returns the For each group 525 ''' 526 return self._groupA
527
528 - def getDoGroup(self):
529 ''' 530 Returns the Do group 531 ''' 532 return self._groupB
533 534 535 536 # end 537