3 import Analysis.Disjoint.HeapAnalysis;
4 import Analysis.Disjoint.Alloc;
11 // This BuildCode Extension (BCX) takes a heap analysis
12 // with points-to information and generates checks at runtime
13 // verifies the allocation site of objects pointed-to. It
14 // doesn't fully verify an analysis but it can reveal bugs!
17 public class BCXPointsToCheckVRuntime implements BuildCodeExtension {
19 protected BuildCode buildCode;
20 protected TypeUtil typeUtil;
21 protected HeapAnalysis heapAnalysis;
23 protected ClassDescriptor cdObject;
26 public BCXPointsToCheckVRuntime( BuildCode buildCode,
28 HeapAnalysis heapAnalysis ) {
29 this.buildCode = buildCode;
30 this.typeUtil = typeUtil;
31 this.heapAnalysis = heapAnalysis;
35 public void additionalIncludesMethodsHeader(PrintWriter outmethodheader) {
36 outmethodheader.println( "#include<stdio.h>" );
37 outmethodheader.println( "#include<execinfo.h>" );
41 public void additionalCodeAtTopFlatMethodBody(PrintWriter output, FlatMethod fm) {
43 for( int i = 0; i < fm.numParameters(); ++i ) {
44 TempDescriptor td = fm.getParameter( i );
45 TypeDescriptor type = td.getType();
47 genAssertRuntimePtrVsHeapResults( output,
50 heapAnalysis.canPointToAfter( td, fm )
57 public void additionalCodePreNode(FlatMethod fm, FlatNode fn, PrintWriter output) {
68 case FKind.FlatOpNode: {
69 FlatOpNode fon = (FlatOpNode) fn;
70 if( fon.getOp().getOp() == Operation.ASSIGN ) {
76 genAssertRuntimePtrVsHeapResults( output,
79 heapAnalysis.canPointToAt( lhs, fn )
82 genAssertRuntimePtrVsHeapResults( output,
85 heapAnalysis.canPointToAt( rhs, fn )
92 case FKind.FlatCastNode: {
93 FlatCastNode fcn = (FlatCastNode) fn;
99 genAssertRuntimePtrVsHeapResults( output,
102 heapAnalysis.canPointToAt( lhs, fn )
105 genAssertRuntimePtrVsHeapResults( output,
108 heapAnalysis.canPointToAt( rhs, fn )
114 case FKind.FlatFieldNode: {
115 FlatFieldNode ffn = (FlatFieldNode) fn;
118 fld = ffn.getField();
120 type = lhs.getType();
122 genAssertRuntimePtrVsHeapResults( output,
125 heapAnalysis.canPointToAt( lhs, fn )
128 genAssertRuntimePtrVsHeapResults( output,
131 heapAnalysis.canPointToAt( rhs, fn )
134 genAssertRuntimePtrVsHeapResults( output,
139 heapAnalysis.canPointToAt( rhs, fld, fn )
145 case FKind.FlatElementNode: {
146 FlatElementNode fen = (FlatElementNode) fn;
149 idx = fen.getIndex();
151 type = lhs.getType();
153 genAssertRuntimePtrVsHeapResults( output,
156 heapAnalysis.canPointToAt( lhs, fn )
159 genAssertRuntimePtrVsHeapResults( output,
162 heapAnalysis.canPointToAt( rhs, fn )
165 genAssertRuntimePtrVsHeapResults( output,
170 heapAnalysis.canPointToAtElement( rhs, fn )
180 public void additionalCodePostNode(FlatMethod fm,
182 PrintWriter output) {
183 switch( fn.kind() ) {
184 case FKind.FlatCall: {
185 FlatCall fc = (FlatCall) fn;
186 TempDescriptor td = fc.getReturnTemp();
189 TypeDescriptor type = td.getType();
191 genAssertRuntimePtrVsHeapResults( output,
194 heapAnalysis.canPointToAfter( td, fn )
205 printConditionFailed( PrintWriter output,
209 // don't do this in the constructor of this extension object because
210 // build code hasn't created any types or classes yet!
211 if( cdObject == null ) {
212 cdObject = typeUtil.getClass( typeUtil.ObjectClass );
213 assert cdObject != null;
216 output.println( "printf(\"[[[ CHECK VS HEAP RESULTS FAILED ]]] Condition for failure( "+
217 condition+" ) allocsite=%d at %s:%d\\n\", ((struct "+
218 cdObject.getSafeSymbol()+"*)"+
219 pointer+")->allocsite, __FILE__, __LINE__ );" );
221 // spit out the stack trace (so fancy!)
222 output.println( "{" );
223 output.println( "void* buffer[100];" );
224 output.println( "char** strings;" );
225 output.println( "int nptrs,j;" );
226 output.println( "nptrs = backtrace(buffer, 100);" );
227 output.println( "strings = backtrace_symbols(buffer, nptrs);" );
228 output.println( "if (strings == NULL) {" );
229 output.println( " perror(\"backtrace_symbols\");" );
230 output.println( "}" );
231 output.println( "for (j = 0; j < nptrs; j++) {" );
232 output.println( " printf(\"%s\\n\", strings[j]);" );
233 output.println( "}" );
234 output.println( "}" );
241 genAssertRuntimePtrVsHeapResults( PrintWriter output,
244 Set<Alloc> targetsByAnalysis ) {
246 assert targetsByAnalysis != null;
248 output.println( "" );
249 output.println( "// checks vs. heap results (DEBUG) for "+x );
252 if( targetsByAnalysis == HeapAnalysis.DONTCARE_PTR ) {
253 output.println( "// ANALYSIS DIDN'T CARE WHAT "+x+" POINTS-TO" );
257 String ptr = buildCode.generateTemp( context, x );
261 if( targetsByAnalysis.isEmpty() ) {
262 condition = ptr+" != NULL";
265 condition = ptr+" != NULL &&";
267 Iterator<Alloc> aItr = targetsByAnalysis.iterator();
268 while( aItr.hasNext() ) {
269 Alloc a = aItr.next();
270 condition += ptr+"->allocsite != "+a.getUniqueAllocSiteID();
272 if( aItr.hasNext() ) {
278 output.println( "if( "+condition+" ) {" );
279 printConditionFailed( output, condition, ptr );
280 output.println( "}\n" );
286 genAssertRuntimePtrVsHeapResults( PrintWriter output,
289 FieldDescriptor f, // this null OR
290 TempDescriptor i, // this null
291 Hashtable< Alloc, Set<Alloc> > targetsByAnalysis ) {
292 // I assume when you invoke this method you already
293 // invoked a check on just what x points to, don't duplicate
294 // AND assume the check to x passed
296 assert targetsByAnalysis != null;
298 assert f == null || i == null;
301 output.println( "// checks vs. heap results (DEBUG) for "+x+"."+f );
303 output.println( "// checks vs. heap results (DEBUG) for "+x+"["+i+"]" );
307 if( targetsByAnalysis == HeapAnalysis.DONTCARE_DREF ) {
308 output.println( "// ANALYSIS DIDN'T CARE WHAT "+x+" POINTS-TO" );
313 if( targetsByAnalysis.isEmpty() ) {
314 output.println( "// Should have already checked "+x+" is NULL" );
317 output.println( "{" );
319 // if the ptr is null, that's ok, if not check allocsite
320 output.println( "if( "+
321 buildCode.generateTemp( context, x )+
324 // precompute the allocsite, if any, of the object we will
325 // get from hopping through the first ptr
326 output.println( "int allocsiteOneHop = -1;" );
327 output.println( buildCode.strObjType+"* objOneHop;" );
330 output.println( "objOneHop = ("+buildCode.strObjType+"*) "+
331 buildCode.generateTemp( context, x )+
332 "->"+f.getSafeSymbol()+";");
334 output.println( "objOneHop = ("+buildCode.strObjType+"*) "+
335 "((struct "+x.getType().dereference().getSafeSymbol()+"**)"+
336 "(((void*) &("+buildCode.generateTemp( context, x )+"->___length___))+sizeof(int)))"+
337 "["+buildCode.generateTemp( context, i )+"];" );
340 output.println( "if( objOneHop != NULL ) { allocsiteOneHop = objOneHop->allocsite; }" );
342 output.println( "switch( "+
343 buildCode.generateTemp( context, x )+
346 Iterator<Alloc> kItr = targetsByAnalysis.keySet().iterator();
347 while( kItr.hasNext() ) {
348 Alloc k = kItr.next();
350 output.print( "case "+
351 k.getUniqueAllocSiteID()+
354 Set<Alloc> hopTargets = targetsByAnalysis.get( k );
355 if( hopTargets == HeapAnalysis.DONTCARE_PTR ) {
356 output.print( "/* ANALYSIS DOESN'T CARE */" );
359 String condition = "allocsiteOneHop != -1";
361 if( !hopTargets.isEmpty() ) {
365 Iterator<Alloc> aItr = hopTargets.iterator();
366 while( aItr.hasNext() ) {
367 Alloc a = aItr.next();
370 "allocsiteOneHop != "+
371 a.getUniqueAllocSiteID();
373 if( aItr.hasNext() ) {
378 output.println( "if( "+condition+" ) {" );
379 printConditionFailed( output, condition, "objOneHop" );
380 output.println( "}" );
383 output.println( "break;" );
386 output.println( "default:" );
387 output.println( "// the previous condition for "+x+
388 " should already report this failure point" );
389 output.println( "break;" );
390 output.println( "}" );
391 output.println( "}" );
392 output.println( "}\n" );
399 public void printExtraArrayFields(PrintWriter outclassdefs) {}
400 public void outputTransCode(PrintWriter output) {}
401 public void buildCodeSetup() {}
402 public void generateSizeArrayExtensions(PrintWriter outclassdefs) {}
403 public void preCodeGenInitialization() {}
404 public void postCodeGenCleanUp() {}
405 public void additionalClassObjectFields(PrintWriter outclassdefs) {}
406 public void additionalCodeGen(PrintWriter outmethodheader,
407 PrintWriter outstructs,
408 PrintWriter outmethod) {}
409 public void additionalCodeAtTopOfMain(PrintWriter outmethod) {}
410 public void additionalCodeForCommandLineArgs(PrintWriter outmethod, String argsVar) {}
411 public void additionalCodeAtBottomOfMain(PrintWriter outmethod) {}
412 public void additionalIncludesMethodsImplementation(PrintWriter outmethod) {}
413 public void additionalIncludesStructsHeader(PrintWriter outstructs) {}
414 public void additionalCodeAtTopMethodsImplementation(PrintWriter outmethod) {}
415 public void additionalCodeNewObject(PrintWriter outmethod, String dstVar, FlatNew flatNew) {}
416 public void additionalCodeNewStringLiteral(PrintWriter output, String dstVar) {}