Using high-level synthetic methods

This topic illustrates how to use some of the key features of high-level synthetic methods. For full details, see the Framework for Frameworks API classes and methods Javadoc™ documentation.

Creating a high-level synthetic method

To create a high-level synthetic method and add it to the F4FActions object actions, use code such as:

HighLevelSyntheticMethod m = HighLevelSyntheticMethod.make();
actions.addHighLevelSyntheticMethod(m);

You can specify the name, parameter types, and return type of the synthetic method by passing a VDB method signature to HighLevelSyntheticMethod.make().

Creating locals

A new local variable for a high-level synthetic method m can be created in this manner:

Local l = m.newLocal("java.lang.String");

Constructors need not be invoked in synthetic methods. Given the above code, one can assume that l refers to a non-null String object when adding further statements to the synthetic method.

Adding calls

Most statements in high-level synthetic methods will be method calls, added via the addCall() method. The parameters to addCall() represent the method to be invoked, file position information for the invocation, and parameters to be passed at the invocation. This is an example for adding a call to a setter method sample.BeanType.setName(), assuming an F4FApp object app:

Collection<IMethod> setterMethods =
   app.getClassMethods("sample.BeanType", "setName");
// assume there is exactly one "setName" method in BeanType
IMethod setter = setterMethods.iterator().next();
HighLevelSyntheticMethod m = HighLevelSyntheticMethod.make();
Local l = m.newLocal("sample.BeanType");
m.addCall(setter, null, l, Taint.taint());

Steps 2-5 of handling client form submission in an MVC architecture (as outlined in High-level synthetic methods) can all be modelled to some degree by adding appropriate calls to a synthetic method in the manner shown above.

The parameters for a call are represented by objects of type Param, which can be any one of:

  • A Local object, representing a local
  • A Taint object, representing untrusted or tainted data.
  • An EnclosingFormal object, representing a formal parameter of the high-level synthetic method. For example, if you have a synthetic method with signature synthMethod(int):void, EnclosingFormal.FIRST refers to the int parameter of the method.
  • A Global object representing a global (discussed in Globals).
Note: For non-static instance methods, the value to be passed as this must be provided to addCall(). In the above example, the value in l will be passed as this to setName().

Adding a return value

A synthetic method can return a value by using the setReturnedValue() method. Return values can be useful for generating marker methods to model complex framework validation. For example, if you are using a framework that performs complex validation of a tainted HTTP request value before passing it to the setter method of a model object, you can expose the validation on traces discovered by AppScan® Source by using code such as this:

String validatorSig =
   "Synth.validatorModel(java.lang.String):
   java.lang.String";
HighLevelSyntheticMethod validator =
   HighLevelSyntheticMethod.make(validatorSig);
// just return the parameter passed in
validator.setReturnedValue(EnclosingFormal.FIRST);
HighLevelSyntheticMethod m = ...;
Local validated = m.addCall(validatorSig, null, Taint.taint());
// now, validated can be passed to a setter

The synthetic method Synth.validatorModel() simply returns the String that is passed to it as a parameter. Then, a call to Synth.validatorModel() is added in another synthetic method, passing a tainted value as an argument. The result of this call is stored in validated, which can be passed in a subsequent call to a setter method (as illustrated by example in Adding calls). Traces involving this tainted data will include the call to Synth.validatorModel(), and an AppScan Source user can choose to filter the traces if the validation is deemed sufficient.

Globals

Globals are an advanced feature that can be used to expose flow between disparate parts of an application. For example, globals can be used to model the flow of data from a controller to a view via request or session attributes. The key operations for creating and accessing globals are:

  • To create a Global object representing a global, use F4FActions.createGlobal().
  • To write to a global, use HighLevelSyntheticMethod.addGlobalWrite().
  • To read from a global, pass the Global object as a Param parameter in a call to HighLevelSyntheticMethod.addCall() - or have it returned from a synthetic method via HighLevelSyntheticMethod.setReturnedValue().

Example: A controller class writes a user's first name to the request attribute firstName, and then the view reads this request attribute and renders the value to the response. At a high level, one could model this flow as:

Global firstNameGlobal = actions.createGlobal
   ("firstName", "java.lang.String", true);
HighLevelSyntheticMethod controller = ...;
Local firstNameLocal = controller.newLocal("java.lang.String");
controller.addGlobalWrite(firstNameGlobal, firstNameLocal, null);
HighLevelSyntheticMethod view = ...;
view.addCall("Response.write(java.lang.String):void",
   null, firstNameGlobal);

By adding a write to firstNameGlobal in the controller synthetic method and then passing firstNameGlobal to Response.write() in the view synthetic method, the data flow from controller to the view is exposed.

Note: This example contains many simplifications. Among other things, a full version would need to expose the proper flow of data to firstNameLocal.