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 State state;
20 protected BuildCode buildCode;
21 protected TypeUtil typeUtil;
22 protected HeapAnalysis heapAnalysis;
24 protected ClassDescriptor cdObject;
26 protected TypeDescriptor stringType;
28 private boolean DEBUG = false;
32 public BCXPointsToCheckVRuntime( State state,
35 HeapAnalysis heapAnalysis ) {
37 this.buildCode = buildCode;
38 this.typeUtil = typeUtil;
39 this.heapAnalysis = heapAnalysis;
41 ClassDescriptor cdString = typeUtil.getClass( typeUtil.StringClass );
42 assert cdString != null;
43 stringType = new TypeDescriptor( cdString );
47 public void additionalIncludesMethodsHeader(PrintWriter outmethodheader) {
48 outmethodheader.println( "#include<stdio.h>" );
49 outmethodheader.println( "#include<execinfo.h>" );
53 public void additionalCodeAtTopFlatMethodBody(PrintWriter output, FlatMethod fm) {
55 output.println( "// Generating points-to checks for method params" );
57 for( int i = 0; i < fm.numParameters(); ++i ) {
58 TempDescriptor td = fm.getParameter( i );
59 TypeDescriptor type = td.getType();
62 genAssertRuntimePtrVsHeapResults( output,
65 heapAnalysis.canPointToAfter( td, fm )
69 System.out.println( "\nGenerating code for "+fm );
70 System.out.println( " arg "+td+" can point to "+heapAnalysis.canPointToAfter( td, fm ) );
75 output.println( "// end method params" );
79 public void additionalCodePreNode(FlatMethod fm, FlatNode fn, PrintWriter output) {
90 // for PRE-NODE checks, only look at pointers we are reading from because
91 // pointers about to be set may be undefined and don't pass runtime checks nicely
96 case FKind.FlatOpNode: {
97 FlatOpNode fon = (FlatOpNode) fn;
98 if( fon.getOp().getOp() == Operation.ASSIGN ) {
102 type = lhs.getType();
105 output.println( "// Generating points-to checks for pre-node op assign" );
107 genAssertRuntimePtrVsHeapResults( output,
110 heapAnalysis.canPointToAt( rhs, fn )
113 output.println( "// end pre-node op assign" );
117 System.out.println( " before "+fn );
118 System.out.println( " "+rhs+" can point to "+heapAnalysis.canPointToAt( rhs, fn ) );
125 case FKind.FlatCastNode: {
126 FlatCastNode fcn = (FlatCastNode) fn;
130 type = fcn.getType();
133 output.println( "// Generating points-to checks for pre-node cast" );
135 genAssertRuntimePtrVsHeapResults( output,
138 heapAnalysis.canPointToAt( rhs, fn )
141 output.println( "// end pre-node cast" );
145 System.out.println( " before "+fn );
146 System.out.println( " "+rhs+" can point to "+heapAnalysis.canPointToAt( rhs, fn ) );
152 case FKind.FlatFieldNode: {
153 FlatFieldNode ffn = (FlatFieldNode) fn;
156 fld = ffn.getField();
158 type = lhs.getType();
161 output.println( "// Generating points-to checks for pre-node field" );
163 genAssertRuntimePtrVsHeapResults( output,
166 heapAnalysis.canPointToAt( rhs, fn )
169 genAssertRuntimePtrVsHeapResults( output,
174 heapAnalysis.canPointToAt( rhs, fld, fn )
177 output.println( "// end pre-node field" );
181 System.out.println( " before "+fn );
182 System.out.println( " "+rhs+" can point to "+heapAnalysis.canPointToAt( rhs, fn ) );
183 System.out.println( " "+rhs+"."+fld+" can point to "+heapAnalysis.canPointToAt( rhs, fld, fn ) );
189 case FKind.FlatElementNode: {
190 FlatElementNode fen = (FlatElementNode) fn;
193 idx = fen.getIndex();
195 type = lhs.getType();
198 output.println( "// Generating points-to checks for pre-node element" );
200 genAssertRuntimePtrVsHeapResults( output,
203 heapAnalysis.canPointToAt( rhs, fn )
206 genAssertRuntimePtrVsHeapResults( output,
211 heapAnalysis.canPointToAtElement( rhs, fn )
214 output.println( "// end pre-node element" );
218 System.out.println( " before "+fn );
219 System.out.println( " "+rhs+" can point to "+heapAnalysis.canPointToAt( rhs, fn ) );
220 System.out.println( " "+rhs+"["+idx+"] can point to "+heapAnalysis.canPointToAtElement( rhs, fn ) );
226 case FKind.FlatCall: {
227 FlatCall fc = (FlatCall) fn;
229 FlatMethod fmCallee = state.getMethodFlat( fc.getMethod() );
231 boolean somethingChecked = false;
233 output.println( "// Generating points-to checks for pre-node call" );
235 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
236 arg = fc.getArgMatchingParamIndex( fmCallee, i );
237 type = arg.getType();
239 genAssertRuntimePtrVsHeapResults( output,
242 heapAnalysis.canPointToAt( arg, fn )
244 somethingChecked = true;
248 output.println( "// end pre-node call" );
250 if( DEBUG && somethingChecked ) {
252 System.out.println( " before "+fn+":" );
254 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
255 arg = fc.getArgMatchingParamIndex( fmCallee, i );
256 type = arg.getType();
258 System.out.println( " arg "+arg+" can point to "+heapAnalysis.canPointToAt( arg, fn ) );
268 public void additionalCodePostNode(FlatMethod fm,
270 PrintWriter output) {
282 switch( fn.kind() ) {
285 case FKind.FlatLiteralNode: {
286 FlatLiteralNode fln = (FlatLiteralNode) fn;
288 if( fln.getType().equals( stringType ) ) {
291 output.println( "// Generating points-to checks for post-node string literal" );
293 genAssertRuntimePtrVsHeapResults( output,
296 heapAnalysis.canPointToAfter( lhs, fn )
299 output.println( "// end post-node string literal" );
303 System.out.println( " after "+fn );
304 System.out.println( " "+lhs+" can point to "+heapAnalysis.canPointToAfter( lhs, fn ) );
310 case FKind.FlatOpNode: {
311 FlatOpNode fon = (FlatOpNode) fn;
312 if( fon.getOp().getOp() == Operation.ASSIGN ) {
315 type = lhs.getType();
318 output.println( "// Generating points-to checks for post-node op assign" );
320 genAssertRuntimePtrVsHeapResults( output,
323 heapAnalysis.canPointToAfter( lhs, fn )
326 output.println( "// end post-node op assign" );
330 System.out.println( " after "+fn );
331 System.out.println( " "+lhs+" can point to "+heapAnalysis.canPointToAfter( lhs, fn ) );
338 case FKind.FlatCastNode: {
339 FlatCastNode fcn = (FlatCastNode) fn;
342 type = fcn.getType();
345 output.println( "// Generating points-to checks for post-node cast" );
347 genAssertRuntimePtrVsHeapResults( output,
350 heapAnalysis.canPointToAfter( lhs, fn )
353 output.println( "// end post-node cast" );
357 System.out.println( " after "+fn );
358 System.out.println( " "+lhs+" can point to "+heapAnalysis.canPointToAfter( lhs, fn ) );
364 case FKind.FlatFieldNode: {
365 FlatFieldNode ffn = (FlatFieldNode) fn;
368 type = lhs.getType();
371 output.println( "// Generating points-to checks for post-node field" );
373 genAssertRuntimePtrVsHeapResults( output,
376 heapAnalysis.canPointToAfter( lhs, fn )
379 output.println( "// end post-node field" );
383 System.out.println( " after "+fn );
384 System.out.println( " "+lhs+" can point to "+heapAnalysis.canPointToAfter( lhs, fn ) );
390 case FKind.FlatElementNode: {
391 FlatElementNode fen = (FlatElementNode) fn;
394 type = lhs.getType();
397 output.println( "// Generating points-to checks for post-node element" );
399 genAssertRuntimePtrVsHeapResults( output,
402 heapAnalysis.canPointToAfter( lhs, fn )
405 output.println( "// end post-node element" );
409 System.out.println( " after "+fn );
410 System.out.println( " "+lhs+" can point to "+heapAnalysis.canPointToAfter( lhs, fn ) );
416 case FKind.FlatCall: {
417 FlatCall fc = (FlatCall) fn;
418 ret = fc.getReturnTemp();
420 FlatMethod fmCallee = state.getMethodFlat( fc.getMethod() );
422 boolean somethingChecked = false;
424 output.println( "// Generating points-to checks for post-node call" );
426 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
427 arg = fc.getArgMatchingParamIndex( fmCallee, i );
428 type = arg.getType();
430 genAssertRuntimePtrVsHeapResults( output,
433 heapAnalysis.canPointToAfter( arg, fn )
435 somethingChecked = true;
440 type = ret.getType();
442 genAssertRuntimePtrVsHeapResults( output,
445 heapAnalysis.canPointToAfter( ret, fn )
447 somethingChecked = true;
451 output.println( "// end post-node call" );
453 if( DEBUG && somethingChecked ) {
455 System.out.println( " after "+fn+":" );
457 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
458 arg = fc.getArgMatchingParamIndex( fmCallee, i );
459 type = arg.getType();
461 System.out.println( " arg "+arg+" can point to "+heapAnalysis.canPointToAfter( arg, fn ) );
466 type = ret.getType();
468 System.out.println( " return temp "+ret+" can point to "+heapAnalysis.canPointToAfter( ret, fn ) );
480 printConditionFailed( PrintWriter output,
484 // don't do this in the constructor of this extension object because
485 // build code hasn't created any types or classes yet!
486 if( cdObject == null ) {
487 cdObject = typeUtil.getClass( typeUtil.ObjectClass );
488 assert cdObject != null;
491 output.println( "printf(\"[[[ CHECK VS HEAP RESULTS FAILED ]]] Condition for failure( "+
492 condition+" ) allocsite=%d at %s:%d\\n\", ((struct "+
493 cdObject.getSafeSymbol()+"*)"+
494 pointer+")->allocsite, __FILE__, __LINE__ );" );
496 // spit out the stack trace (so fancy!)
497 output.println( "{" );
498 output.println( "void* buffer[100];" );
499 output.println( "char** strings;" );
500 output.println( "int nptrs,j;" );
501 output.println( "nptrs = backtrace(buffer, 100);" );
502 output.println( "strings = backtrace_symbols(buffer, nptrs);" );
503 output.println( "if (strings == NULL) {" );
504 output.println( " perror(\"backtrace_symbols\");" );
505 output.println( "}" );
506 output.println( "for (j = 0; j < nptrs; j++) {" );
507 output.println( " printf(\"%s\\n\", strings[j]);" );
508 output.println( "}" );
509 output.println( "}" );
516 genAssertRuntimePtrVsHeapResults( PrintWriter output,
519 Set<Alloc> targetsByAnalysis ) {
521 assert targetsByAnalysis != null;
523 output.println( "" );
524 output.println( "// checks vs. heap results (DEBUG) for "+x );
527 if( targetsByAnalysis == HeapAnalysis.DONTCARE_PTR ) {
528 output.println( "// ANALYSIS DIDN'T CARE WHAT "+x+" POINTS-TO" );
532 String ptr = buildCode.generateTemp( context, x );
536 if( targetsByAnalysis.isEmpty() ) {
537 condition = ptr+" != NULL";
540 condition = ptr+" != NULL &&";
542 Iterator<Alloc> aItr = targetsByAnalysis.iterator();
543 while( aItr.hasNext() ) {
544 Alloc a = aItr.next();
545 condition += ptr+"->allocsite != "+a.getUniqueAllocSiteID();
547 if( aItr.hasNext() ) {
553 output.println( "if( "+condition+" ) {" );
554 printConditionFailed( output, condition, ptr );
555 output.println( "}\n" );
561 genAssertRuntimePtrVsHeapResults( PrintWriter output,
564 FieldDescriptor f, // this null OR
565 TempDescriptor i, // this null
566 Hashtable< Alloc, Set<Alloc> > targetsByAnalysis ) {
567 // I assume when you invoke this method you already
568 // invoked a check on just what x points to, don't duplicate
569 // AND assume the check to x passed
571 assert targetsByAnalysis != null;
573 assert f == null || i == null;
576 output.println( "// checks vs. heap results (DEBUG) for "+x+"."+f );
578 output.println( "// checks vs. heap results (DEBUG) for "+x+"["+i+"]" );
582 if( targetsByAnalysis == HeapAnalysis.DONTCARE_DREF ) {
583 output.println( "// ANALYSIS DIDN'T CARE WHAT "+x+" POINTS-TO" );
588 if( targetsByAnalysis.isEmpty() ) {
589 output.println( "// Should have already checked "+x+" is NULL" );
592 output.println( "{" );
594 // if the ptr is null, that's ok, if not check allocsite
595 output.println( "if( "+
596 buildCode.generateTemp( context, x )+
599 // precompute the allocsite, if any, of the object we will
600 // get from hopping through the first ptr
601 output.println( "int allocsiteOneHop = -1;" );
602 output.println( buildCode.strObjType+"* objOneHop;" );
607 // jjenista - DON'T DEAL WITH THIS RIGHT NOW
608 //ClassDescriptor cdX = ;
609 //output.println( "objOneHop = ("+buildCode.strObjType+"*) "+
611 // "->"+f.getSafeSymbol()+";");
612 output.println( "}" );
613 output.println( "}" );
617 output.println( "objOneHop = ("+buildCode.strObjType+"*) "+
618 buildCode.generateTemp( context, x )+
619 "->"+f.getSafeSymbol()+";");
623 output.println( "objOneHop = ("+buildCode.strObjType+"*) "+
624 "((struct "+x.getType().dereference().getSafeSymbol()+"**)"+
625 "(((void*) &("+buildCode.generateTemp( context, x )+"->___length___))+sizeof(int)))"+
626 "["+buildCode.generateTemp( context, i )+"];" );
629 output.println( "if( objOneHop != NULL ) { allocsiteOneHop = objOneHop->allocsite; }" );
631 output.println( "switch( "+
632 buildCode.generateTemp( context, x )+
635 Iterator<Alloc> kItr = targetsByAnalysis.keySet().iterator();
636 while( kItr.hasNext() ) {
637 Alloc k = kItr.next();
639 output.print( "case "+
640 k.getUniqueAllocSiteID()+
643 Set<Alloc> hopTargets = targetsByAnalysis.get( k );
644 if( hopTargets == HeapAnalysis.DONTCARE_PTR ) {
645 output.print( "/* ANALYSIS DOESN'T CARE */" );
648 String condition = "allocsiteOneHop != -1";
650 if( !hopTargets.isEmpty() ) {
654 Iterator<Alloc> aItr = hopTargets.iterator();
655 while( aItr.hasNext() ) {
656 Alloc a = aItr.next();
659 "allocsiteOneHop != "+
660 a.getUniqueAllocSiteID();
662 if( aItr.hasNext() ) {
667 output.println( "if( "+condition+" ) {" );
668 printConditionFailed( output, condition, "objOneHop" );
669 output.println( "}" );
672 output.println( "break;" );
675 output.println( "default:" );
676 output.println( "// the previous condition for "+x+
677 " should already report this failure point" );
678 output.println( "break;" );
679 output.println( "}" );
680 output.println( "}" );
681 output.println( "}\n" );
688 public void printExtraArrayFields(PrintWriter outclassdefs) {}
689 public void outputTransCode(PrintWriter output) {}
690 public void buildCodeSetup() {}
691 public void generateSizeArrayExtensions(PrintWriter outclassdefs) {}
692 public void preCodeGenInitialization() {}
693 public void postCodeGenCleanUp() {}
694 public void additionalClassObjectFields(PrintWriter outclassdefs) {}
695 public void additionalCodeGen(PrintWriter outmethodheader,
696 PrintWriter outstructs,
697 PrintWriter outmethod) {}
698 public void additionalCodeAtTopOfMain(PrintWriter outmethod) {}
699 public void additionalCodeForCommandLineArgs(PrintWriter outmethod, String argsVar) {}
700 public void additionalCodeAtBottomOfMain(PrintWriter outmethod) {}
701 public void additionalIncludesMethodsImplementation(PrintWriter outmethod) {}
702 public void additionalIncludesStructsHeader(PrintWriter outstructs) {}
703 public void additionalCodeAtTopMethodsImplementation(PrintWriter outmethod) {}
704 public void additionalCodeNewObject(PrintWriter outmethod, String dstVar, FlatNew flatNew) {}
705 public void additionalCodeNewStringLiteral(PrintWriter output, String dstVar) {}