Skip to content

Commit b66de84

Browse files
committed
minor bug fixes in queries for better readability
1 parent 301a0d8 commit b66de84

7 files changed

Lines changed: 89 additions & 46 deletions

File tree

src/tools/queries/double_free.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88

99
val output = new StringBuilder()
1010

11+
// Helper: build path-boundary anchored regex from a filename
12+
// e.g., "parser.c" -> "(^|.*/)parser\\.c$" so it matches "/path/to/parser.c"
13+
// but NOT "/path/to/myparser.c"
14+
def pathBoundaryRegex(f: String): String = {
15+
val escaped = java.util.regex.Pattern.quote(f)
16+
"(^|.*/)" + escaped + "$"
17+
}
18+
1119
/** Check if two line numbers are in mutually exclusive branches of the same IF.
1220
* Returns true if lineA is inside the THEN block and lineB inside ELSE (or vice versa),
1321
* meaning they cannot both execute in the same control flow path.
@@ -70,7 +78,8 @@
7078
val freeCalls = cpg.call.name("free|cfree|g_free|xmlFree|xsltFree.*").l
7179

7280
val freeCallsFiltered = if (fileFilter.nonEmpty) {
73-
freeCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
81+
val pattern = pathBoundaryRegex(fileFilter)
82+
freeCalls.filter(_.file.name.headOption.exists(_.matches(pattern)))
7483
} else {
7584
freeCalls
7685
}

src/tools/queries/integer_overflow.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
val output = new StringBuilder()
1010

11+
// Helper: build path-boundary anchored regex from a filename
12+
def pathBoundaryRegex(f: String): String = {
13+
val escaped = java.util.regex.Pattern.quote(f)
14+
"(^|.*/)" + escaped + "$"
15+
}
16+
1117
output.append("Integer Overflow/Underflow Analysis\n")
1218
output.append("=" * 60 + "\n\n")
1319

@@ -127,8 +133,10 @@
127133
// --- Analysis ---
128134

129135
val allAllocCalls = cpg.call.name(allocPattern).l
136+
val filePattern = if (fileFilter.nonEmpty) pathBoundaryRegex(fileFilter) else ""
137+
130138
val allocCalls = if (fileFilter.nonEmpty) {
131-
allAllocCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
139+
allAllocCalls.filter(_.file.name.headOption.exists(_.matches(filePattern)))
132140
} else {
133141
allAllocCalls
134142
}
@@ -248,7 +256,7 @@
248256
// Only flag high-risk arithmetic in array indices, with no bounds check nearby.
249257
val allIndexCalls = cpg.call.name("<operator>.indirectIndexAccess|<operator>.indexAccess").l
250258
val indexCalls = if (fileFilter.nonEmpty) {
251-
allIndexCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
259+
allIndexCalls.filter(_.file.name.headOption.exists(_.matches(filePattern)))
252260
} else {
253261
allIndexCalls
254262
}
@@ -316,7 +324,7 @@
316324
}
317325

318326
val arithSourcesFiltered = if (fileFilter.nonEmpty) {
319-
arithSourceCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
327+
arithSourceCalls.filter(_.file.name.headOption.exists(_.matches(filePattern)))
320328
} else {
321329
arithSourceCalls
322330
}
@@ -395,7 +403,8 @@
395403
}
396404
}
397405
} catch {
398-
case _: Exception => // Ignore dataflow engine errors gracefully
406+
case e: Exception =>
407+
output.append(s" Note: Interprocedural arithmetic flow analysis encountered an error (${e.getClass.getSimpleName})\n")
399408
}
400409

401410
// === Output results ===

src/tools/queries/null_pointer_deref.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
val output = new StringBuilder()
1010

