1 19 20 package edu.umd.cs.findbugs.detect; 21 22 import java.util.regex.Pattern ; 23 import java.util.regex.PatternSyntaxException ; 24 25 import org.apache.bcel.classfile.Code; 26 import org.apache.bcel.classfile.JavaClass; 27 import org.apache.bcel.classfile.Method; 28 29 import edu.umd.cs.findbugs.BugInstance; 30 import edu.umd.cs.findbugs.BugReporter; 31 import edu.umd.cs.findbugs.BytecodeScanningDetector; 32 import edu.umd.cs.findbugs.OpcodeStack; 33 import edu.umd.cs.findbugs.StatelessDetector; 34 35 public class BadSyntaxForRegularExpression 36 extends BytecodeScanningDetector { 37 38 BugReporter bugReporter; 39 40 public BadSyntaxForRegularExpression(BugReporter bugReporter) { 41 this.bugReporter = bugReporter; 42 } 43 44 45 46 @Override 47 public void visit(JavaClass obj) { 48 } 49 50 @Override 51 public void visit(Method obj) { 52 } 53 54 OpcodeStack stack = new OpcodeStack(); 55 @Override 56 public void visit(Code obj) { 57 stack.resetForMethodEntry(this); 58 super.visit(obj); 59 } 60 61 private void singleDotPatternWouldBeSilly(int stackDepth, boolean ignorePasswordMasking) { 62 if (ignorePasswordMasking && stackDepth != 1) 63 throw new IllegalArgumentException ("Password masking requires stack depth 1, but is " + stackDepth); 64 if (stack.getStackDepth() < stackDepth) return; 65 OpcodeStack.Item it = stack.getStackItem(stackDepth); 66 Object value = it.getConstant(); 67 if (value == null || !(value instanceof String )) return; 68 String regex = (String ) value; 69 if (!regex.equals(".")) return; 70 if (ignorePasswordMasking) { 71 OpcodeStack.Item top = stack.getStackItem(0); 72 Object topValue = top.getConstant(); 73 if (topValue instanceof String ) { 74 String replacementString = (String ) topValue; 75 if (replacementString.length() == 1 && replacementString.toLowerCase().equals("x") || replacementString.equals("*") || replacementString.equals("\\*")) return; 76 } 77 78 } 79 80 81 bugReporter.reportBug(new BugInstance(this, "RE_POSSIBLE_UNINTENDED_PATTERN", 82 NORMAL_PRIORITY) 83 .addClassAndMethod(this) 84 .addSourceLine(this) 85 ); 86 } 87 88 private void sawRegExPattern(int stackDepth) { 89 sawRegExPattern(stackDepth, 0); 90 } 91 private void sawRegExPattern(int stackDepth, int flags) { 92 if (stack.getStackDepth() < stackDepth) return; 93 OpcodeStack.Item it = stack.getStackItem(stackDepth); 94 if (it.getSpecialKind() == OpcodeStack.Item.FILE_SEPARATOR_STRING && (flags & Pattern.LITERAL) == 0) { 95 bugReporter.reportBug(new BugInstance(this, "RE_CANT_USE_FILE_SEPARATOR_AS_REGULAR_EXPRESSION", 96 HIGH_PRIORITY) 97 .addClassAndMethod(this) 98 .addSourceLine(this) 99 ); 100 return; 101 } 102 Object value = it.getConstant(); 103 if (value == null || !(value instanceof String )) return; 104 String regex = (String ) value; 105 try { 106 Pattern.compile(regex, flags); 107 } catch (PatternSyntaxException e) { 108 bugReporter.reportBug(new BugInstance(this, "RE_BAD_SYNTAX_FOR_REGULAR_EXPRESSION", 109 HIGH_PRIORITY) 110 .addClassAndMethod(this) 111 .addSourceLine(this) 112 ); 113 } 114 } 115 116 117 private int getIntValue(int stackDepth, int defaultValue) { 118 if (stack.getStackDepth() < stackDepth) return defaultValue; 119 OpcodeStack.Item it = stack.getStackItem(stackDepth); 120 Object value = it.getConstant(); 121 if (value == null || !(value instanceof Integer )) return defaultValue; 122 return ((Number )value).intValue(); 123 } 124 125 @Override 126 public void sawOpcode(int seen) { 127 stack.mergeJumps(this); 128 if (seen == INVOKESTATIC 129 && getClassConstantOperand().equals("java/util/regex/Pattern") 130 && getNameConstantOperand().equals("compile") 131 && getSigConstantOperand().startsWith("(Ljava/lang/String;I)") 132 ) 133 sawRegExPattern(1, getIntValue(0, 0)); 134 else if (seen == INVOKESTATIC 135 && getClassConstantOperand().equals("java/util/regex/Pattern") 136 && getNameConstantOperand().equals("compile") 137 && getSigConstantOperand().startsWith("(Ljava/lang/String;)") 138 ) 139 sawRegExPattern(0); 140 else if (seen == INVOKESTATIC 141 && getClassConstantOperand().equals("java/util/regex/Pattern") 142 && getNameConstantOperand().equals("matches") 143 ) 144 sawRegExPattern(1); 145 else if (seen == INVOKEVIRTUAL 146 && getClassConstantOperand().equals("java/lang/String") 147 && getNameConstantOperand().equals("replaceAll") 148 ) { 149 sawRegExPattern(1); 150 singleDotPatternWouldBeSilly(1, true); 151 } 152 else if (seen == INVOKEVIRTUAL 153 && getClassConstantOperand().equals("java/lang/String") 154 && getNameConstantOperand().equals("replaceFirst") 155 ) 156 { 157 sawRegExPattern(1); 158 singleDotPatternWouldBeSilly(1, false); 159 } 160 else if (seen == INVOKEVIRTUAL 161 && getClassConstantOperand().equals("java/lang/String") 162 && getNameConstantOperand().equals("matches") 163 ) 164 { 165 sawRegExPattern(0); 166 singleDotPatternWouldBeSilly(0, false); 167 } 168 else if (seen == INVOKEVIRTUAL 169 && getClassConstantOperand().equals("java/lang/String") 170 && getNameConstantOperand().equals("split") 171 ) 172 { 173 sawRegExPattern(0); 174 singleDotPatternWouldBeSilly(0, false); 175 } 176 177 stack.sawOpcode(this,seen); 178 } 179 180 } 181 | Popular Tags |