11+
// Helper: build path-boundary anchored regex from a filename
12+
def pathBoundaryRegex(f: String): String = {
13+
val escaped = java.util.regex.Pattern.quote(f)
14+
"(^|.*/)" + escaped + "$"
15+
}
16+
1117
/** Check if two line numbers are in mutually exclusive branches of the same IF.
1218
* Returns true if lineA is inside the THEN block and lineB inside ELSE (or vice versa),
1319
* meaning they cannot both execute in the same control flow path.
@@ -80,7 +86,8 @@
8086
val allocCalls = cpg.call.name(allocFunctions).l
8187

8288
val allocCallsFiltered = if (fileFilter.nonEmpty) {
83-
allocCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
89+
val pattern = pathBoundaryRegex(fileFilter)
90+
allocCalls.filter(_.file.name.headOption.exists(_.matches(pattern)))
8491
} else {
8592
allocCalls
8693
}
@@ -390,7 +397,8 @@
390397
}
391398
}
392399
} catch {
393-
case _: Exception => // Ignore dataflow errors gracefully
400+
case e: Exception =>
401+
output.append(s" Note: Interprocedural analysis skipped for $assignedPtr in $methodName() (${e.getClass.getSimpleName})\n")
394402
}
395403
}
396404
}

src/tools/queries/program_slice.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
sortedDeps.groupBy(_._2).foreach { case (file, deps) =>
124124
output.append(s" File: $file\n")
125125
deps.sortBy(_._1).foreach { case (line, _, varName, code, deps) =>
126-
val lineInfo = if (line != -1) s"[$line]" else "[Local]"
126+
val lineInfo = if (line != -1) s"[$file:$line]" else "[Local]"
127127
output.append(s" $lineInfo $varName: $code\n")
128128
if (deps.nonEmpty) output.append(s" <- depends on: ${deps.mkString(", ")}\n")
129129
}
@@ -227,7 +227,7 @@
227227
sortedProps.groupBy(_._2).foreach { case (file, props) =>
228228
output.append(s" File: $file\n")
229229
props.sortBy(_._1).foreach { case (line, _, propType, varName, code) =>
230-
output.append(s" [$line] $propType ($varName): $code\n")
230+
output.append(s" [$file:$line] $propType ($varName): $code\n")
231231
}
232232
}
233233
}

src/tools/queries/taint_flows.scala

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -173,49 +173,58 @@
173173
}
174174
}
175175
} else {
176-
output.append(s"Found ${flows.size} taint flow(s):\n\n")
177-
178-
flows.zipWithIndex.foreach { case (flow, idx) =>
179-
output.append(s"--- Flow ${idx + 1} ---\n")
180-
176+
// Deduplicate: track seen (source_file:line -> sink_file:line) pairs
177+
val seen = mutable.Set[String]()
178+
179+
flows.foreach { flow =>
181180
val elements = flow.elements.l
182181
if (elements.nonEmpty) {
183-
// Source (first element)
184182
val source = elements.head
183+
val sink = elements.last
184+
185185
val srcFile = source.file.name.headOption.getOrElse("?")
186186
val srcLine = source.lineNumber.getOrElse(-1)
187-
val srcMethod = getMethodName(source)
188-
output.append(s"Source: ${source.code}\n")
189-
output.append(s" Location: $srcFile:$srcLine in $srcMethod()\n")
190-
191-
// Path elements (intermediate steps)
192-
if (elements.size > 2) {
193-
output.append(s"\nPath (${elements.size - 2} intermediate steps):\n")
194-
elements.slice(1, elements.size - 1).take(15).foreach { elem =>
195-
val elemFile = elem.file.name.headOption.getOrElse("?")
196-
val elemLine = elem.lineNumber.getOrElse(-1)
197-
val elemMethod = getMethodName(elem)
198-
val codeSnippet = elem.code.take(60).replaceAll("\n", " ")
199-
output.append(s" [$elemFile:$elemLine] $codeSnippet\n")
200-
output.append(s" in $elemMethod()\n")
201-
}
202-
if (elements.size - 2 > 15) {
203-
output.append(s" ... and ${elements.size - 17} more steps\n")
204-
}
205-
}
206-
207-
// Sink (last element)
208-
val sink = elements.last
209187
val snkFile = sink.file.name.headOption.getOrElse("?")
210188
val snkLine = sink.lineNumber.getOrElse(-1)
211-
val snkMethod = getMethodName(sink)
212-
output.append(s"\nSink: ${sink.code}\n")
213-
output.append(s" Location: $snkFile:$snkLine in $snkMethod()\n")
214-
215-
output.append(s"\nPath length: ${elements.size} nodes\n")
189+
190+
val key = s"$srcFile:$srcLine->$snkFile:$snkLine"
191+
if (!seen.contains(key)) {
192+
seen.add(key)
193+
194+
output.append(s"--- Flow ${seen.size} ---\n")
195+
196+
// Source (first element)
197+
val srcMethod = getMethodName(source)
198+
output.append(s"Source: ${source.code}\n")
199+
output.append(s" Location: $srcFile:$srcLine in $srcMethod()\n")
200+
201+
// Path elements (intermediate steps)
202+
if (elements.size > 2) {
203+
output.append(s"\nPath (${elements.size - 2} intermediate steps):\n")
204+
elements.slice(1, elements.size - 1).take(15).foreach { elem =>
205+
val elemFile = elem.file.name.headOption.getOrElse("?")
206+
val elemLine = elem.lineNumber.getOrElse(-1)
207+
val elemMethod = getMethodName(elem)
208+
val codeSnippet = elem.code.take(60).replaceAll("\n", " ")
209+
output.append(s" [$elemFile:$elemLine] $codeSnippet\n")
210+
output.append(s" in $elemMethod()\n")
211+
}
212+
if (elements.size - 2 > 15) {
213+
output.append(s" ... and ${elements.size - 17} more steps\n")
214+
}
215+
}
216+
217+
// Sink (last element)
218+
val snkMethod = getMethodName(sink)
219+
output.append(s"\nSink: ${sink.code}\n")
220+
output.append(s" Location: $snkFile:$snkLine in $snkMethod()\n")
221+
222+
output.append(s"\nPath length: ${elements.size} nodes\n\n")
223+
}
216224
}
217-
output.append("\n")
218225
}
226+
227+
output.append(s"Summary: ${seen.size} unique flow(s)\n")
219228
}
220229
}
221230

src/tools/queries/use_after_free.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
val output = new StringBuilder()
1010

11+
// Helper: build path-boundary anchored regex from a filename
12+
def pathBoundaryRegex(f: String): String = {
13+
val escaped = java.util.regex.Pattern.quote(f)
14+
"(^|.*/)" + escaped + "$"
15+
}
16+
1117
/** Check if two line numbers are in mutually exclusive branches of the same IF.
1218
* Returns true if lineA is inside the THEN block and lineB inside ELSE (or vice versa),
1319
* meaning they cannot both execute in the same control flow path.
@@ -71,7 +77,8 @@
7177
val freeCalls = cpg.call.name("free|cfree|g_free|xmlFree|xsltFree.*").l
7278

7379
val freeCallsFiltered = if (fileFilter.nonEmpty) {
74-
freeCalls.filter(_.file.name.headOption.exists(f => f.contains(fileFilter) || f.endsWith(fileFilter)))
80+
val pattern = pathBoundaryRegex(fileFilter)
81+
freeCalls.filter(_.file.name.headOption.exists(_.matches(pattern)))
7582
} else {
7683
freeCalls
7784
}
@@ -263,7 +270,8 @@
263270
}
264271
}
265272
} catch {
266-
case _: Exception => // Ignore dataflow errors
273+
case e: Exception =>
274+
output.append(s" Note: Interprocedural analysis skipped for $freedPtr in $methodName() (${e.getClass.getSimpleName})\n")
267275
}
268276
}
269277
}

src/tools/queries/variable_flow.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
// Deduplicate output
169169
val uniqueDeps = sortedDeps.distinct
170170
uniqueDeps.foreach { case (file, line, code, typeName) =>
171-
sb.append(f"[$file:$line%4d] $code ($typeName)\n")
171+
sb.append(s"[$file:$line] $code ($typeName)\n")
172172
}
173173
}
174174

0 commit comments

Comments
 (0)