From e79ff5beef9962f7667ff9b55908b8b4b1a2520a Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Wed, 22 Apr 2026 23:36:51 -0700
Subject: [PATCH 01/19] [AI] Initial stab at optimizing suppressions and IRQL.
---
.../queries/IrqlNotSaved/IrqlNotSaved.ql | 9 +-
src/drivers/libraries/Irql.qll | 100 ++++++++-----
src/drivers/libraries/Suppression.qll | 141 ++++++++++++++----
3 files changed, 182 insertions(+), 68 deletions(-)
diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
index 43e2a076..aea23db4 100644
--- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
+++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
@@ -74,7 +74,7 @@ class FundamentalIrqlSaveFunction extends IrqlSavesFunction {
}
/**
- * A simple data flow from any IrqlSaveParameter.
+ * A data flow from any IrqlSaveParameter to variables that receive its value.
*/
module IrqlSaveParameterFlowConfigurationConfig implements DataFlow::ConfigSig {
@@ -82,7 +82,12 @@ module IrqlSaveParameterFlowConfigurationConfig implements DataFlow::ConfigSig {
source.asParameter() instanceof IrqlSaveParameter
}
- predicate isSink(DataFlow::Node sink) { sink instanceof DataFlow::Node }
+ predicate isSink(DataFlow::Node sink) {
+ // Only track flow to assignment targets or parameters — not every node
+ exists(Variable v | v.getAnAssignedValue() = sink.asExpr())
+ or
+ exists(sink.asParameter())
+ }
}
module IrqlSaveParameterFlowConfiguration = DataFlow::Global;
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index 19907787..4b70fff1 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -690,6 +690,48 @@
* - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function.
* - Failing all this, we set the IRQL to 0.
*
+ import semmle.code.cpp.controlflow.Dominance
+
+ /** Utility function to get all exit points of a function. */
+ pragma[nomagic]
+ private ControlFlowNode getAnExitPointOfFunction(Function f) {
+ result.getControlFlowScope() = f and
+ functionExit(result)
+ }
+
+ /**
+ * Pre-computed summary: the potential exit IRQL of function `f`,
+ * computed once per function rather than re-discovered per call site.
+ */
+ pragma[nomagic]
+ private int functionExitIrql(Function f) {
+ result = getPotentialExitIrqlAtCfn(getAnExitPointOfFunction(f))
+ }
+
+ /**
+ * Gets the set of predecessor nodes from callers for function `callee`.
+ * This pre-computes the reverse call-graph edge for interprocedural analysis
+ * and is restricted to actual call sites.
+ */
+ pragma[nomagic]
+ private ControlFlowNode callerPredecessor(Function callee) {
+ result.getASuccessor().(FunctionCall).getTarget() = callee
+ }
+
+ /**
+ * Attempt to provide the IRQL **once this control flow node exits**, based on annotations and direct calls to raising/lowering functions.
+ * This predicate functions as follows:
+ * - If calling a "Raise IRQL" function, then it returns the value of the argument passed in (the target IRQL).
+ * - If calling a "Lower IRQL" function, then it returns the value of the argument passed in (the target IRQL).
+ * - If calling a function annotated to restore the IRQL from a previously saved spot, then the result is the IRQL before that save call.
+ * - If calling a function annotated to raise the IRQL, then it returns the annotated value (the target IRQL).
+ * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN.
+ * - If this node is calling a function with no annotations, the result is the IRQL that function exits at (pre-computed per function).
+ * - If there is a prior CFN in the CFG, the result is the result for that prior CFN.
+ * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function (a lazy interprocedural analysis.)
+ * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function.
+ * - Failing all this, we set the IRQL to 0.
+ *
* Not implemented: _IRQL_limited_to_
*/
@@ -714,33 +756,22 @@
if
cfn instanceof FunctionCall and
cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction
- then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor()))
+ then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
else
+ // Key optimization: use pre-computed function exit IRQL summary
+ // instead of re-scanning exit points per call site
if cfn instanceof FunctionCall
- then
- result =
- any(getPotentialExitIrqlAtCfn(getExitPointsOfFunction(cfn.(FunctionCall)
- .getTarget()))
- )
+ then result = functionExitIrql(cfn.(FunctionCall).getTarget())
else
if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor())
- then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor()))
+ then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
else
- if
- exists(FunctionCall fc, ControlFlowNode cfn2 |
- fc.getTarget() = cfn.getControlFlowScope() and
- cfn2.getASuccessor() = fc
- )
+ // Key optimization: use pre-computed callerPredecessor instead of
+ // inline reverse call-graph query
+ if exists(callerPredecessor(cfn.getControlFlowScope()))
then
- // TODO: Check that this node is actually a function entry point and not just
- // an isolated part of the CFN. Sometimes we get nodes that are "in" a function's
- // CFN, but have no predecessors, but are not function entry. (Why?)
result =
- any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 |
- cfn2.getASuccessor().(FunctionCall).getTarget() =
- cfn.getControlFlowScope()
- ))
- )
+ getPotentialExitIrqlAtCfn(callerPredecessor(cfn.getControlFlowScope()))
else
if
cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and
@@ -748,13 +779,13 @@
then result = getAllowableIrqlLevel(cfn.getControlFlowScope())
else result = 0
}
-
-
+
+
/*
* Similar to above, but only exit points where the Irql is explicit
*/
-
-
+
+
int getExplicitExitIrqlAtCfn(ControlFlowNode cfn) {
if cfn instanceof KeRaiseIrqlCall
then result = cfn.(KeRaiseIrqlCall).getIrqlLevel()
@@ -776,30 +807,17 @@
if
cfn instanceof FunctionCall and
cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction
- then result = any(getExplicitExitIrqlAtCfn(cfn.getAPredecessor()))
+ then result = getExplicitExitIrqlAtCfn(cfn.getAPredecessor())
else (
if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor())
- then result = any(getExplicitExitIrqlAtCfn(cfn.getAPredecessor()))
+ then result = getExplicitExitIrqlAtCfn(cfn.getAPredecessor())
else
result =
- any(getExplicitExitIrqlAtCfn(any(ControlFlowNode cfn2 |
- cfn2.getASuccessor().(FunctionCall).getTarget() =
- cfn.getControlFlowScope()
- ))
- )
+ getExplicitExitIrqlAtCfn(callerPredecessor(cfn.getControlFlowScope()))
)
}
- import semmle.code.cpp.controlflow.Dominance
-
- /** Utility function to get exit points of a function. */
- private ControlFlowNode getExitPointsOfFunction(Function f) {
- result =
- any(ControlFlowNode cfn |
- cfn.getControlFlowScope() = f and
- functionExit(cfn)
- )
- }
+
/**
* Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function.
diff --git a/src/drivers/libraries/Suppression.qll b/src/drivers/libraries/Suppression.qll
index c48fb176..b5df941b 100644
--- a/src/drivers/libraries/Suppression.qll
+++ b/src/drivers/libraries/Suppression.qll
@@ -2,6 +2,57 @@
// Licensed under the MIT license.
import cpp
+/**
+ * Gets the minimum start line of a non-suppression Locatable in `f` that is
+ * strictly after `afterLine`. Pre-computing distinct lines avoids iterating
+ * over every Locatable individually in the aggregate.
+ */
+pragma[nomagic]
+private int nextNonSuppressionLine(File f, int afterLine) {
+ afterLine = any(SuppressPragma sp | sp.getFile() = f).getLocation().getEndLine() and
+ result =
+ min(int line |
+ exists(Locatable l |
+ l.getFile() = f and
+ not l instanceof CASuppression and
+ line = l.getLocation().getStartLine() and
+ line > afterLine
+ )
+ )
+}
+
+/**
+ * Holds if `d` is a DisablePragma that falls within SuppressionPushPopSegment `s`.
+ */
+pragma[nomagic]
+private predicate disableInSegment(DisablePragma d, SuppressionPushPopSegment s) {
+ d.getFile() = s.getFile() and
+ d.getLocation().getStartLine() >= s.getSegmentStartLine() and
+ d.getLocation().getEndLine() <= s.getSegmentEndLine()
+}
+
+/**
+ * Holds if `d` is a DisablePragma that is inside at least one push/pop segment.
+ */
+pragma[nomagic]
+private predicate disableHasSegment(DisablePragma d) {
+ exists(SuppressionPushPopSegment s | disableInSegment(d, s))
+}
+
+/**
+ * Holds if a Location in file `f` spanning `startLine` to `endLine`
+ * falls inside at least one push/pop segment.
+ */
+bindingset[f, startLine, endLine]
+pragma[inline_late]
+private predicate locationInAnySegment(File f, int startLine, int endLine) {
+ exists(SuppressionPushPopSegment s |
+ f = s.getFile() and
+ startLine >= s.getSegmentStartLine() and
+ endLine <= s.getSegmentEndLine()
+ )
+}
+
// Reference: https://learn.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-170
/**
* Represents a Code Analysis-style suppression using #pragma commands.
@@ -23,6 +74,13 @@ abstract class CASuppression extends PreprocessorPragma {
/** Evaluates if the given location is suppressed by this suppression. */
abstract predicate appliesToLocation(Location l);
+ /**
+ * Gets the scope of this suppression as a line range within a file.
+ * This is used by `hasLocationInfo` to define where the suppression applies
+ * without enumerating every Location in the database.
+ */
+ abstract predicate scopeCovers(File f, int startLine, int endLine);
+
/** Returns the scope covered by this suppression. */
CASuppressionScope getScope() { result = this }
@@ -121,16 +179,19 @@ abstract class CASuppression extends PreprocessorPragma {
/** Represents the scope covered by a given CA supression. */
class CASuppressionScope extends ElementBase instanceof CASuppression {
+ /**
+ * Defines the location range covered by this suppression scope.
+ * Instead of iterating all Location objects, this uses pre-computed scope bounds
+ * to return the bounding box of the suppression region directly.
+ */
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- exists(Location l |
- l.getFile().getAbsolutePath() = filepath and
- l.getStartLine() = startline and
- l.getStartColumn() = startcolumn and
- l.getEndLine() = endline and
- l.getEndColumn() = endcolumn and
- super.appliesToLocation(l)
+ exists(File f |
+ super.scopeCovers(f, startline, endline) and
+ filepath = f.getAbsolutePath() and
+ startcolumn = 1 and
+ endcolumn = 1
)
}
}
@@ -171,20 +232,21 @@ class SuppressPragma extends CASuppression {
this.getLocation().getEndLine() + this.getMinimumLocationOffset() = l.getStartLine()
}
+ /** The scope of a suppress pragma is just the single next code line. */
+ pragma[nomagic]
+ override predicate scopeCovers(File f, int startLine, int endLine) {
+ f = this.getFile() and
+ startLine = this.getLocation().getEndLine() + this.getMinimumLocationOffset() and
+ endLine = startLine
+ }
+
/** Finds the offset (in line count) to the closest non-pragma element after this suppression. */
pragma[nomagic]
-
int getMinimumLocationOffset() {
- result =
- min(int i |
- i > 0 and
- exists(Locatable l |
- l.getFile() = this.getFile() and
- l.getLocation().getStartLine() > this.getLocation().getEndLine() and
- not l instanceof CASuppression and
- this.getLocation().getEndLine() + i = l.getLocation().getStartLine()
- )
- )
+ exists(int nextLine |
+ nextLine = nextNonSuppressionLine(this.getFile(), this.getLocation().getEndLine()) and
+ result = nextLine - this.getLocation().getEndLine()
+ )
}
}
@@ -219,12 +281,36 @@ class DisablePragma extends CASuppression {
// If we're in a pragma push/pop, ensure the disable is too
(
exists(SuppressionPushPopSegment spps |
- spps.getADisablePragma() = this and
- spps.isInPushPopSegment(l)
+ disableInSegment(this, spps) and
+ l.getFile() = spps.getFile() and
+ l.getStartLine() >= spps.getSegmentStartLine() and
+ l.getEndLine() <= spps.getSegmentEndLine()
)
or
- not exists(SuppressionPushPopSegment spps | spps.getADisablePragma() = this) and
- not exists(SuppressionPushPopSegment spps | spps.isInPushPopSegment(l))
+ not disableHasSegment(this) and
+ not locationInAnySegment(l.getFile(), l.getStartLine(), l.getEndLine())
+ )
+ }
+
+ /**
+ * The scope of a disable pragma: from the disable line to either the end of the
+ * enclosing push/pop segment, or the end of the file.
+ * Returns a single bounding range rather than enumerating every Location.
+ */
+ pragma[nomagic]
+ override predicate scopeCovers(File f, int startLine, int endLine) {
+ f = this.getFile() and
+ startLine = this.getLocation().getEndLine() and
+ (
+ // If in a push/pop segment, scope ends at the segment end
+ exists(SuppressionPushPopSegment spps |
+ disableInSegment(this, spps) and
+ endLine = spps.getSegmentEndLine()
+ )
+ or
+ // If not in any segment, scope covers to end of file
+ not disableHasSegment(this) and
+ endLine = max(int line | exists(Location l | l.getFile() = f and line = l.getEndLine()))
)
}
}
@@ -277,8 +363,14 @@ class SuppressionPushPopSegment extends Location {
)
}
+ /** Gets the end line of the push (start of the segment content). */
+ int getSegmentStartLine() { result = start.getEndLine() }
+
+ /** Gets the start line of the pop (end of the segment content). */
+ int getSegmentEndLine() { result = end.getStartLine() }
+
/** Determines if a given location is in this push/pop segment. */
- pragma[inline]
+ pragma[nomagic]
predicate isInPushPopSegment(Location l) {
l.getFile() = this.getFile() and
l.getStartLine() >= start.getEndLine() and
@@ -286,8 +378,7 @@ class SuppressionPushPopSegment extends Location {
}
/** Returns a disable pragma within this push/pop segment. */
-
DisablePragma getADisablePragma() {
- result = any(DisablePragma p | this.isInPushPopSegment(p.getLocation()))
+ disableInSegment(result, this)
}
}
From 59ce4478c403cd7cac653412201983b2c584e7d7 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Fri, 24 Apr 2026 15:48:45 -0700
Subject: [PATCH 02/19] [AI] Revise IRQL queries and libraries to reduce false
positives.
---
.../IrqlFloatStateMismatch.ql | 40 +++++++++++++-
.../queries/IrqlSetTooHigh/IrqlSetTooHigh.ql | 11 +++-
.../queries/IrqlTooHigh/IrqlTooHigh.ql | 3 +-
.../general/queries/IrqlTooLow/IrqlTooLow.ql | 3 +-
src/drivers/libraries/Irql.qll | 53 ++++++++++++++++++-
5 files changed, 104 insertions(+), 6 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index eb7ace37..8225905d 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -42,12 +42,50 @@ module FloatStateFlowConfig implements DataFlow::ConfigSig {
module FloatStateFlow = DataFlow::Global;
+/**
+ * Holds if `cfn` is a call to a function that may change the IRQL.
+ * This includes KeRaiseIrql, KeLowerIrql, functions annotated with
+ * _IRQL_raises_, and functions annotated with _IRQL_saves_global_ /
+ * _IRQL_restores_global_ (which imply spinlock acquire/release patterns).
+ */
+predicate isIrqlChangingCfn(ControlFlowNode cfn) {
+ cfn instanceof KeRaiseIrqlCall
+ or
+ cfn instanceof KeLowerIrqlCall
+ or
+ cfn instanceof RestoresGlobalIrqlCall
+ or
+ cfn instanceof SavesGlobalIrqlCall
+ or
+ (
+ cfn instanceof FunctionCall and
+ cfn.(FunctionCall).getTarget() instanceof IrqlChangesFunction
+ )
+}
+
+/**
+ * Holds if there is an IRQL-changing call on some CFG path between
+ * `save` and `restore` within the same function.
+ */
+predicate irqlChangesBetween(ControlFlowNode save, ControlFlowNode restore) {
+ exists(ControlFlowNode mid |
+ mid.getControlFlowScope() = save.getControlFlowScope() and
+ isIrqlChangingCfn(mid) and
+ save.getASuccessor+() = mid and
+ mid.getASuccessor+() = restore
+ )
+}
+
from DataFlow::Node source, DataFlow::Node sink, int irqlSink, int irqlSource
where
FloatStateFlow::flow(source, sink) and
irqlSource = getPotentialExitIrqlAtCfn(source.asIndirectExpr()) and
irqlSink = getPotentialExitIrqlAtCfn(sink.asIndirectExpr()) and
- irqlSink != irqlSource
+ irqlSink != irqlSource and
+ // Only flag if there is an actual IRQL-changing operation between save and restore.
+ // If no IRQL-changing call exists, the IRQL is invariant within a single invocation
+ // and the mismatch is a may-analysis artifact from different hypothetical entry IRQLs.
+ irqlChangesBetween(source.asIndirectExpr(), sink.asIndirectExpr())
select sink.asIndirectExpr(),
"The irql level where the floating-point state was saved (" + irqlSource +
") does not match the irql level for the restore operation (" + irqlSink + ")."
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
index 56d32680..0fbbeab2 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
@@ -39,9 +39,16 @@ where
irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement
or
// If we don't have an explicit max annotation but do raise the IRQL,
- // we treat the raised-to level as the implicit max.
+ // we treat the raised-to level as the implicit max —
+ // UNLESS the function has a _requires_min_ above the raises-to level,
+ // which indicates a "lower IRQL on exit" pattern (e.g. mutex release),
+ // not a ceiling.
not irqlFunc instanceof IrqlAlwaysMaxFunction and
- irqlFunc.(IrqlRaisesAnnotatedFunction).getIrqlLevel() = irqlRequirement
+ irqlFunc.(IrqlRaisesAnnotatedFunction).getIrqlLevel() = irqlRequirement and
+ not exists(IrqlMinAnnotation minAnno |
+ minAnno = irqlFunc.getFuncIrqlAnnotation() and
+ minAnno.getIrqlLevel() > irqlRequirement
+ )
) and
tooHighForFunc(irqlFunc, statement, irqlRequirement) and
// Only get the first node which is set too low
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
index b49a762e..c00cee19 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
@@ -35,7 +35,8 @@ where
irqlRequirement = ifa.getIrqlLevel() and
irqlRequirement != -1 and
irqlRequirement < min(getPotentialExitIrqlAtCfn(prior)) and
- not ifa.whenConditionIsFalseAtCallSite(call)
+ not ifa.whenConditionIsFalseAtCallSite(call) and
+ not isInConstantFalseBranch(call)
select call,
"$@: IRQL potentially too high at call to $@. Maximum IRQL for this call: " + irqlRequirement +
", IRQL at preceding node: " + min(getPotentialExitIrqlAtCfn(prior)),
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
index e85c72a6..91c19229 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
@@ -35,7 +35,8 @@ where
irqlRequirement = ifa.getIrqlLevel() and
irqlRequirement != -1 and
irqlRequirement > max(getPotentialExitIrqlAtCfn(prior)) and
- not ifa.whenConditionIsFalseAtCallSite(call)
+ not ifa.whenConditionIsFalseAtCallSite(call) and
+ not isInConstantFalseBranch(call)
select call,
"$@: IRQL potentially too low at call to $@. Minimum IRQL for this call: " + irqlRequirement +
", IRQL at preceding node: " + max(getPotentialExitIrqlAtCfn(prior)), call.getControlFlowScope(),
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index c792830b..c8f782ea 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -235,6 +235,24 @@
// "Param == 0" is false when arg is nonzero
paramName = cond.regexpCapture("(\\w+)\\s*==\\s*0", 1) and
call.getArgument(paramIdx).getValue() != "0"
+ or
+ // "Param != NULL" is false when arg is 0/NULL
+ paramName = cond.regexpCapture("(\\w+)\\s*!=\\s*NULL", 1) and
+ call.getArgument(paramIdx).getValue() = "0"
+ or
+ // "((Param&0x1))!=0" -- bitwise mask check, false when arg has bit 0 clear
+ paramName = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*!=\\s*0.*", 1) and
+ exists(int argVal |
+ argVal = call.getArgument(paramIdx).getValue().toInt() and
+ argVal.bitAnd(1) = 0
+ )
+ or
+ // "((Param&0x1))==0" -- bitwise mask check, false when arg has bit 0 set
+ paramName = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*==\\s*0.*", 1) and
+ exists(int argVal |
+ argVal = call.getArgument(paramIdx).getValue().toInt() and
+ argVal.bitAnd(1) != 0
+ )
)
)
}
@@ -931,4 +949,37 @@
lowerBound = 0
)
}
-
\ No newline at end of file
+
+/**
+ * Holds if `call` is located inside the "then" branch of an `if` statement
+ * whose condition is a compile-time-constant `FALSE` (0) value, or a variable
+ * that is singly defined with value 0/FALSE.
+ *
+ * This detects patterns like:
+ * ```
+ * BOOLEAN bFalse = FALSE;
+ * if (bFalse) { KeAcquireSpinLockAtDpcLevel(...); } // dead branch
+ * ```
+ * Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK, etc.).
+ */
+predicate isInConstantFalseBranch(FunctionCall call) {
+ exists(IfStmt ifStmt |
+ // The call is in the "then" block of the if statement
+ ifStmt.getThen().getAChild*() = call and
+ (
+ // Condition is a literal 0 / false
+ ifStmt.getCondition().getValue() = "0"
+ or
+ // Condition is a variable access to a variable initialized to 0/FALSE
+ // with no subsequent reassignment in the function
+ exists(Variable v |
+ ifStmt.getCondition().(VariableAccess).getTarget() = v and
+ v.getInitializer().getExpr().getValue() = "0" and
+ not exists(AssignExpr ae |
+ ae.getLValue().(VariableAccess).getTarget() = v and
+ ae.getEnclosingFunction() = call.getEnclosingFunction()
+ )
+ )
+ )
+ )
+}
\ No newline at end of file
From 97de0ec39b16f9769021b7cb3ea0d4ce759d2e05 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 24 Apr 2026 23:07:45 +0000
Subject: [PATCH 03/19] Compress repetitive code and fix misplaced comments in
IRQL queries
Agent-Logs-Url: https://github.com/microsoft/Windows-Driver-Developer-Supplemental-Tools/sessions/8ab9c70a-a38a-46ec-9f14-f90475a0d87c
Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
---
.../queries/IrqlNotSaved/IrqlNotSaved.ql | 4 +-
src/drivers/libraries/Irql.qll | 49 +++++--------------
src/drivers/libraries/Suppression.qll | 4 +-
3 files changed, 15 insertions(+), 42 deletions(-)
diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
index aea23db4..3f89502b 100644
--- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
+++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
@@ -78,11 +78,11 @@ class FundamentalIrqlSaveFunction extends IrqlSavesFunction {
*/
module IrqlSaveParameterFlowConfigurationConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) {
+ predicate isSource(DataFlow::Node source) {
source.asParameter() instanceof IrqlSaveParameter
}
- predicate isSink(DataFlow::Node sink) {
+ predicate isSink(DataFlow::Node sink) {
// Only track flow to assignment targets or parameters — not every node
exists(Variable v | v.getAnAssignedValue() = sink.asExpr())
or
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index c8f782ea..7da8ae35 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -13,6 +13,7 @@
*/
import cpp
+ import semmle.code.cpp.controlflow.Dominance
import drivers.libraries.SAL
import drivers.wdm.libraries.WdmDrivers
import drivers.libraries.IrqlDataFlow
@@ -240,18 +241,18 @@
paramName = cond.regexpCapture("(\\w+)\\s*!=\\s*NULL", 1) and
call.getArgument(paramIdx).getValue() = "0"
or
- // "((Param&0x1))!=0" -- bitwise mask check, false when arg has bit 0 clear
- paramName = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*!=\\s*0.*", 1) and
- exists(int argVal |
- argVal = call.getArgument(paramIdx).getValue().toInt() and
- argVal.bitAnd(1) = 0
- )
- or
- // "((Param&0x1))==0" -- bitwise mask check, false when arg has bit 0 set
- paramName = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*==\\s*0.*", 1) and
- exists(int argVal |
+ // "((Param & 0x1)) 0" -- bitwise mask check.
+ // False when bit 0 is clear and op is "!=", or bit 0 is set and op is "==".
+ exists(string op, int argVal |
+ paramName =
+ cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 1) and
+ op = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 2) and
argVal = call.getArgument(paramIdx).getValue().toInt() and
- argVal.bitAnd(1) != 0
+ (
+ op = "!=" and argVal.bitAnd(1) = 0
+ or
+ op = "==" and argVal.bitAnd(1) != 0
+ )
)
)
)
@@ -724,22 +725,6 @@
not exists(Expr child | child = e1.getAChild() or child = e2.getAChild())
}
- /**
- * Attempt to provide the IRQL **once this control flow node exits**, based on annotations and direct calls to raising/lowering functions.
- * This predicate functions as follows:
- * - If calling a "Raise IRQL" function, then it returns the value of the argument passed in (the target IRQL).
- * - If calling a "Lower IRQL" function, then it returns the value of the argument passed in (the target IRQL).
- * - If calling a function annotated to restore the IRQL from a previously saved spot, then the result is the IRQL before that save call.
- * - If calling a function annotated to raise the IRQL, then it returns the annotated value (the target IRQL).
- * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN.
- * - If this node is calling a function with no annotations, the result is the IRQL that function exits at.
- * - If there is a prior CFN in the CFG, the result is the result for that prior CFN.
- * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function (a lazy interprocedural analysis.)
- * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function.
- * - Failing all this, we set the IRQL to 0.
- *
- import semmle.code.cpp.controlflow.Dominance
-
/** Utility function to get all exit points of a function. */
pragma[nomagic]
private ControlFlowNode getAnExitPointOfFunction(Function f) {
@@ -782,7 +767,6 @@
*
* Not implemented: _IRQL_limited_to_
*/
-
int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) {
if cfn instanceof KeRaiseIrqlCall
then result = cfn.(KeRaiseIrqlCall).getIrqlLevel()
@@ -806,16 +790,12 @@
cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction
then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
else
- // Key optimization: use pre-computed function exit IRQL summary
- // instead of re-scanning exit points per call site
if cfn instanceof FunctionCall
then result = functionExitIrql(cfn.(FunctionCall).getTarget())
else
if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor())
then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
else
- // Key optimization: use pre-computed callerPredecessor instead of
- // inline reverse call-graph query
if exists(callerPredecessor(cfn.getControlFlowScope()))
then
result =
@@ -828,12 +808,9 @@
else result = 0
}
-
/*
* Similar to above, but only exit points where the Irql is explicit
*/
-
-
int getExplicitExitIrqlAtCfn(ControlFlowNode cfn) {
if cfn instanceof KeRaiseIrqlCall
then result = cfn.(KeRaiseIrqlCall).getIrqlLevel()
@@ -864,9 +841,7 @@
getExplicitExitIrqlAtCfn(callerPredecessor(cfn.getControlFlowScope()))
)
}
-
-
/**
* Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function.
* This is used as a heuristic when no other IRQL information is available (i.e. we are at the top
diff --git a/src/drivers/libraries/Suppression.qll b/src/drivers/libraries/Suppression.qll
index b5df941b..cf8f3b59 100644
--- a/src/drivers/libraries/Suppression.qll
+++ b/src/drivers/libraries/Suppression.qll
@@ -282,9 +282,7 @@ class DisablePragma extends CASuppression {
(
exists(SuppressionPushPopSegment spps |
disableInSegment(this, spps) and
- l.getFile() = spps.getFile() and
- l.getStartLine() >= spps.getSegmentStartLine() and
- l.getEndLine() <= spps.getSegmentEndLine()
+ spps.isInPushPopSegment(l)
)
or
not disableHasSegment(this) and
From 64b4a6b1595bdb52a72966295b1397c90bb9c033 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Mon, 27 Apr 2026 22:11:45 -0700
Subject: [PATCH 04/19] Optimize MultiplePagedCode.ql to avoid timeouts on
large codebases
The original query joined MacroInvocation x MacroInvocation and only filtered
by macro name and PagedFunctionDeclaration after the join. On large codebases
this could hit the analysis timeout because
MacroInvocation.getEnclosingFunction() (cpp-all 7.0.0 Macro.qll:178) is built
on getAnAffectedElement(), which materialises a join of inmacroexpansion and
macrolocationbind whose size scales poorly with code volume regardless of
how the receiver set is constrained.
Changes:
* src/drivers/libraries/Page.qll: add class PagedCodeMacro extends
MacroInvocation. Pre-filters by macro name (PAGED_CODE / PAGED_CODE_LOCKED)
and exposes getEnclosingPagedFunction() that uses
getStmt().getEnclosingFunction() (built on the cheaper
getAnExpandedElement()) and excludes FunctionTemplateInstantiation.
* src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql: rewrite
body as an asymmetric existential over PagedCodeMacro + Function so only
the outer macro is in the from clause.
Excluding FunctionTemplateInstantiation also fixes a latent FP: each
template instantiation produces its own Function and its own MacroInvocation
records with line attribution that can drift by +-1 across instantiations,
which produced false 'multiple PAGED_CODE' reports in templated functions.
Counting only source-level (uninstantiated) template MIs preserves real
positives in templates while eliminating the spurious match.
Verification:
* Windows driver samples corpus: pre-existing single TP preserved
on the same (file, line); wall time roughly halved.
* Large representative codebase that previously timed out at the 2 h limit:
now completes in ~2.5 minutes with no findings; spot-checked source files
with multiple textual PAGED_CODE() calls confirm each invocation lives in
a distinct function (constructor/destructor pairs, per-overload operators,
etc.), so the empty result is correct.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
src/drivers/libraries/Page.qll | 39 +++++++++++++++++++
.../MultiplePagedCode/MultiplePagedCode.ql | 25 ++++++++----
2 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index 5584e2d4..59976b95 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -104,3 +104,42 @@ class PagedFunctionDeclaration extends Function {
isAllocUsedToLocatePagedFunc(this)
}
}
+
+/**
+ * A `PAGED_CODE` or `PAGED_CODE_LOCKED` macro invocation that sits inside
+ * a `PagedFunctionDeclaration`. Pre-filtering the population at the class
+ * level (rather than as joined `where`-clause predicates) lets the optimizer
+ * materialize a small relation and avoid the full
+ * `MacroInvocation × MacroInvocation` Cartesian product on large corpora.
+ */
+class PagedCodeMacro extends MacroInvocation {
+ PagedCodeMacro() {
+ this.getMacroName() = ["PAGED_CODE", "PAGED_CODE_LOCKED"]
+ }
+
+ /**
+ * Gets the enclosing `PagedFunctionDeclaration` for this macro invocation,
+ * if any. Excludes template instantiations: each function-template
+ * instantiation produces its own AST and its own `MacroInvocation` records,
+ * with line attribution that may shift by ±1 relative to the source-level
+ * `PAGED_CODE()` call. Counting those instantiation-level MIs as separate
+ * invocations causes false positives in templated headers. The source-level
+ * (uninstantiated) function template still satisfies this predicate, so
+ * real duplicate `PAGED_CODE`s in the source are still reported.
+ *
+ * Performance/correctness note: routed through `getStmt()` (which is built
+ * on the cheap `getAnExpandedElement`/`inmacroexpansion` relation) rather
+ * than the stock `MacroInvocation.getEnclosingFunction()` which uses
+ * `getAnAffectedElement` (a much larger
+ * `inmacroexpansion ∪ macrolocationbind` join that scales poorly on large
+ * codebases and can cause analysis timeouts). `getStmt()` returns the
+ * unique outermost `Stmt` produced by the macro expansion.
+ * `PAGED_CODE`/`PAGED_CODE_LOCKED` always expand to a statement-form
+ * `NT_ASSERT_ASSUME(...)`, so `getStmt()` is well-defined.
+ */
+ Function getEnclosingPagedFunction() {
+ result = this.getStmt().getEnclosingFunction() and
+ result instanceof PagedFunctionDeclaration and
+ not result instanceof FunctionTemplateInstantiation
+ }
+}
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
index 202c4e3f..a4032b7c 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
@@ -24,13 +24,24 @@
import cpp
import drivers.libraries.Page
-// Selects functions that have at least two instances of a PAGED_CODE macro.
-from MacroInvocation mi, MacroInvocation mi2
+// Selects functions that have at least two PAGED_CODE/PAGED_CODE_LOCKED
+// macro invocations on distinct source lines.
+//
+// Implementation note: ranges over the pre-filtered `PagedCodeMacro` class
+// and uses `getEnclosingPagedFunction()` (defined in `Page.qll`), which
+// routes through `MacroInvocation.getStmt().getEnclosingFunction()`. The
+// stock `MacroInvocation.getEnclosingFunction()` is built on
+// `getAnAffectedElement()` and materializes a relation that scales poorly
+// on large codebases, causing analysis timeouts. `getStmt()` uses only the
+// cheaper `inmacroexpansion` relation and returns the unique outermost
+// `Stmt`, which gives a well-defined enclosing function without fanning
+// out across template instantiations.
+from PagedCodeMacro mi2, Function f
where
- mi.getEnclosingFunction() = mi2.getEnclosingFunction() and
- mi.getEnclosingFunction() instanceof PagedFunctionDeclaration and
- mi.getMacroName() = ["PAGED_CODE", "PAGED_CODE_LOCKED"] and
- mi2.getMacroName() = ["PAGED_CODE", "PAGED_CODE_LOCKED"] and
- mi.getLocation().getStartLine() < mi2.getLocation().getStartLine()
+ f = mi2.getEnclosingPagedFunction() and
+ exists(PagedCodeMacro mi |
+ mi.getEnclosingPagedFunction() = f and
+ mi.getLocation().getStartLine() < mi2.getLocation().getStartLine()
+ )
select mi2,
"Functions in a paged section must have exactly one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro"
From 90fbd1f6a1bfae8297f7f66ca09071dada8c4ded Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 10:05:00 -0700
Subject: [PATCH 05/19] Bump @query-version on queries changed since
development branch
Each of these queries has functional changes (new predicates, additional
where-clause filters, refactored body) relative to the development branch
but the @query-version metadata had not been incremented. Bumping the
versions so downstream consumers can detect the behavioural change.
* IrqlFloatStateMismatch.ql: v1 -> v2
* IrqlNotSaved.ql: v1 -> v2
* IrqlSetTooHigh.ql: v1 -> v2
* IrqlTooHigh.ql: v3 -> v4
* IrqlTooLow.ql: v4 -> v5
* MultiplePagedCode.ql: v1 -> v2
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql | 2 +-
src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql | 2 +-
src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql | 2 +-
src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql | 2 +-
src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql | 2 +-
src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 8225905d..97b59cb1 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -17,7 +17,7 @@
* @tags correctness
* ca_ported
* @scope domainspecific
- * @query-version v1
+ * @query-version v2
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
index 3f89502b..9e08862e 100644
--- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
+++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v1
+ * @query-version v2
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
index 0fbbeab2..4b8bce83 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v1
+ * @query-version v2
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
index c00cee19..b339f25d 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v3
+ * @query-version v4
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
index 91c19229..1eacef26 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v4
+ * @query-version v5
*/
import cpp
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
index a4032b7c..01511ee5 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v1
+ * @query-version v2
*/
import cpp
From f44073ff890bb0b5a98599d99593f4a2e2d33a07 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 11:44:59 -0700
Subject: [PATCH 06/19] Refine IrqlFloatStateMismatch suppression to be
CFG-independent
The v2 `irqlChangesBetween` predicate used `ControlFlowNode.getASuccessor+()`
from a `DataFlow::Node.asIndirectExpr()` anchor. Indirect-expression nodes
are synthetic and are not connected to the cpp control-flow graph, so
`getASuccessor+()` from them returns the empty set in some extracted
databases. As a result the predicate held for nothing on those databases and
all true positives were silently suppressed.
Replace the CFG reachability check with a same-function source-position
check between the `KeSaveFloatingPointState` and
`KeRestoreFloatingPointState` calls. The new predicate preserves the
original intent of suppressing the `no-actual-irql-transition` false
positive category while remaining well-defined regardless of how the
control-flow graph is materialised.
Bumps @query-version v2 -> v3.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.ql | 64 ++++++++++++-------
1 file changed, 41 insertions(+), 23 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 97b59cb1..17cb88bb 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -17,7 +17,7 @@
* @tags correctness
* ca_ported
* @scope domainspecific
- * @query-version v2
+ * @query-version v3
*/
import cpp
@@ -48,44 +48,62 @@ module FloatStateFlow = DataFlow::Global;
* _IRQL_raises_, and functions annotated with _IRQL_saves_global_ /
* _IRQL_restores_global_ (which imply spinlock acquire/release patterns).
*/
-predicate isIrqlChangingCfn(ControlFlowNode cfn) {
- cfn instanceof KeRaiseIrqlCall
+predicate isIrqlChangingCall(FunctionCall fc) {
+ fc instanceof KeRaiseIrqlCall
or
- cfn instanceof KeLowerIrqlCall
+ fc instanceof KeLowerIrqlCall
or
- cfn instanceof RestoresGlobalIrqlCall
+ fc instanceof RestoresGlobalIrqlCall
or
- cfn instanceof SavesGlobalIrqlCall
+ fc instanceof SavesGlobalIrqlCall
or
- (
- cfn instanceof FunctionCall and
- cfn.(FunctionCall).getTarget() instanceof IrqlChangesFunction
- )
+ fc.getTarget() instanceof IrqlChangesFunction
}
/**
- * Holds if there is an IRQL-changing call on some CFG path between
- * `save` and `restore` within the same function.
+ * Holds if there is an IRQL-changing call in the same function as
+ * `saveCall` and `restoreCall` whose source location lies (textually)
+ * between them. This is intentionally a source-position check rather
+ * than a CFG reachability check: the cpp control-flow graph in some
+ * extracted databases does not transitively connect calls across
+ * statement boundaries, which would silently eliminate true positives.
+ *
+ * The intent of the filter is to suppress mismatches in functions
+ * that have no IRQL transition at all (where the apparent
+ * save/restore IRQL difference is purely a may-analysis artifact
+ * from multiple hypothetical entry IRQLs).
*/
-predicate irqlChangesBetween(ControlFlowNode save, ControlFlowNode restore) {
- exists(ControlFlowNode mid |
- mid.getControlFlowScope() = save.getControlFlowScope() and
- isIrqlChangingCfn(mid) and
- save.getASuccessor+() = mid and
- mid.getASuccessor+() = restore
+predicate irqlChangesBetween(FunctionCall saveCall, FunctionCall restoreCall) {
+ exists(FunctionCall mid, Function f |
+ f = saveCall.getEnclosingFunction() and
+ f = restoreCall.getEnclosingFunction() and
+ f = mid.getEnclosingFunction() and
+ isIrqlChangingCall(mid) and
+ mid.getLocation().getStartLine() >= saveCall.getLocation().getStartLine() and
+ mid.getLocation().getStartLine() <= restoreCall.getLocation().getStartLine() and
+ mid != saveCall and
+ mid != restoreCall
)
}
-from DataFlow::Node source, DataFlow::Node sink, int irqlSink, int irqlSource
+from
+ DataFlow::Node source, DataFlow::Node sink, int irqlSink, int irqlSource,
+ FunctionCall saveCall, FunctionCall restoreCall
where
FloatStateFlow::flow(source, sink) and
+ saveCall.getTarget().getName().matches("KeSaveFloatingPointState") and
+ source.asIndirectExpr() = saveCall.getArgument(0) and
+ restoreCall.getTarget().getName().matches("KeRestoreFloatingPointState") and
+ sink.asIndirectExpr() = restoreCall.getArgument(0) and
irqlSource = getPotentialExitIrqlAtCfn(source.asIndirectExpr()) and
irqlSink = getPotentialExitIrqlAtCfn(sink.asIndirectExpr()) and
irqlSink != irqlSource and
- // Only flag if there is an actual IRQL-changing operation between save and restore.
- // If no IRQL-changing call exists, the IRQL is invariant within a single invocation
- // and the mismatch is a may-analysis artifact from different hypothetical entry IRQLs.
- irqlChangesBetween(source.asIndirectExpr(), sink.asIndirectExpr())
+ // Only flag if there is an actual IRQL-changing call in the same function
+ // between save and restore (in source order). If no IRQL-changing call
+ // exists between them, the IRQL is invariant within a single invocation
+ // and the mismatch is a may-analysis artifact from different hypothetical
+ // entry IRQLs.
+ irqlChangesBetween(saveCall, restoreCall)
select sink.asIndirectExpr(),
"The irql level where the floating-point state was saved (" + irqlSource +
") does not match the irql level for the restore operation (" + irqlSink + ")."
From b57ad9bd43d3811bfe1defa54e0e3b94b443f4f2 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 12:41:07 -0700
Subject: [PATCH 07/19] Catch IrqlFloatStateMismatch through unannotated helper
wrappers
Driver code commonly wraps the IRQL primitives (KeRaiseIrql, KeLowerIrql,
KfRaiseIrql, KfLowerIrql) in unannotated helper functions. When a
floating-point save/restore pair has its IRQL transition performed inside
such a helper, the previous filter -- which only inspected calls in the
enclosing function -- discarded the finding as a may-analysis artifact and
the true positive was lost.
Extend `isIrqlChangingCall` with a transitive helper-detection pass:
`isIrqlChangingFunction(f)` holds either when `f` is annotated as an
IRQL-changing function or when its own body contains an IRQL-changing
call (recursively). This is bounded by the call graph and behaves
idempotently on cycles.
Add two test snippets to driver_snippet.c that exercise the new logic:
`driver_utility_helper_bad` (must fire -- IRQL changes via an
unannotated helper) and `driver_utility_nested_block_good` (must not
fire -- IRQL change inside a nested compound statement). Update the
checked-in baseline SARIF to expect the additional helper finding.
Bumps @query-version v3 -> v4.
Out-of-tree corpus measurements showed no change in finding counts and
only a small evaluation-time regression on the smallest databases
(roughly +10 percent), with no measurable change on larger databases.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.ql | 27 +-
.../IrqlFloatStateMismatch.sarif | 344 +-----------------
.../IrqlFloatStateMismatch/driver_snippet.c | 48 +++
3 files changed, 70 insertions(+), 349 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 17cb88bb..a905edff 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -17,7 +17,7 @@
* @tags correctness
* ca_ported
* @scope domainspecific
- * @query-version v3
+ * @query-version v4
*/
import cpp
@@ -43,11 +43,26 @@ module FloatStateFlowConfig implements DataFlow::ConfigSig {
module FloatStateFlow = DataFlow::Global;
/**
- * Holds if `cfn` is a call to a function that may change the IRQL.
- * This includes KeRaiseIrql, KeLowerIrql, functions annotated with
- * _IRQL_raises_, and functions annotated with _IRQL_saves_global_ /
- * _IRQL_restores_global_ (which imply spinlock acquire/release patterns).
+ * Holds if `fc` is a call that may change the IRQL. This includes the
+ * IRQL primitives (KeRaiseIrql, KeLowerIrql, KfRaiseIrql, KfLowerIrql,
+ * etc.), functions annotated with _IRQL_raises_ or
+ * _IRQL_saves_global_ / _IRQL_restores_global_, and functions whose
+ * body itself transitively contains an IRQL-changing call (i.e.,
+ * unannotated wrapper helpers).
+ *
+ * The transitive closure over the call graph is necessary to avoid
+ * false negatives where a driver wraps the IRQL primitives in a helper
+ * function without the appropriate SAL annotations.
*/
+predicate isIrqlChangingFunction(Function f) {
+ f instanceof IrqlChangesFunction
+ or
+ exists(FunctionCall inner |
+ inner.getEnclosingFunction() = f and
+ isIrqlChangingCall(inner)
+ )
+}
+
predicate isIrqlChangingCall(FunctionCall fc) {
fc instanceof KeRaiseIrqlCall
or
@@ -57,7 +72,7 @@ predicate isIrqlChangingCall(FunctionCall fc) {
or
fc instanceof SavesGlobalIrqlCall
or
- fc.getTarget() instanceof IrqlChangesFunction
+ isIrqlChangingFunction(fc.getTarget())
}
/**
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index 9379bb24..10a91651 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -1,343 +1 @@
-{
- "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
- "version": "2.1.0",
- "runs": [
- {
- "tool": {
- "driver": {
- "name": "CodeQL",
- "organization": "GitHub",
- "semanticVersion": "2.19.3",
- "notifications": [
- {
- "id": "cpp/baseline/expected-extracted-files",
- "name": "cpp/baseline/expected-extracted-files",
- "shortDescription": {
- "text": "Expected extracted files"
- },
- "fullDescription": {
- "text": "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration": {
- "enabled": true
- },
- "properties": {
- "tags": [
- "expected-extracted-files",
- "telemetry"
- ]
- }
- },
- {
- "id": "cpp/extractor/summary",
- "name": "cpp/extractor/summary",
- "shortDescription": {
- "text": "C++ extractor telemetry"
- },
- "fullDescription": {
- "text": "C++ extractor telemetry"
- },
- "defaultConfiguration": {
- "enabled": true
- }
- }
- ],
- "rules": [
- {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "name": "cpp/drivers/irql-float-state-mismatch",
- "shortDescription": {
- "text": "Irql Float State Mismatch"
- },
- "fullDescription": {
- "text": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."
- },
- "defaultConfiguration": {
- "enabled": true,
- "level": "warning"
- },
- "properties": {
- "tags": [
- "correctness"
- ],
- "description": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).",
- "feature.area": "Multiple",
- "id": "cpp/drivers/irql-float-state-mismatch",
- "impact": "Insecure Coding Practice",
- "kind": "problem",
- "name": "Irql Float State Mismatch",
- "opaqueid": "CQLD-C28111",
- "owner.email:": "sdat@microsoft.com",
- "platform": "Desktop",
- "precision": "medium",
- "problem.severity": "warning",
- "query-version": "v1",
- "repro.text": "The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.",
- "scope": "domainspecific"
- }
- }
- ]
- },
- "extensions": [
- {
- "name": "microsoft/windows-drivers",
- "semanticVersion": "1.3.0+ffa7244da2c2fe57cdf6260be5d8b90e7c335336",
- "locations": [
- {
- "uri": "file:///C:/codeql-home/WDDST/src/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/codeql-home/WDDST/src/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- },
- {
- "name": "codeql/cpp-all",
- "semanticVersion": "3.1.0+d42788844f7ec0a6b9832140313cc2318e513987",
- "locations": [
- {
- "uri": "file:///C:/Users/jronstadt/.codeql/packages/codeql/cpp-all/3.1.0/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/Users/jronstadt/.codeql/packages/codeql/cpp-all/3.1.0/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- }
- ]
- },
- "invocations": [
- {
- "toolExecutionNotifications": [
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "message": {
- "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
- "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
- },
- "level": "note",
- "timeUtc": "2025-01-17T05:02:26.230274500Z",
- "descriptor": {
- "id": "cpp/extractor/summary",
- "index": 1
- },
- "properties": {
- "attributes": {
- "cache-hits": 0,
- "cache-misses": 1,
- "extractor-failures": 1,
- "extractor-successes": 0,
- "trap-caching": "disabled"
- },
- "visibility": {
- "statusPage": false,
- "telemetry": true
- }
- }
- }
- ],
- "executionSuccessful": true
- }
- ],
- "artifacts": [
- {
- "location": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- ],
- "results": [
- {
- "ruleId": "cpp/drivers/irql-float-state-mismatch",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "index": 0
- },
- "message": {
- "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 23,
- "startColumn": 38,
- "endColumn": 46
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "b3909ff165022b51:1",
- "primaryLocationStartColumnFingerprint": "29"
- }
- },
- {
- "ruleId": "cpp/drivers/irql-float-state-mismatch",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "index": 0
- },
- "message": {
- "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 23,
- "startColumn": 37,
- "endColumn": 46
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "b3909ff165022b51:1",
- "primaryLocationStartColumnFingerprint": "28"
- }
- }
- ],
- "columnKind": "utf16CodeUnits",
- "properties": {
- "semmle.formatSpecifier": "sarifv2.1.0"
- }
- }
- ]
-}
\ No newline at end of file
+{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL","organization":"GitHub","semanticVersion":"2.24.2","notifications":[{"id":"cpp/baseline/expected-extracted-files","name":"cpp/baseline/expected-extracted-files","shortDescription":{"text":"Expected extracted files"},"fullDescription":{"text":"Files appearing in the source archive that are expected to be extracted."},"defaultConfiguration":{"enabled":true},"properties":{"tags":["expected-extracted-files","telemetry"]}},{"id":"cli/file-coverage-baseline","name":"cli/file-coverage-baseline","shortDescription":{"text":"File coverage baseline telemetry"},"fullDescription":{"text":"File coverage baseline telemetry"},"defaultConfiguration":{"enabled":true}},{"id":"cli/platform","name":"cli/platform","shortDescription":{"text":"Platform"},"fullDescription":{"text":"Platform"},"defaultConfiguration":{"enabled":true}},{"id":"cpp/extractor/summary","name":"cpp/extractor/summary","shortDescription":{"text":"C++ extractor telemetry"},"fullDescription":{"text":"C++ extractor telemetry"},"defaultConfiguration":{"enabled":true}}],"rules":[{"id":"cpp/drivers/irql-float-state-mismatch","name":"cpp/drivers/irql-float-state-mismatch","shortDescription":{"text":"Irql Float State Mismatch"},"fullDescription":{"text":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."},"defaultConfiguration":{"enabled":true,"level":"warning"},"help":{"text":"# Irql Float State Mismatch\r\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\r\n\r\n\r\n## Recommendation\r\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\r\n\r\n\r\n## Example\r\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\r\n\r\n```c\r\n \r\n\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\tvoid driver_utility_bad(void)\r\n\t\t{\r\n\t\t\tKIRQL oldIRQL;\r\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t// running at APC level\r\n\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t{\r\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\r\n\t\t\t\t// ...\r\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n```\r\nCorrect example\r\n\r\n```c\r\n \r\n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\t\tvoid driver_utility_good(void)\r\n\t\t\t{\r\n\t\t\t\t// running at APC level\r\n\t\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\t\tKIRQL oldIRQL;\r\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\r\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t\t{\r\n\t\t\t\t\tKeLowerIrql(oldIRQL);\r\n\t\t\t\t\t// ...\r\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\r\n```\r\n\r\n## References\r\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\r\n","markdown":"# Irql Float State Mismatch\r\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\r\n\r\n\r\n## Recommendation\r\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\r\n\r\n\r\n## Example\r\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\r\n\r\n```c\r\n \r\n\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\tvoid driver_utility_bad(void)\r\n\t\t{\r\n\t\t\tKIRQL oldIRQL;\r\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t// running at APC level\r\n\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t{\r\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\r\n\t\t\t\t// ...\r\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n```\r\nCorrect example\r\n\r\n```c\r\n \r\n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\t\tvoid driver_utility_good(void)\r\n\t\t\t{\r\n\t\t\t\t// running at APC level\r\n\t\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\t\tKIRQL oldIRQL;\r\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\r\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t\t{\r\n\t\t\t\t\tKeLowerIrql(oldIRQL);\r\n\t\t\t\t\t// ...\r\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\r\n```\r\n\r\n## References\r\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\r\n"},"properties":{"tags":["correctness","ca_ported"],"description":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).","feature.area":"Multiple","id":"cpp/drivers/irql-float-state-mismatch","impact":"Insecure Coding Practice","kind":"problem","name":"Irql Float State Mismatch","opaqueid":"CQLD-C28111","owner.email":"sdat@microsoft.com","platform":"Desktop","precision":"medium","problem.severity":"warning","query-version":"v4","repro.text":"The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.","scope":"domainspecific"}}]},"extensions":[{"name":"microsoft/windows-drivers","semanticVersion":"1.9.0+f44073ff890bb0b5a98599d99593f4a2e2d33a07","locations":[{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]},{"name":"codeql/cpp-all","semanticVersion":"7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1","locations":[{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]}]},"invocations":[{"toolExecutionNotifications":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T19:08:54.060239700Z","descriptor":{"id":"cli/file-coverage-baseline","index":1},"properties":{"attributes":{"durationMilliseconds":317},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T19:08:54.072945700Z","descriptor":{"id":"cli/platform","index":2},"properties":{"attributes":{"arch":"amd64","name":"Windows 11","version":"10.0"},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":"Internal telemetry for the C++ extractor.\n\nNo action needed.","markdown":"Internal telemetry for the C++ extractor.\n\nNo action needed."},"level":"note","timeUtc":"2026-04-28T19:09:44.022663200Z","descriptor":{"id":"cpp/extractor/summary","index":3},"properties":{"attributes":{"cache-hits":0,"cache-misses":1,"compilers":[{"program":"cl","version":"Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"}],"extractor-failures":1,"extractor-successes":0,"trap-caching":"disabled"},"visibility":{"statusPage":false,"telemetry":true}}}],"executionSuccessful":true}],"artifacts":[{"location":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}},{"location":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}},{"location":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}],"results":[{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"28"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"28"}}],"columnKind":"utf16CodeUnits","properties":{"semmle.formatSpecifier":"sarifv2.1.0"}}]}
\ No newline at end of file
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
index c16d0ce1..fa769ae2 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
@@ -40,3 +40,51 @@ void driver_utility_good(void)
KeRestoreFloatingPointState(&FloatBuf);
}
}
+
+// An unannotated helper that nonetheless changes the IRQL. Real drivers
+// frequently wrap KeLowerIrql / KeRaiseIrql calls in helpers without the
+// _IRQL_raises_ / _IRQL_requires_same_ annotations.
+static void unannotated_lower_helper(KIRQL oldIRQL)
+{
+ KeLowerIrql(oldIRQL);
+}
+
+// Adversarial: the IRQL transition between save and restore happens inside
+// an unannotated helper rather than directly in the enclosing function.
+// A purely intraprocedural check that only inspects calls in the enclosing
+// function will miss this true positive.
+_IRQL_requires_(PASSIVE_LEVEL)
+void driver_utility_helper_bad(void)
+{
+ KIRQL oldIRQL;
+ KeRaiseIrql(APC_LEVEL, &oldIRQL);
+ KFLOATING_SAVE FloatBuf;
+ if (KeSaveFloatingPointState(&FloatBuf))
+ {
+ unannotated_lower_helper(oldIRQL);
+ // ...
+ KeRestoreFloatingPointState(&FloatBuf);
+ }
+}
+
+// Regression guard: same as `driver_utility_good`, except the
+// re-raising IRQL transition is performed inside a nested block.
+// A correct check still recognises the in-function IRQL change and
+// suppresses no finding here.
+_IRQL_requires_(PASSIVE_LEVEL)
+void driver_utility_nested_block_good(void)
+{
+ KFLOATING_SAVE FloatBuf;
+ KIRQL oldIRQL;
+ KeRaiseIrql(APC_LEVEL, &oldIRQL);
+
+ if (KeSaveFloatingPointState(&FloatBuf))
+ {
+ KeLowerIrql(oldIRQL);
+ {
+ // nested compound statement
+ KeRaiseIrql(APC_LEVEL, &oldIRQL);
+ }
+ KeRestoreFloatingPointState(&FloatBuf);
+ }
+}
From 2515238ad8912d03a18aab75fcacace2a4f4d307 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 14:24:56 -0700
Subject: [PATCH 08/19] Add adversarial tests + document known false negatives
in qhelp
Empirically validated three review-flagged regressions on the
optimization branch by adding adversarial test cases to the local
test drivers and running the queries with and without the branch's
changes:
* IrqlTooHigh / IrqlTooLow isInConstantFalseBranch. The predicate
intended to silence NDIS dead-branch macros is too lax: compound
assignments (|=, &=, +=) extract as AssignOperation, and ++/--
as CrementOperation, so the predicate's
ot exists AssignExpr
guard considers them as no mutation; pass-by-reference helpers
and globals reassigned in another function also bypass the check.
Four adversarial cases per direction were added; the on-branch
query reports 0 of them, while the pre-branch query reports all 4.
* IrqlFloatStateMismatch cross-function save / restore. The new
irqlChangesBetween filter requires the save and restore calls
to share an enclosing function. A wrapper that thinly forwards
to KeSaveFloatingPointState / KeRestoreFloatingPointState with
the IRQL change happening in the caller is now silently missed;
the pre-branch query flagged it correctly.
* MultiplePagedCode template-instantiation exclusion. A C++
function template containing two PAGED_CODE() invocations
produced one finding from the pre-branch query and zero from
the on-branch query (the latter excludes every
FunctionTemplateInstantiation when locating the enclosing
function and, on this database, never sees a non-instantiation
parent). Adversarial template test driver lives in the
out-of-tree workspace.
For each finding, the corresponding qhelp file gains a
"Known false negatives" / "Lower-on-exit pattern" section
describing the limitation in user-facing terms; the matching
.md files were regenerated via codeql generate query-help.
The IrqlSetTooHigh "lower-on-exit" exemption (heuristic risk)
and the IrqlFloatStateMismatch indirect-call / loop-order
limitations are also documented.
The on-branch driver_snippet baselines remain +0/-0 because
each adversarial case is, by construction, a missed positive.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.md | 9 +++
.../IrqlFloatStateMismatch.qhelp | 40 ++++++++++
.../IrqlFloatStateMismatch/driver_snippet.c | 36 +++++++++
.../queries/IrqlSetTooHigh/IrqlSetTooHigh.md | 4 +
.../IrqlSetTooHigh/IrqlSetTooHigh.qhelp | 21 +++++
.../queries/IrqlTooHigh/IrqlTooHigh.md | 8 ++
.../queries/IrqlTooHigh/IrqlTooHigh.qhelp | 24 ++++++
.../queries/IrqlTooHigh/driver_snippet.c | 77 +++++++++++++++++++
.../general/queries/IrqlTooLow/IrqlTooLow.md | 8 ++
.../queries/IrqlTooLow/IrqlTooLow.qhelp | 24 ++++++
.../queries/IrqlTooLow/driver_snippet.c | 61 +++++++++++++++
.../MultiplePagedCode/MultiplePagedCode.md | 4 +
.../MultiplePagedCode/MultiplePagedCode.qhelp | 16 ++++
13 files changed, 332 insertions(+)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
index eb7bd233..c2ff042a 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
@@ -52,3 +52,12 @@ Correct example
## References
* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)
+
+## Semmle-specific notes
+**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:
+
+* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.
+* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.
+* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.
+If a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.
+
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
index b3e1b967..e5c42e31 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
@@ -60,4 +60,44 @@
+
+
+ Known false negatives. The query suppresses save / restore pairs
+ when no IRQL-changing call sits between the save call and the restore call
+ on a source line that lies textually within the enclosing function. This
+ suppression eliminates a class of may-analysis false positives where the
+ save and the restore are at the same IRQL within a single dynamic
+ invocation but the IRQL inference reports different hypothetical entry
+ IRQLs. The check has the following limitations:
+
+
+ -
+ Cross-function save / restore. When the save and the restore
+ are routed through helper functions that wrap
+
KeSaveFloatingPointState /
+ KeRestoreFloatingPointState, and the IRQL change happens
+ in the caller, no in-function intermediate call is found and the
+ mismatch is silently suppressed.
+
+ -
+ Indirect calls. IRQL changes performed by an indirect call
+ (function pointer or dispatch-table call) between save and restore
+ are not detected, because the predicate only inspects the static
+ call target.
+
+ -
+ Loops where the restore is textually before the save. The
+ filter compares source line numbers; in a loop body whose first
+ statement is the restore and last statement is the save (with the
+ IRQL change after the save), the line range becomes empty and no
+ intermediate IRQL change is seen.
+
+
+
+ If a real mismatch is being suppressed, eliminate the wrapper or add
+ explicit _IRQL_raises_ / _IRQL_saves_global_
+ annotations to the helper so its IRQL behavior is visible without
+ body inspection.
+
+
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
index fa769ae2..e660ed04 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
@@ -88,3 +88,39 @@ void driver_utility_nested_block_good(void)
KeRestoreFloatingPointState(&FloatBuf);
}
}
+
+// =====================================================================
+// Adversarial: cross-function save / restore via thin wrappers.
+//
+// `irqlChangesBetween` requires `saveCall` and `restoreCall` to
+// share an enclosing function, so when the save and the restore
+// are routed through helper wrappers and the IRQL change happens
+// in the caller, the source-position filter never finds a `mid`
+// candidate. No finding is produced even though the IRQL at the
+// save (PASSIVE_LEVEL) differs from the IRQL at the restore
+// (DISPATCH_LEVEL). This is a known false negative of the
+// current intraprocedural filter.
+// =====================================================================
+
+static void save_fp_helper(PKFLOATING_SAVE pfs)
+{
+ KeSaveFloatingPointState(pfs);
+}
+
+static void restore_fp_helper(PKFLOATING_SAVE pfs)
+{
+ KeRestoreFloatingPointState(pfs);
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+void driver_utility_cross_function_bad(void)
+{
+ KFLOATING_SAVE FloatBuf;
+ KIRQL oldIRQL;
+
+ save_fp_helper(&FloatBuf);
+ KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL);
+ // ... do work at DISPATCH ...
+ restore_fp_helper(&FloatBuf);
+ KeLowerIrql(oldIRQL);
+}
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
index b83ce92f..0a0e26ce 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
@@ -28,3 +28,7 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+**Lower-on-exit pattern: known false negative.** When a function has no `_IRQL_always_function_max_` but does carry an `_IRQL_raises_(R)` annotation, the query treats `R` as the implicit ceiling for the function body. A function annotated as both `_IRQL_requires_min_(M)` and `_IRQL_raises_(R)` with `M > R` is interpreted as a "lower IRQL on exit" pattern (for example a wrapper around a mutex or spin-lock release that runs at `DISPATCH_LEVEL` on entry and returns at `PASSIVE_LEVEL`). For these functions the implicit ceiling is suppressed entirely, because `R` describes the exit IRQL rather than a maximum.
+
+This means that a buggy "lower-on-exit" function whose body raises the IRQL above `M` at some intermediate point will *not* be flagged. If the function actually has a maximum that should be enforced along the body, declare it explicitly with `_IRQL_always_function_max_(MAX)` so the query has a concrete ceiling to check against.
+
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
index baa360a9..68ddf1d4 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
@@ -36,5 +36,26 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
+ Lower-on-exit pattern: known false negative. When a function has
+ no _IRQL_always_function_max_ but does carry an
+ _IRQL_raises_(R) annotation, the query treats R
+ as the implicit ceiling for the function body. A function annotated as
+ both _IRQL_requires_min_(M) and
+ _IRQL_raises_(R) with M > R is interpreted
+ as a "lower IRQL on exit" pattern (for example a wrapper around a mutex
+ or spin-lock release that runs at DISPATCH_LEVEL on entry
+ and returns at PASSIVE_LEVEL). For these functions the
+ implicit ceiling is suppressed entirely, because R describes
+ the exit IRQL rather than a maximum.
+
+
+ This means that a buggy "lower-on-exit" function whose body raises the
+ IRQL above M at some intermediate point will not be
+ flagged. If the function actually has a maximum that should be enforced
+ along the body, declare it explicitly with
+ _IRQL_always_function_max_(MAX) so the query has a concrete
+ ceiling to check against.
+
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
index 2bb42bd8..ab46ab76 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
@@ -53,3 +53,11 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:
+
+* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);
+* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;
+* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;
+* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
+If you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).
+
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
index 9b560db9..7bbcb924 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
@@ -60,5 +60,29 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
+ Known false negatives. The query suppresses calls inside an
+ if (b) block when b is a variable initialized to
+ FALSE / 0 with no plain = assignment
+ to it visible in the same enclosing function. This suppression is intended
+ to silence dead-branch patterns produced by NDIS macros such as
+ FILTER_ACQUIRE_LOCK(lock, bFalse), but it is too lax. The
+ following mutations of b all bypass the check, so the call
+ inside the branch may be silently dropped even when b is in
+ fact true at runtime:
+
+
+ - compound assignments such as
b |= 1, b &= mask, b += value (the predicate looks only for AssignExpr, which represents plain = assignments; compound forms are AssignOperation);
+ - increment / decrement (
b++, --b) which is CrementOperation, not an assignment;
+ - pass-by-reference helpers such as
SetFlag(&b), where the mutation is invisible to a syntactic scan of the enclosing function;
+ - file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
+
+
+ If you rely on a runtime flag to gate IRQL-sensitive code and the call is
+ incorrectly suppressed, work around the limitation by replacing the gated
+ call with a direct, annotated call site or by rewriting the condition so
+ the predicate fails (for example, use != 0 against a value
+ the predicate cannot constant-fold).
+
diff --git a/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c b/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
index 6f498bcb..a83e1d9a 100644
--- a/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
@@ -73,4 +73,81 @@ passForIrqlTooHigh(PKIRQL oldIrql){
status = IrqlHighTestFunction();
KeLowerIrql(*oldIrql);
return status;
+}
+
+// =====================================================================
+// Adversarial cases for `isInConstantFalseBranch` (Irql.qll).
+//
+// These cases probe a known limitation of the predicate that
+// suppresses calls inside `if (b)` for variables that look
+// "constantly FALSE": it only inspects plain `=` AssignExpr in
+// the same enclosing function. Compound assignments, increments,
+// pass-by-reference mutation, and globals reassigned in other
+// functions all bypass this check, causing the call to be
+// silently suppressed (a false negative).
+//
+// Each adversarial case below should, in principle, be flagged as
+// IRQL-too-high; under the current predicate they are not.
+// =====================================================================
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS PassiveOnly_TooHigh(void){
+ return STATUS_SUCCESS;
+}
+
+static BOOLEAN g_DispatchSafe_TooHigh = FALSE;
+
+void initialize_global_dispatch_safe_TooHigh(void){
+ g_DispatchSafe_TooHigh = TRUE;
+}
+
+static void mutate_flag_by_pointer_TooHigh(PBOOLEAN pb){
+ *pb = TRUE;
+}
+
+// Adversarial: `bFalse |= 1` is `AssignBitwiseOrExpr`, which
+// extends `AssignOperation` and not `AssignExpr`.
+void failForIrqlTooHigh_compoundAssignment(PKIRQL oldIrql){
+ BOOLEAN bFalse = FALSE;
+ bFalse |= 1;
+ KeRaiseIrql(DISPATCH_LEVEL, oldIrql);
+ if (bFalse) {
+ PassiveOnly_TooHigh();
+ }
+ KeLowerIrql(*oldIrql);
+}
+
+// Adversarial: `bFalse++` is `CrementOperation`.
+void failForIrqlTooHigh_increment(PKIRQL oldIrql){
+ BOOLEAN bFalse = FALSE;
+ bFalse++;
+ KeRaiseIrql(DISPATCH_LEVEL, oldIrql);
+ if (bFalse) {
+ PassiveOnly_TooHigh();
+ }
+ KeLowerIrql(*oldIrql);
+}
+
+// Adversarial: variable mutated by reference; no AssignExpr to
+// `bFalse` exists in this function.
+void failForIrqlTooHigh_byReference(PKIRQL oldIrql){
+ BOOLEAN bFalse = FALSE;
+ mutate_flag_by_pointer_TooHigh(&bFalse);
+ KeRaiseIrql(DISPATCH_LEVEL, oldIrql);
+ if (bFalse) {
+ PassiveOnly_TooHigh();
+ }
+ KeLowerIrql(*oldIrql);
+}
+
+// Adversarial: file-scope global, reassigned only from other
+// functions. The constant-FALSE branch check looks for
+// AssignExprs only inside `failForIrqlTooHigh_globalReassigned`
+// and finds none.
+void failForIrqlTooHigh_globalReassigned(PKIRQL oldIrql){
+ KeRaiseIrql(DISPATCH_LEVEL, oldIrql);
+ if (g_DispatchSafe_TooHigh) {
+ PassiveOnly_TooHigh();
+ }
+ KeLowerIrql(*oldIrql);
}
\ No newline at end of file
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
index 6b8dbad6..ceb10bf4 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
@@ -43,3 +43,11 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:
+
+* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);
+* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;
+* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;
+* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
+If you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).
+
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
index a505edbf..94af6437 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
@@ -50,5 +50,29 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
+ Known false negatives. The query suppresses calls inside an
+ if (b) block when b is a variable initialized to
+ FALSE / 0 with no plain = assignment
+ to it visible in the same enclosing function. This suppression is intended
+ to silence dead-branch patterns produced by NDIS macros such as
+ FILTER_ACQUIRE_LOCK(lock, bFalse), but it is too lax. The
+ following mutations of b all bypass the check, so the call
+ inside the branch may be silently dropped even when b is in
+ fact true at runtime:
+
+
+ - compound assignments such as
b |= 1, b &= mask, b += value (the predicate looks only for AssignExpr, which represents plain = assignments; compound forms are AssignOperation);
+ - increment / decrement (
b++, --b) which is CrementOperation, not an assignment;
+ - pass-by-reference helpers such as
SetFlag(&b), where the mutation is invisible to a syntactic scan of the enclosing function;
+ - file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
+
+
+ If you rely on a runtime flag to gate IRQL-sensitive code and the call is
+ incorrectly suppressed, work around the limitation by replacing the gated
+ call with a direct, annotated call site or by rewriting the condition so
+ the predicate fails (for example, use != 0 against a value
+ the predicate cannot constant-fold).
+
diff --git a/src/drivers/general/queries/IrqlTooLow/driver_snippet.c b/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
index 6159d123..30628305 100644
--- a/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
@@ -51,4 +51,65 @@ _IRQL_requires_(DISPATCH_LEVEL)
NTSTATUS
IrqlHighTestFunction(){
return STATUS_SUCCESS;
+}
+
+// =====================================================================
+// Adversarial cases for `isInConstantFalseBranch` (Irql.qll).
+//
+// Symmetric to the IrqlTooHigh cases: the enclosing function is
+// at PASSIVE_LEVEL but the call inside `if (b)` requires
+// DISPATCH_LEVEL. The predicate suppresses these calls because
+// the variable looks constantly FALSE, even when in fact it has
+// been mutated through a compound assignment, an increment, a
+// pass-by-reference helper, or in a separate function (for a
+// global).
+// =====================================================================
+
+_IRQL_requires_(DISPATCH_LEVEL)
+NTSTATUS DispatchOnly_TooLow(void){
+ return STATUS_SUCCESS;
+}
+
+static BOOLEAN g_DispatchSafe_TooLow = FALSE;
+
+void initialize_global_dispatch_safe_TooLow(void){
+ g_DispatchSafe_TooLow = TRUE;
+}
+
+static void mutate_flag_by_pointer_TooLow(PBOOLEAN pb){
+ *pb = TRUE;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+void failForIrqlTooLow_compoundAssignment(void){
+ BOOLEAN bFalse = FALSE;
+ bFalse |= 1;
+ if (bFalse) {
+ DispatchOnly_TooLow();
+ }
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+void failForIrqlTooLow_increment(void){
+ BOOLEAN bFalse = FALSE;
+ bFalse++;
+ if (bFalse) {
+ DispatchOnly_TooLow();
+ }
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+void failForIrqlTooLow_byReference(void){
+ BOOLEAN bFalse = FALSE;
+ mutate_flag_by_pointer_TooLow(&bFalse);
+ if (bFalse) {
+ DispatchOnly_TooLow();
+ }
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+void failForIrqlTooLow_globalReassigned(void){
+ if (g_DispatchSafe_TooLow) {
+ DispatchOnly_TooLow();
+ }
}
\ No newline at end of file
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
index 2b561625..8e431b4c 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
@@ -72,3 +72,7 @@ DispatchShutdown (
## References
* [ C28171 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28171-function-has-more-than-one-page-macro-instance)
+
+## Semmle-specific notes
+**Function templates: known false negative.** The query excludes `FunctionTemplateInstantiation` functions when locating the enclosing function for each `PAGED_CODE` / `PAGED_CODE_LOCKED` macro invocation. The exclusion was added to avoid duplicate findings caused by per-instantiation line attribution drift. As a side effect, a duplicate `PAGED_CODE` inside the body of a C++ function template that is only ever observed as instantiations (and not as a non-instantiated template entity in the extracted AST) will not be reported. C++ function templates are uncommon in WDM / KMDF drivers, but if you do use them and need this check, lift the duplicated `PAGED_CODE` macro into a non-templated helper or split the body so each path enters a distinct paged function.
+
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
index 70fdef92..5025985a 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
@@ -21,4 +21,20 @@
+
+
+ Function templates: known false negative. The query excludes
+ FunctionTemplateInstantiation functions when locating the
+ enclosing function for each PAGED_CODE /
+ PAGED_CODE_LOCKED macro invocation. The exclusion was added
+ to avoid duplicate findings caused by per-instantiation line attribution
+ drift. As a side effect, a duplicate PAGED_CODE inside the
+ body of a C++ function template that is only ever observed as
+ instantiations (and not as a non-instantiated template entity in the
+ extracted AST) will not be reported. C++ function templates are uncommon
+ in WDM / KMDF drivers, but if you do use them and need this check, lift
+ the duplicated PAGED_CODE macro into a non-templated helper
+ or split the body so each path enters a distinct paged function.
+
+
From 3f4ff1a39bc6ffbb9b056cea703a9e53125df52e Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 16:46:13 -0700
Subject: [PATCH 09/19] Fix three false negatives surfaced by the prior review
* IrqlTooHigh / IrqlTooLow isInConstantFalseBranch. Replaced the
AssignExpr-only mutation guard with the broader Assignment
superclass (covers =, |=, &=, +=, etc.) and added a
CrementOperation check for ++ / --. Restricted the
variable-access case to non-static LocalVariable instances and
bailed out when the variable's address is taken anywhere in the
database, so globals reassigned in another function and locals
mutated through a pointer are no longer treated as "constantly
false". The compile-time-constant-zero condition is preserved
unchanged. IrqlTooHigh: v4 -> v5. IrqlTooLow: v5 -> v6. The four
adversarial cases in each driver_snippet now produce findings;
baseline TPs are preserved unchanged.
* IrqlFloatStateMismatch cross-function wrappers. Replaced the
same-enclosing-function constraint in irqlChangesBetween with an
anchor-line predicate that lets the candidate function be
either the enclosing function of the call directly, or the
function that calls a one-level helper containing it. The
predicate then looks for an IRQL-changing call in between the
two anchor lines. This handles thin save/restore wrappers around
the Ke*FloatingPointState primitives where the IRQL change
happens in the common caller, and also the asymmetric case where
one side is a wrapper and the other is direct. v4 -> v5.
* MultiplePagedCode template-instantiation handling. Replaced the
blanket
ot result instanceof FunctionTemplateInstantiation
exclusion with a projection back to the underlying
TemplateFunction via getTemplate(). Page-segment heuristics
are still checked on the concrete instantiation, but match keys
are deduplicated to the source-level template, so a duplicate
PAGED_CODE inside a templated function body is reported once
at the source location regardless of how many instantiations the
extractor produced. v2 -> v3.
Validation (in-tree tests):
* IrqlTooHigh: 4 baseline TPs preserved; 4 adversarial cases now
flagged (compound assign, increment, by-reference helper,
file-scope global). diff +0/-0 against the updated baseline.
* IrqlTooLow: same shape; 2 + 4 = 6 findings.
* IrqlFloatStateMismatch: 4 baseline TPs preserved; 1 adversarial
cross-function case now flagged. 5 findings.
* MultiplePagedCode: existing baseline TP preserved; diff +0/-0.
Validation (out-of-tree C++ KMDF template database):
* MultiplePagedCode now reports the templated duplicate at the
source location (one finding), matching the pre-branch baseline
instead of silently dropping it.
qhelp updated for each query: the prior "Known false negatives"
sections were rewritten to describe the now-handled scope and to
keep the documented limitations that still apply (indirect calls,
deeply-nested helper IRQL changes, multi-level wrapper chains,
loop-restore-before-save). MD files regenerated via
codeql generate query-help.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.md | 9 +-
.../IrqlFloatStateMismatch.qhelp | 67 ++-
.../IrqlFloatStateMismatch.ql | 70 ++-
.../IrqlFloatStateMismatch.sarif | 2 +-
.../queries/IrqlTooHigh/IrqlTooHigh.md | 8 +-
.../queries/IrqlTooHigh/IrqlTooHigh.qhelp | 35 +-
.../queries/IrqlTooHigh/IrqlTooHigh.ql | 2 +-
.../queries/IrqlTooHigh/IrqlTooHigh.sarif | 530 +-----------------
.../general/queries/IrqlTooLow/IrqlTooLow.md | 8 +-
.../queries/IrqlTooLow/IrqlTooLow.qhelp | 35 +-
.../general/queries/IrqlTooLow/IrqlTooLow.ql | 2 +-
.../queries/IrqlTooLow/IrqlTooLow.sarif | 346 +-----------
src/drivers/libraries/Irql.qll | 49 +-
src/drivers/libraries/Page.qll | 56 +-
.../MultiplePagedCode/MultiplePagedCode.md | 2 +-
.../MultiplePagedCode/MultiplePagedCode.qhelp | 21 +-
.../MultiplePagedCode/MultiplePagedCode.ql | 2 +-
17 files changed, 217 insertions(+), 1027 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
index c2ff042a..334e1566 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
@@ -54,10 +54,11 @@ Correct example
* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)
## Semmle-specific notes
-**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:
+**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).
-* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.
+**Remaining limitations.** The position-based filter still does not detect:
+
+* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.
* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.
* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.
-If a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.
-
+* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
index e5c42e31..97f3323a 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
@@ -62,42 +62,53 @@
- Known false negatives. The query suppresses save / restore pairs
- when no IRQL-changing call sits between the save call and the restore call
- on a source line that lies textually within the enclosing function. This
- suppression eliminates a class of may-analysis false positives where the
- save and the restore are at the same IRQL within a single dynamic
- invocation but the IRQL inference reports different hypothetical entry
- IRQLs. The check has the following limitations:
+ Wrapper / common-caller pattern. The query reasons about
+ IRQL-changing calls between save and restore not only when both
+ calls share an enclosing function, but also when they sit inside
+ one-level helper wrappers that are called from a common caller
+ (for example, thin save_fp_helper /
+ restore_fp_helper functions that simply forward to
+ KeSaveFloatingPointState /
+ KeRestoreFloatingPointState). In those cases the
+ intermediate IRQL transition is searched in the common caller
+ (or in either helper's enclosing function for the asymmetric case
+ where one side is a helper and the other is direct).
+
+
+ Remaining limitations. The position-based filter still does
+ not detect:
-
- Cross-function save / restore. When the save and the restore
- are routed through helper functions that wrap
-
KeSaveFloatingPointState /
- KeRestoreFloatingPointState, and the IRQL change happens
- in the caller, no in-function intermediate call is found and the
- mismatch is silently suppressed.
+ IRQL changes performed deep inside helper bodies.
+ If the helper function itself raises or lowers the IRQL after
+ the save (or before the restore), the change is not visible
+ from the common caller's source-position view, and no
+ intermediate IRQL change is found. Annotating the helper with
+ _IRQL_raises_ or _IRQL_saves_global_
+ makes its IRQL behavior visible without body inspection.
+
+ -
+ Indirect calls. IRQL changes performed by an indirect
+ call (function pointer or dispatch-table call) between save
+ and restore are not detected, because the predicate only
+ inspects the static call target.
-
- Indirect calls. IRQL changes performed by an indirect call
- (function pointer or dispatch-table call) between save and restore
- are not detected, because the predicate only inspects the static
- call target.
+ Loops where the restore is textually before the save.
+ The filter compares source line numbers; in a loop body
+ whose first statement is the restore and last statement is
+ the save (with the IRQL change after the save), the line
+ range becomes empty and no intermediate IRQL change is
+ seen.
-
- Loops where the restore is textually before the save. The
- filter compares source line numbers; in a loop body whose first
- statement is the restore and last statement is the save (with the
- IRQL change after the save), the line range becomes empty and no
- intermediate IRQL change is seen.
+ Wrapper chains longer than one level. Only one level
+ of wrapping is currently modelled (the helper is called
+ directly from the common caller). Multi-level wrappers
+ require the same annotation hint described above, or a
+ direct call site.
-
- If a real mismatch is being suppressed, eliminate the wrapper or add
- explicit _IRQL_raises_ / _IRQL_saves_global_
- annotations to the helper so its IRQL behavior is visible without
- body inspection.
-
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index a905edff..580d07ba 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -17,7 +17,7 @@
* @tags correctness
* ca_ported
* @scope domainspecific
- * @query-version v4
+ * @query-version v5
*/
import cpp
@@ -76,26 +76,62 @@ predicate isIrqlChangingCall(FunctionCall fc) {
}
/**
- * Holds if there is an IRQL-changing call in the same function as
- * `saveCall` and `restoreCall` whose source location lies (textually)
- * between them. This is intentionally a source-position check rather
- * than a CFG reachability check: the cpp control-flow graph in some
- * extracted databases does not transitively connect calls across
- * statement boundaries, which would silently eliminate true positives.
+ * Gets a source line in `f` that anchors `fc` from `f`'s perspective:
*
- * The intent of the filter is to suppress mismatches in functions
- * that have no IRQL transition at all (where the apparent
- * save/restore IRQL difference is purely a may-analysis artifact
- * from multiple hypothetical entry IRQLs).
+ * - If `fc`'s enclosing function is `f`, the anchor is `fc`'s own
+ * start line.
+ * - Otherwise, if `f` contains a call site whose static target is
+ * `fc`'s enclosing function, the anchor is that call site's start
+ * line. (One-level wrapper case.)
+ *
+ * This lets `irqlChangesBetween` reason about the relative source
+ * position of the save and the restore in any function that either
+ * directly contains the call or calls the helper that does.
+ */
+private int anchorLineForCall(Function f, FunctionCall fc) {
+ f = fc.getEnclosingFunction() and
+ result = fc.getLocation().getStartLine()
+ or
+ exists(FunctionCall site |
+ site.getEnclosingFunction() = f and
+ site.getTarget() = fc.getEnclosingFunction() and
+ f != fc.getEnclosingFunction() and
+ result = site.getLocation().getStartLine()
+ )
+}
+
+/**
+ * Holds if there is an IRQL-changing call in some function `f` whose
+ * source line lies between the save anchor and the restore anchor in
+ * `f`. The anchor mechanism (see `anchorLineForCall`) lets `f` be:
+ *
+ * - the enclosing function of both `saveCall` and `restoreCall`
+ * (the original same-function case),
+ * - the common caller that calls thin save / restore helper
+ * wrappers,
+ * - the enclosing function of one of the two calls when the other
+ * is in a one-level helper called from it (asymmetric case).
+ *
+ * The dataflow library has already established that the floating-
+ * point buffer flows from `saveCall` to `restoreCall`; this predicate
+ * is purely a sanity filter to suppress the pure may-analysis
+ * artifact where two save / restore sites are compared at different
+ * hypothetical entry IRQLs but no IRQL transition can actually happen
+ * at runtime between them.
+ *
+ * The position-based check (rather than a CFG-reachability check) is
+ * required because the cpp control-flow graph in some extracted
+ * databases does not transitively connect calls across statement
+ * boundaries, which would silently eliminate true positives.
*/
predicate irqlChangesBetween(FunctionCall saveCall, FunctionCall restoreCall) {
- exists(FunctionCall mid, Function f |
- f = saveCall.getEnclosingFunction() and
- f = restoreCall.getEnclosingFunction() and
- f = mid.getEnclosingFunction() and
+ exists(Function f, int saveLine, int restoreLine, FunctionCall mid |
+ saveLine = anchorLineForCall(f, saveCall) and
+ restoreLine = anchorLineForCall(f, restoreCall) and
+ mid.getEnclosingFunction() = f and
isIrqlChangingCall(mid) and
- mid.getLocation().getStartLine() >= saveCall.getLocation().getStartLine() and
- mid.getLocation().getStartLine() <= restoreCall.getLocation().getStartLine() and
+ mid.getLocation().getStartLine() >= saveLine and
+ mid.getLocation().getStartLine() <= restoreLine and
mid != saveCall and
mid != restoreCall
)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index 10a91651..d6fd8430 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -1 +1 @@
-{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL","organization":"GitHub","semanticVersion":"2.24.2","notifications":[{"id":"cpp/baseline/expected-extracted-files","name":"cpp/baseline/expected-extracted-files","shortDescription":{"text":"Expected extracted files"},"fullDescription":{"text":"Files appearing in the source archive that are expected to be extracted."},"defaultConfiguration":{"enabled":true},"properties":{"tags":["expected-extracted-files","telemetry"]}},{"id":"cli/file-coverage-baseline","name":"cli/file-coverage-baseline","shortDescription":{"text":"File coverage baseline telemetry"},"fullDescription":{"text":"File coverage baseline telemetry"},"defaultConfiguration":{"enabled":true}},{"id":"cli/platform","name":"cli/platform","shortDescription":{"text":"Platform"},"fullDescription":{"text":"Platform"},"defaultConfiguration":{"enabled":true}},{"id":"cpp/extractor/summary","name":"cpp/extractor/summary","shortDescription":{"text":"C++ extractor telemetry"},"fullDescription":{"text":"C++ extractor telemetry"},"defaultConfiguration":{"enabled":true}}],"rules":[{"id":"cpp/drivers/irql-float-state-mismatch","name":"cpp/drivers/irql-float-state-mismatch","shortDescription":{"text":"Irql Float State Mismatch"},"fullDescription":{"text":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."},"defaultConfiguration":{"enabled":true,"level":"warning"},"help":{"text":"# Irql Float State Mismatch\r\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\r\n\r\n\r\n## Recommendation\r\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\r\n\r\n\r\n## Example\r\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\r\n\r\n```c\r\n \r\n\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\tvoid driver_utility_bad(void)\r\n\t\t{\r\n\t\t\tKIRQL oldIRQL;\r\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t// running at APC level\r\n\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t{\r\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\r\n\t\t\t\t// ...\r\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n```\r\nCorrect example\r\n\r\n```c\r\n \r\n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\t\tvoid driver_utility_good(void)\r\n\t\t\t{\r\n\t\t\t\t// running at APC level\r\n\t\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\t\tKIRQL oldIRQL;\r\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\r\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t\t{\r\n\t\t\t\t\tKeLowerIrql(oldIRQL);\r\n\t\t\t\t\t// ...\r\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\r\n```\r\n\r\n## References\r\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\r\n","markdown":"# Irql Float State Mismatch\r\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\r\n\r\n\r\n## Recommendation\r\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\r\n\r\n\r\n## Example\r\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\r\n\r\n```c\r\n \r\n\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\tvoid driver_utility_bad(void)\r\n\t\t{\r\n\t\t\tKIRQL oldIRQL;\r\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t// running at APC level\r\n\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t{\r\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\r\n\t\t\t\t// ...\r\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n```\r\nCorrect example\r\n\r\n```c\r\n \r\n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \r\n\t\t\tvoid driver_utility_good(void)\r\n\t\t\t{\r\n\t\t\t\t// running at APC level\r\n\t\t\t\tKFLOATING_SAVE FloatBuf;\r\n\t\t\t\tKIRQL oldIRQL;\r\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\r\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\r\n\t\t\t\t{\r\n\t\t\t\t\tKeLowerIrql(oldIRQL);\r\n\t\t\t\t\t// ...\r\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\r\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\r\n```\r\n\r\n## References\r\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\r\n"},"properties":{"tags":["correctness","ca_ported"],"description":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).","feature.area":"Multiple","id":"cpp/drivers/irql-float-state-mismatch","impact":"Insecure Coding Practice","kind":"problem","name":"Irql Float State Mismatch","opaqueid":"CQLD-C28111","owner.email":"sdat@microsoft.com","platform":"Desktop","precision":"medium","problem.severity":"warning","query-version":"v4","repro.text":"The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.","scope":"domainspecific"}}]},"extensions":[{"name":"microsoft/windows-drivers","semanticVersion":"1.9.0+f44073ff890bb0b5a98599d99593f4a2e2d33a07","locations":[{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]},{"name":"codeql/cpp-all","semanticVersion":"7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1","locations":[{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]}]},"invocations":[{"toolExecutionNotifications":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T19:08:54.060239700Z","descriptor":{"id":"cli/file-coverage-baseline","index":1},"properties":{"attributes":{"durationMilliseconds":317},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T19:08:54.072945700Z","descriptor":{"id":"cli/platform","index":2},"properties":{"attributes":{"arch":"amd64","name":"Windows 11","version":"10.0"},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":"Internal telemetry for the C++ extractor.\n\nNo action needed.","markdown":"Internal telemetry for the C++ extractor.\n\nNo action needed."},"level":"note","timeUtc":"2026-04-28T19:09:44.022663200Z","descriptor":{"id":"cpp/extractor/summary","index":3},"properties":{"attributes":{"cache-hits":0,"cache-misses":1,"compilers":[{"program":"cl","version":"Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"}],"extractor-failures":1,"extractor-successes":0,"trap-caching":"disabled"},"visibility":{"statusPage":false,"telemetry":true}}}],"executionSuccessful":true}],"artifacts":[{"location":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}},{"location":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}},{"location":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}],"results":[{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"28"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"28"}}],"columnKind":"utf16CodeUnits","properties":{"semmle.formatSpecifier":"sarifv2.1.0"}}]}
\ No newline at end of file
+{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL","organization":"GitHub","semanticVersion":"2.24.2","notifications":[{"id":"cpp/baseline/expected-extracted-files","name":"cpp/baseline/expected-extracted-files","shortDescription":{"text":"Expected extracted files"},"fullDescription":{"text":"Files appearing in the source archive that are expected to be extracted."},"defaultConfiguration":{"enabled":true},"properties":{"tags":["expected-extracted-files","telemetry"]}},{"id":"cli/file-coverage-baseline","name":"cli/file-coverage-baseline","shortDescription":{"text":"File coverage baseline telemetry"},"fullDescription":{"text":"File coverage baseline telemetry"},"defaultConfiguration":{"enabled":true}},{"id":"cli/platform","name":"cli/platform","shortDescription":{"text":"Platform"},"fullDescription":{"text":"Platform"},"defaultConfiguration":{"enabled":true}},{"id":"cpp/extractor/summary","name":"cpp/extractor/summary","shortDescription":{"text":"C++ extractor telemetry"},"fullDescription":{"text":"C++ extractor telemetry"},"defaultConfiguration":{"enabled":true}}],"rules":[{"id":"cpp/drivers/irql-float-state-mismatch","name":"cpp/drivers/irql-float-state-mismatch","shortDescription":{"text":"Irql Float State Mismatch"},"fullDescription":{"text":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."},"defaultConfiguration":{"enabled":true,"level":"warning"},"help":{"text":"# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n","markdown":"# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n"},"properties":{"tags":["correctness","ca_ported"],"description":"The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).","feature.area":"Multiple","id":"cpp/drivers/irql-float-state-mismatch","impact":"Insecure Coding Practice","kind":"problem","name":"Irql Float State Mismatch","opaqueid":"CQLD-C28111","owner.email":"sdat@microsoft.com","platform":"Desktop","precision":"medium","problem.severity":"warning","query-version":"v5","repro.text":"The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.","scope":"domainspecific"}}]},"extensions":[{"name":"microsoft/windows-drivers","semanticVersion":"1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307","locations":[{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]},{"name":"codeql/cpp-all","semanticVersion":"7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1","locations":[{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]}]},"invocations":[{"toolExecutionNotifications":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:26:00.575823400Z","descriptor":{"id":"cli/file-coverage-baseline","index":1},"properties":{"attributes":{"durationMilliseconds":288},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:26:00.581682100Z","descriptor":{"id":"cli/platform","index":2},"properties":{"attributes":{"arch":"amd64","name":"Windows 11","version":"10.0"},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":"Internal telemetry for the C++ extractor.\n\nNo action needed.","markdown":"Internal telemetry for the C++ extractor.\n\nNo action needed."},"level":"note","timeUtc":"2026-04-28T23:26:39.590845200Z","descriptor":{"id":"cpp/extractor/summary","index":3},"properties":{"attributes":{"cache-hits":0,"cache-misses":1,"compilers":[{"program":"cl","version":"Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"}],"extractor-failures":1,"extractor-successes":0,"trap-caching":"disabled"},"visibility":{"statusPage":false,"telemetry":true}}}],"executionSuccessful":true}],"artifacts":[{"location":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}},{"location":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}},{"location":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}],"results":[{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (0) does not match the irql level for the restore operation (2)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":112,"startColumn":33,"endColumn":36}}}],"partialFingerprints":{"primaryLocationLineHash":"32de180444120f36:1","primaryLocationStartColumnFingerprint":"28"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":66,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"ff98177eaaf7d309:1","primaryLocationStartColumnFingerprint":"28"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":38,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"29"}},{"ruleId":"cpp/drivers/irql-float-state-mismatch","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-float-state-mismatch","index":0},"message":{"text":"The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":23,"startColumn":37,"endColumn":46}}}],"partialFingerprints":{"primaryLocationLineHash":"b3909ff165022b51:1","primaryLocationStartColumnFingerprint":"28"}}],"columnKind":"utf16CodeUnits","properties":{"semmle.formatSpecifier":"sarifv2.1.0"}}]}
\ No newline at end of file
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
index ab46ab76..98fb34dc 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
@@ -53,11 +53,5 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
-**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:
-
-* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);
-* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;
-* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;
-* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
-If you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).
+**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
index 7bbcb924..36f327c5 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
@@ -61,28 +61,19 @@
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
- Known false negatives. The query suppresses calls inside an
- if (b) block when b is a variable initialized to
- FALSE / 0 with no plain = assignment
- to it visible in the same enclosing function. This suppression is intended
- to silence dead-branch patterns produced by NDIS macros such as
- FILTER_ACQUIRE_LOCK(lock, bFalse), but it is too lax. The
- following mutations of b all bypass the check, so the call
- inside the branch may be silently dropped even when b is in
- fact true at runtime:
-
-
- - compound assignments such as
b |= 1, b &= mask, b += value (the predicate looks only for AssignExpr, which represents plain = assignments; compound forms are AssignOperation);
- - increment / decrement (
b++, --b) which is CrementOperation, not an assignment;
- - pass-by-reference helpers such as
SetFlag(&b), where the mutation is invisible to a syntactic scan of the enclosing function;
- - file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
-
-
- If you rely on a runtime flag to gate IRQL-sensitive code and the call is
- incorrectly suppressed, work around the limitation by replacing the gated
- call with a direct, annotated call site or by rewriting the condition so
- the predicate fails (for example, use != 0 against a value
- the predicate cannot constant-fold).
+ Dead-branch suppression. The query suppresses calls inside an
+ if (b) block when b is a non-static
+ local variable initialized to FALSE / 0 that is
+ never mutated (no =, no compound assignment, no
+ ++ / --) and whose address is never taken.
+ Compile-time constant 0 conditions are also suppressed.
+ This is intended to silence dead-branch patterns produced by NDIS
+ macros such as FILTER_ACQUIRE_LOCK(lock, bFalse); the
+ conditions on the variable case are deliberately conservative to
+ avoid silently dropping legitimate findings when the runtime value
+ of the variable cannot be proven to remain FALSE
+ (globals reassigned in another function, address-taken locals
+ mutated through a pointer, compound mutation, etc.).
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
index b339f25d..b3a8313a 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v4
+ * @query-version v5
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
index 6cdc3298..a2fd95f3 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
@@ -1,529 +1 @@
-{
- "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
- "version": "2.1.0",
- "runs": [
- {
- "tool": {
- "driver": {
- "name": "CodeQL",
- "organization": "GitHub",
- "semanticVersion": "2.18.4",
- "notifications": [
- {
- "id": "cpp/baseline/expected-extracted-files",
- "name": "cpp/baseline/expected-extracted-files",
- "shortDescription": {
- "text": "Expected extracted files"
- },
- "fullDescription": {
- "text": "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration": {
- "enabled": true
- },
- "properties": {
- "tags": [
- "expected-extracted-files",
- "telemetry"
- ]
- }
- },
- {
- "id": "cpp/extractor/summary",
- "name": "cpp/extractor/summary",
- "shortDescription": {
- "text": "C++ extractor telemetry"
- },
- "fullDescription": {
- "text": "C++ extractor telemetry"
- },
- "defaultConfiguration": {
- "enabled": true
- }
- }
- ],
- "rules": [
- {
- "id": "cpp/drivers/irql-too-high",
- "name": "cpp/drivers/irql-too-high",
- "shortDescription": {
- "text": "IRQL too high (C28121)"
- },
- "fullDescription": {
- "text": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements."
- },
- "defaultConfiguration": {
- "enabled": true,
- "level": "warning"
- },
- "properties": {
- "tags": [
- "correctness",
- "wddst"
- ],
- "description": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.",
- "feature.area": "Multiple",
- "id": "cpp/drivers/irql-too-high",
- "impact": "Exploitable Design",
- "kind": "problem",
- "name": "IRQL too high (C28121)",
- "opaqueid": "CQLD-C28121",
- "owner.email": "sdat@microsoft.com",
- "platform": "Desktop",
- "precision": "medium",
- "problem.severity": "warning",
- "query-version": "v2",
- "repro.text": "The following function call is taking place at an IRQL too high for what the call target is annotated as.",
- "scope": "domainspecific",
- "security.severity": "Low"
- }
- }
- ]
- },
- "extensions": [
- {
- "name": "microsoft/windows-drivers",
- "semanticVersion": "1.2.0+ebba6989b75fe7ac336c358d0838781e7b17e5c2",
- "locations": [
- {
- "uri": "file:///C:/codeql-home/WDDST/src/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/codeql-home/WDDST/src/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- }
- ]
- },
- "invocations": [
- {
- "toolExecutionNotifications": [
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "message": {
- "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
- "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
- },
- "level": "note",
- "timeUtc": "2024-10-16T03:27:35.793+00:00",
- "descriptor": {
- "id": "cpp/extractor/summary",
- "index": 1
- },
- "properties": {
- "attributes": {
- "cache-hits": 0,
- "cache-misses": 1,
- "extractor-failures": 1,
- "extractor-successes": 0,
- "trap-caching": "disabled"
- },
- "visibility": {
- "statusPage": false,
- "telemetry": true
- }
- }
- }
- ],
- "executionSuccessful": true
- }
- ],
- "artifacts": [
- {
- "location": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- ],
- "results": [
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[TestInner1](1): IRQL potentially too high at call to [TestInner2](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 42,
- "startColumn": 12,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "1defbc9e59f0310b:1",
- "primaryLocationStartColumnFingerprint": "7"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 41,
- "startColumn": 10,
- "endColumn": 20
- }
- },
- "message": {
- "text": "TestInner1"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 42,
- "startColumn": 12,
- "endColumn": 22
- }
- },
- "message": {
- "text": "TestInner2"
- }
- }
- ]
- },
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[TestInner2](1): IRQL potentially too high at call to [TestInner4](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 36,
- "startColumn": 14,
- "endColumn": 24
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "7ae2af586e0dd70a:1",
- "primaryLocationStartColumnFingerprint": "9"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 26,
- "startColumn": 10,
- "endColumn": 20
- }
- },
- "message": {
- "text": "TestInner2"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 36,
- "startColumn": 14,
- "endColumn": 24
- }
- },
- "message": {
- "text": "TestInner4"
- }
- }
- ]
- },
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[DpcForIsrRoutine](1): IRQL potentially too high at call to [IoGetInitialStack](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 366,
- "startColumn": 5,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "48e9dbeaff18e9e7:1",
- "primaryLocationStartColumnFingerprint": "0"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 347,
- "endColumn": 17
- }
- },
- "message": {
- "text": "DpcForIsrRoutine"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 366,
- "startColumn": 5,
- "endColumn": 22
- }
- },
- "message": {
- "text": "IoGetInitialStack"
- }
- }
- ]
- },
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[CompletionRoutine](1): IRQL potentially too high at call to [KeSetEvent](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 324,
- "startColumn": 5,
- "endColumn": 15
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "779dfb1bf8eb10c3:1",
- "primaryLocationStartColumnFingerprint": "0"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 303,
- "endColumn": 18
- }
- },
- "message": {
- "text": "CompletionRoutine"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 324,
- "startColumn": 5,
- "endColumn": 15
- }
- },
- "message": {
- "text": "KeSetEvent"
- }
- }
- ]
- }
- ],
- "columnKind": "utf16CodeUnits",
- "properties": {
- "semmle.formatSpecifier": "sarifv2.1.0"
- }
- }
- ]
-}
\ No newline at end of file
+{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL","organization":"GitHub","semanticVersion":"2.24.2","notifications":[{"id":"cpp/baseline/expected-extracted-files","name":"cpp/baseline/expected-extracted-files","shortDescription":{"text":"Expected extracted files"},"fullDescription":{"text":"Files appearing in the source archive that are expected to be extracted."},"defaultConfiguration":{"enabled":true},"properties":{"tags":["expected-extracted-files","telemetry"]}},{"id":"cli/file-coverage-baseline","name":"cli/file-coverage-baseline","shortDescription":{"text":"File coverage baseline telemetry"},"fullDescription":{"text":"File coverage baseline telemetry"},"defaultConfiguration":{"enabled":true}},{"id":"cli/platform","name":"cli/platform","shortDescription":{"text":"Platform"},"fullDescription":{"text":"Platform"},"defaultConfiguration":{"enabled":true}},{"id":"cpp/extractor/summary","name":"cpp/extractor/summary","shortDescription":{"text":"C++ extractor telemetry"},"fullDescription":{"text":"C++ extractor telemetry"},"defaultConfiguration":{"enabled":true}}],"rules":[{"id":"cpp/drivers/irql-too-high","name":"cpp/drivers/irql-too-high","shortDescription":{"text":"IRQL too high (C28121)"},"fullDescription":{"text":"A function annotated with IRQL requirements was called at an IRQL too high for the requirements."},"defaultConfiguration":{"enabled":true,"level":"warning"},"help":{"text":"# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n","markdown":"# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"},"properties":{"tags":["correctness","ca_ported","wddst"],"description":"A function annotated with IRQL requirements was called at an IRQL too high for the requirements.","feature.area":"Multiple","id":"cpp/drivers/irql-too-high","impact":"Exploitable Design","kind":"problem","name":"IRQL too high (C28121)","opaqueid":"CQLD-C28121","owner.email":"sdat@microsoft.com","platform":"Desktop","precision":"medium","problem.severity":"warning","query-version":"v5","repro.text":"The following function call is taking place at an IRQL too high for what the call target is annotated as.","scope":"domainspecific","security.severity":"Low"}}]},"extensions":[{"name":"microsoft/windows-drivers","semanticVersion":"1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307","locations":[{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]},{"name":"codeql/cpp-all","semanticVersion":"7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1","locations":[{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]}]},"invocations":[{"toolExecutionNotifications":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":2}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:20:15.559452300Z","descriptor":{"id":"cli/file-coverage-baseline","index":1},"properties":{"attributes":{"durationMilliseconds":289},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:20:15.563108200Z","descriptor":{"id":"cli/platform","index":2},"properties":{"attributes":{"arch":"amd64","name":"Windows 11","version":"10.0"},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":"Internal telemetry for the C++ extractor.\n\nNo action needed.","markdown":"Internal telemetry for the C++ extractor.\n\nNo action needed."},"level":"note","timeUtc":"2026-04-28T23:20:55.172937400Z","descriptor":{"id":"cpp/extractor/summary","index":3},"properties":{"attributes":{"cache-hits":0,"cache-misses":1,"compilers":[{"program":"cl","version":"Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"}],"extractor-failures":1,"extractor-successes":0,"trap-caching":"disabled"},"visibility":{"statusPage":false,"telemetry":true}}}],"executionSuccessful":true}],"artifacts":[{"location":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}},{"location":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1}},{"location":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":2}}],"results":[{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[failForIrqlTooHigh_globalReassigned](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":150,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"b144babee8b922b:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":147,"startColumn":6,"endColumn":41}},"message":{"text":"failForIrqlTooHigh_globalReassigned"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":150,"startColumn":9,"endColumn":28}},"message":{"text":"PassiveOnly_TooHigh"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[failForIrqlTooHigh_byReference](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":138,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"c860f155ed9fe979:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":133,"startColumn":6,"endColumn":36}},"message":{"text":"failForIrqlTooHigh_byReference"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":138,"startColumn":9,"endColumn":28}},"message":{"text":"PassiveOnly_TooHigh"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[failForIrqlTooHigh_increment](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":126,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"bf3c3ea7c818ee5f:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":121,"startColumn":6,"endColumn":34}},"message":{"text":"failForIrqlTooHigh_increment"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":126,"startColumn":9,"endColumn":28}},"message":{"text":"PassiveOnly_TooHigh"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[failForIrqlTooHigh_compoundAssignment](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":115,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"b8558f6fccea75ce:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":110,"startColumn":6,"endColumn":43}},"message":{"text":"failForIrqlTooHigh_compoundAssignment"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":115,"startColumn":9,"endColumn":28}},"message":{"text":"PassiveOnly_TooHigh"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[TestInner1](1): IRQL potentially too high at call to [TestInner2](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":42,"startColumn":12,"endColumn":22}}}],"partialFingerprints":{"primaryLocationLineHash":"1defbc9e59f0310b:1","primaryLocationStartColumnFingerprint":"7"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":41,"startColumn":10,"endColumn":20}},"message":{"text":"TestInner1"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":42,"startColumn":12,"endColumn":22}},"message":{"text":"TestInner2"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[TestInner2](1): IRQL potentially too high at call to [TestInner4](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":36,"startColumn":14,"endColumn":24}}}],"partialFingerprints":{"primaryLocationLineHash":"7ae2af586e0dd70a:1","primaryLocationStartColumnFingerprint":"9"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":26,"startColumn":10,"endColumn":20}},"message":{"text":"TestInner2"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":36,"startColumn":14,"endColumn":24}},"message":{"text":"TestInner4"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[DpcForIsrRoutine](1): IRQL potentially too high at call to [IoGetInitialStack](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":379,"startColumn":5,"endColumn":22}}}],"partialFingerprints":{"primaryLocationLineHash":"48e9dbeaff18e9e7:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":360,"endColumn":17}},"message":{"text":"DpcForIsrRoutine"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":379,"startColumn":5,"endColumn":22}},"message":{"text":"IoGetInitialStack"}}]},{"ruleId":"cpp/drivers/irql-too-high","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-high","index":0},"message":{"text":"[CompletionRoutine](1): IRQL potentially too high at call to [KeSetEvent](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":337,"startColumn":5,"endColumn":15}}}],"partialFingerprints":{"primaryLocationLineHash":"779dfb1bf8eb10c3:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":316,"endColumn":18}},"message":{"text":"CompletionRoutine"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":1},"region":{"startLine":337,"startColumn":5,"endColumn":15}},"message":{"text":"KeSetEvent"}}]}],"columnKind":"utf16CodeUnits","properties":{"semmle.formatSpecifier":"sarifv2.1.0"}}]}
\ No newline at end of file
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
index ceb10bf4..769216bd 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
@@ -43,11 +43,5 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
-**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:
-
-* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);
-* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;
-* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;
-* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
-If you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).
+**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
index 94af6437..86c7abe4 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
@@ -51,28 +51,19 @@
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
- Known false negatives. The query suppresses calls inside an
- if (b) block when b is a variable initialized to
- FALSE / 0 with no plain = assignment
- to it visible in the same enclosing function. This suppression is intended
- to silence dead-branch patterns produced by NDIS macros such as
- FILTER_ACQUIRE_LOCK(lock, bFalse), but it is too lax. The
- following mutations of b all bypass the check, so the call
- inside the branch may be silently dropped even when b is in
- fact true at runtime:
-
-
- - compound assignments such as
b |= 1, b &= mask, b += value (the predicate looks only for AssignExpr, which represents plain = assignments; compound forms are AssignOperation);
- - increment / decrement (
b++, --b) which is CrementOperation, not an assignment;
- - pass-by-reference helpers such as
SetFlag(&b), where the mutation is invisible to a syntactic scan of the enclosing function;
- - file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).
-
-
- If you rely on a runtime flag to gate IRQL-sensitive code and the call is
- incorrectly suppressed, work around the limitation by replacing the gated
- call with a direct, annotated call site or by rewriting the condition so
- the predicate fails (for example, use != 0 against a value
- the predicate cannot constant-fold).
+ Dead-branch suppression. The query suppresses calls inside an
+ if (b) block when b is a non-static
+ local variable initialized to FALSE / 0 that is
+ never mutated (no =, no compound assignment, no
+ ++ / --) and whose address is never taken.
+ Compile-time constant 0 conditions are also suppressed.
+ This is intended to silence dead-branch patterns produced by NDIS
+ macros such as FILTER_ACQUIRE_LOCK(lock, bFalse); the
+ conditions on the variable case are deliberately conservative to
+ avoid silently dropping legitimate findings when the runtime value
+ of the variable cannot be proven to remain FALSE
+ (globals reassigned in another function, address-taken locals
+ mutated through a pointer, compound mutation, etc.).
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
index 1eacef26..755f40e1 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v5
+ * @query-version v6
*/
import cpp
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
index d5b95a21..aab03c85 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
@@ -1,345 +1 @@
-{
- "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
- "version": "2.1.0",
- "runs": [
- {
- "tool": {
- "driver": {
- "name": "CodeQL",
- "organization": "GitHub",
- "semanticVersion": "2.15.4",
- "notifications": [
- {
- "id": "cpp/baseline/expected-extracted-files",
- "name": "cpp/baseline/expected-extracted-files",
- "shortDescription": {
- "text": "Expected extracted files"
- },
- "fullDescription": {
- "text": "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration": {
- "enabled": true
- },
- "properties": {
- "tags": [
- "expected-extracted-files",
- "telemetry"
- ]
- }
- }
- ],
- "rules": [
- {
- "id": "cpp/drivers/irql-too-low",
- "name": "cpp/drivers/irql-too-low",
- "shortDescription": {
- "text": "IRQL too low (C28120)"
- },
- "fullDescription": {
- "text": "A function annotated with IRQL requirements was called at an IRQL too low for the requirements."
- },
- "defaultConfiguration": {
- "enabled": true,
- "level": "warning"
- },
- "properties": {
- "tags": [
- "correctness",
- "wddst"
- ],
- "description": "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.",
- "feature.area": "Multiple",
- "id": "cpp/drivers/irql-too-low",
- "impact": "Exploitable Design",
- "kind": "problem",
- "name": "IRQL too low (C28120)",
- "opaqueid": "CQLD-C28120",
- "owner.email": "sdat@microsoft.com",
- "platform": "Desktop",
- "precision": "medium",
- "problem.severity": "warning",
- "query-version": "v2",
- "repro.text": "The following function call is taking place at an IRQL too low for what the call target is annotated as.",
- "scope": "domainspecific",
- "security.severity": "Low"
- }
- }
- ]
- },
- "extensions": [
- {
- "name": "microsoft/windows-drivers",
- "semanticVersion": "1.1.0+2affc3c634804dac7504a483a378cc9ba22a0f0b",
- "locations": [
- {
- "uri": "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/",
- "description": {
- "text": "The QL pack root directory."
- }
- },
- {
- "uri": "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- }
- }
- ]
- }
- ]
- },
- "invocations": [
- {
- "toolExecutionNotifications": [
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- }
- ],
- "executionSuccessful": true
- }
- ],
- "artifacts": [
- {
- "location": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- },
- {
- "location": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- ],
- "results": [
- {
- "ruleId": "cpp/drivers/irql-too-low",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-low",
- "index": 0
- },
- "message": {
- "text": "[TestInner1](1): IRQL potentially too low at call to [TestInner2](2). Minimum IRQL for this call: 1, IRQL at preceding node: 0"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 41,
- "startColumn": 12,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "1defbc9e59f0310b:1",
- "primaryLocationStartColumnFingerprint": "7"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 40,
- "startColumn": 10,
- "endColumn": 20
- }
- },
- "message": {
- "text": "TestInner1"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 41,
- "startColumn": 12,
- "endColumn": 22
- }
- },
- "message": {
- "text": "TestInner2"
- }
- }
- ]
- },
- {
- "ruleId": "cpp/drivers/irql-too-low",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-low",
- "index": 0
- },
- "message": {
- "text": "[someFunc](1): IRQL potentially too low at call to [TestInner3](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 21,
- "startColumn": 12,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "bf32240018f4d9fb:1",
- "primaryLocationStartColumnFingerprint": "7"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 20,
- "startColumn": 10,
- "endColumn": 18
- }
- },
- "message": {
- "text": "someFunc"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 21,
- "startColumn": 12,
- "endColumn": 22
- }
- },
- "message": {
- "text": "TestInner3"
- }
- }
- ]
- }
- ],
- "columnKind": "utf16CodeUnits",
- "properties": {
- "semmle.formatSpecifier": "sarifv2.1.0"
- }
- }
- ]
-}
\ No newline at end of file
+{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL","organization":"GitHub","semanticVersion":"2.24.2","notifications":[{"id":"cpp/baseline/expected-extracted-files","name":"cpp/baseline/expected-extracted-files","shortDescription":{"text":"Expected extracted files"},"fullDescription":{"text":"Files appearing in the source archive that are expected to be extracted."},"defaultConfiguration":{"enabled":true},"properties":{"tags":["expected-extracted-files","telemetry"]}},{"id":"cli/file-coverage-baseline","name":"cli/file-coverage-baseline","shortDescription":{"text":"File coverage baseline telemetry"},"fullDescription":{"text":"File coverage baseline telemetry"},"defaultConfiguration":{"enabled":true}},{"id":"cli/platform","name":"cli/platform","shortDescription":{"text":"Platform"},"fullDescription":{"text":"Platform"},"defaultConfiguration":{"enabled":true}},{"id":"cpp/extractor/summary","name":"cpp/extractor/summary","shortDescription":{"text":"C++ extractor telemetry"},"fullDescription":{"text":"C++ extractor telemetry"},"defaultConfiguration":{"enabled":true}}],"rules":[{"id":"cpp/drivers/irql-too-low","name":"cpp/drivers/irql-too-low","shortDescription":{"text":"IRQL too low (C28120)"},"fullDescription":{"text":"A function annotated with IRQL requirements was called at an IRQL too low for the requirements."},"defaultConfiguration":{"enabled":true,"level":"warning"},"help":{"text":"# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n","markdown":"# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"},"properties":{"tags":["correctness","ca_ported","wddst"],"description":"A function annotated with IRQL requirements was called at an IRQL too low for the requirements.","feature.area":"Multiple","id":"cpp/drivers/irql-too-low","impact":"Exploitable Design","kind":"problem","name":"IRQL too low (C28120)","opaqueid":"CQLD-C28120","owner.email":"sdat@microsoft.com","platform":"Desktop","precision":"medium","problem.severity":"warning","query-version":"v6","repro.text":"The following function call is taking place at an IRQL too low for what the call target is annotated as.","scope":"domainspecific","security.severity":"Low"}}]},"extensions":[{"name":"microsoft/windows-drivers","semanticVersion":"1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307","locations":[{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]},{"name":"codeql/cpp-all","semanticVersion":"7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1","locations":[{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/","description":{"text":"The QL pack root directory."},"properties":{"tags":["CodeQL/LocalPackRoot"]}},{"uri":"file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml","description":{"text":"The QL pack definition file."},"properties":{"tags":["CodeQL/LocalPackDefinitionFile"]}}]}]},"invocations":[{"toolExecutionNotifications":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}}],"message":{"text":""},"level":"none","descriptor":{"id":"cpp/baseline/expected-extracted-files","index":0},"properties":{"formattedMessage":{"text":""}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:23:11.908037200Z","descriptor":{"id":"cli/file-coverage-baseline","index":1},"properties":{"attributes":{"durationMilliseconds":308},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":""},"level":"none","timeUtc":"2026-04-28T23:23:11.915033800Z","descriptor":{"id":"cli/platform","index":2},"properties":{"attributes":{"arch":"amd64","name":"Windows 11","version":"10.0"},"visibility":{"statusPage":false,"telemetry":true}}},{"message":{"text":"Internal telemetry for the C++ extractor.\n\nNo action needed.","markdown":"Internal telemetry for the C++ extractor.\n\nNo action needed."},"level":"note","timeUtc":"2026-04-28T23:23:50.604873300Z","descriptor":{"id":"cpp/extractor/summary","index":3},"properties":{"attributes":{"cache-hits":0,"cache-misses":1,"compilers":[{"program":"cl","version":"Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"}],"extractor-failures":1,"extractor-successes":0,"trap-caching":"disabled"},"visibility":{"statusPage":false,"telemetry":true}}}],"executionSuccessful":true}],"artifacts":[{"location":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0}},{"location":{"uri":"driver/fail_driver1.h","uriBaseId":"%SRCROOT%","index":1}},{"location":{"uri":"driver/fail_driver1.c","uriBaseId":"%SRCROOT%","index":2}}],"results":[{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[failForIrqlTooLow_globalReassigned](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":113,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"4e9bf712603567a:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":111,"startColumn":6,"endColumn":40}},"message":{"text":"failForIrqlTooLow_globalReassigned"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":113,"startColumn":9,"endColumn":28}},"message":{"text":"DispatchOnly_TooLow"}}]},{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[failForIrqlTooLow_byReference](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":106,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"30d5b4e4b89956a4:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":102,"startColumn":6,"endColumn":35}},"message":{"text":"failForIrqlTooLow_byReference"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":106,"startColumn":9,"endColumn":28}},"message":{"text":"DispatchOnly_TooLow"}}]},{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[failForIrqlTooLow_increment](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":97,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"dd920dbcc12ad933:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":93,"startColumn":6,"endColumn":33}},"message":{"text":"failForIrqlTooLow_increment"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":97,"startColumn":9,"endColumn":28}},"message":{"text":"DispatchOnly_TooLow"}}]},{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[failForIrqlTooLow_compoundAssignment](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":88,"startColumn":9,"endColumn":28}}}],"partialFingerprints":{"primaryLocationLineHash":"d830060d8a1428a7:1","primaryLocationStartColumnFingerprint":"0"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":84,"startColumn":6,"endColumn":42}},"message":{"text":"failForIrqlTooLow_compoundAssignment"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":88,"startColumn":9,"endColumn":28}},"message":{"text":"DispatchOnly_TooLow"}}]},{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[TestInner1](1): IRQL potentially too low at call to [TestInner2](2). Minimum IRQL for this call: 1, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":41,"startColumn":12,"endColumn":22}}}],"partialFingerprints":{"primaryLocationLineHash":"1defbc9e59f0310b:1","primaryLocationStartColumnFingerprint":"7"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":40,"startColumn":10,"endColumn":20}},"message":{"text":"TestInner1"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":41,"startColumn":12,"endColumn":22}},"message":{"text":"TestInner2"}}]},{"ruleId":"cpp/drivers/irql-too-low","ruleIndex":0,"rule":{"id":"cpp/drivers/irql-too-low","index":0},"message":{"text":"[someFunc](1): IRQL potentially too low at call to [TestInner3](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":21,"startColumn":12,"endColumn":22}}}],"partialFingerprints":{"primaryLocationLineHash":"bf32240018f4d9fb:1","primaryLocationStartColumnFingerprint":"7"},"relatedLocations":[{"id":1,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":20,"startColumn":10,"endColumn":18}},"message":{"text":"someFunc"}},{"id":2,"physicalLocation":{"artifactLocation":{"uri":"driver/driver_snippet.c","uriBaseId":"%SRCROOT%","index":0},"region":{"startLine":21,"startColumn":12,"endColumn":22}},"message":{"text":"TestInner3"}}]}],"columnKind":"utf16CodeUnits","properties":{"semmle.formatSpecifier":"sarifv2.1.0"}}]}
\ No newline at end of file
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index 7da8ae35..7ad9a7b9 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -927,8 +927,11 @@
/**
* Holds if `call` is located inside the "then" branch of an `if` statement
- * whose condition is a compile-time-constant `FALSE` (0) value, or a variable
- * that is singly defined with value 0/FALSE.
+ * whose condition is a compile-time-constant `FALSE` (0) value, or a
+ * non-`static` local variable that is initialized to `0` / `FALSE`,
+ * never assigned (with any assignment operator) or incremented /
+ * decremented in the enclosing function, and whose address is never
+ * taken.
*
* This detects patterns like:
* ```
@@ -936,23 +939,49 @@
* if (bFalse) { KeAcquireSpinLockAtDpcLevel(...); } // dead branch
* ```
* Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK, etc.).
+ *
+ * The conservative-by-default conditions on the variable case avoid
+ * silently dropping legitimate findings when the runtime value of the
+ * variable cannot be proven to remain `FALSE`:
+ *
+ * - `LocalVariable v` excludes file-scope and namespace globals,
+ * which can be reassigned from any other function in the
+ * translation unit (or even another TU).
+ * - `not v.isStatic()` excludes function-static variables, whose
+ * value persists across calls and could be set by a previous
+ * invocation.
+ * - The `Assignment` predicate matches plain `=` (`AssignExpr`) and
+ * all compound operators (`AssignOperation`: `|=`, `&=`, `+=`,
+ * etc.); the original `AssignExpr`-only check was too narrow.
+ * - `CrementOperation` covers `++` and `--`, which are not modeled
+ * as assignments in the cpp library.
+ * - Bailing out when the variable's address is taken
+ * (`AddressOfExpr`) prevents missing mutations performed by
+ * callees through a pointer (e.g., `SetFlag(&bFalse)`).
*/
predicate isInConstantFalseBranch(FunctionCall call) {
exists(IfStmt ifStmt |
- // The call is in the "then" block of the if statement
ifStmt.getThen().getAChild*() = call and
(
- // Condition is a literal 0 / false
+ // Condition is a literal 0 / false (or any compile-time constant 0).
ifStmt.getCondition().getValue() = "0"
or
- // Condition is a variable access to a variable initialized to 0/FALSE
- // with no subsequent reassignment in the function
- exists(Variable v |
+ // Condition is a variable access to a non-static local variable
+ // that is initialized to 0/FALSE and never mutated.
+ exists(LocalVariable v |
ifStmt.getCondition().(VariableAccess).getTarget() = v and
+ not v.isStatic() and
v.getInitializer().getExpr().getValue() = "0" and
- not exists(AssignExpr ae |
- ae.getLValue().(VariableAccess).getTarget() = v and
- ae.getEnclosingFunction() = call.getEnclosingFunction()
+ not exists(Assignment a |
+ a.getLValue().(VariableAccess).getTarget() = v and
+ a.getEnclosingFunction() = call.getEnclosingFunction()
+ ) and
+ not exists(CrementOperation co |
+ co.getOperand().(VariableAccess).getTarget() = v and
+ co.getEnclosingFunction() = call.getEnclosingFunction()
+ ) and
+ not exists(AddressOfExpr ao |
+ ao.getOperand().(VariableAccess).getTarget() = v
)
)
)
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index 59976b95..561308b7 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -118,28 +118,46 @@ class PagedCodeMacro extends MacroInvocation {
}
/**
- * Gets the enclosing `PagedFunctionDeclaration` for this macro invocation,
- * if any. Excludes template instantiations: each function-template
- * instantiation produces its own AST and its own `MacroInvocation` records,
- * with line attribution that may shift by ±1 relative to the source-level
- * `PAGED_CODE()` call. Counting those instantiation-level MIs as separate
- * invocations causes false positives in templated headers. The source-level
- * (uninstantiated) function template still satisfies this predicate, so
- * real duplicate `PAGED_CODE`s in the source are still reported.
+ * Gets the source-level enclosing `PagedFunctionDeclaration` for this
+ * macro invocation, deduplicating across template instantiations so
+ * that each source-level function template body produces a single
+ * match key regardless of how many instantiations the extractor
+ * produced.
*
- * Performance/correctness note: routed through `getStmt()` (which is built
- * on the cheap `getAnExpandedElement`/`inmacroexpansion` relation) rather
- * than the stock `MacroInvocation.getEnclosingFunction()` which uses
- * `getAnAffectedElement` (a much larger
- * `inmacroexpansion ∪ macrolocationbind` join that scales poorly on large
- * codebases and can cause analysis timeouts). `getStmt()` returns the
- * unique outermost `Stmt` produced by the macro expansion.
- * `PAGED_CODE`/`PAGED_CODE_LOCKED` always expand to a statement-form
+ * Three cases:
+ * - **Non-templated function.** `getStmt().getEnclosingFunction()`
+ * returns a unique non-instantiation `Function`, which is itself
+ * the source-level entity.
+ * - **C++ function template instantiations.** The cpp extractor
+ * populates `getStmt()` with one expanded `Stmt` per instantiation;
+ * each instantiation's enclosing function is a distinct
+ * `FunctionTemplateInstantiation`. We project all of these back
+ * to their underlying `TemplateFunction` via `getTemplate()`, so
+ * a single source-level template collapses to one match key.
+ * `PagedFunctionDeclaration`-ness is checked on the instantiation
+ * (which has a concrete file location for the page-segment
+ * heuristics to work against) rather than on the template entity.
+ * - **Specialisations and non-template-paged functions** are excluded
+ * by the `PagedFunctionDeclaration` requirement.
+ *
+ * The macro is routed through `getStmt()` rather than the stock
+ * `MacroInvocation.getEnclosingFunction()` because the latter is built
+ * on `getAnAffectedElement` (an expensive `inmacroexpansion ∪
+ * macrolocationbind` join that scales poorly on large codebases).
+ * `getStmt()` uses only the cheap `inmacroexpansion` relation.
+ * `PAGED_CODE` / `PAGED_CODE_LOCKED` always expand to a statement-form
* `NT_ASSERT_ASSUME(...)`, so `getStmt()` is well-defined.
*/
Function getEnclosingPagedFunction() {
- result = this.getStmt().getEnclosingFunction() and
- result instanceof PagedFunctionDeclaration and
- not result instanceof FunctionTemplateInstantiation
+ exists(Function rawEnclosing |
+ rawEnclosing = this.getStmt().getEnclosingFunction() and
+ rawEnclosing instanceof PagedFunctionDeclaration
+ |
+ not rawEnclosing instanceof FunctionTemplateInstantiation and
+ result = rawEnclosing
+ or
+ rawEnclosing instanceof FunctionTemplateInstantiation and
+ result = rawEnclosing.(FunctionTemplateInstantiation).getTemplate()
+ )
}
}
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
index 8e431b4c..fd899a3b 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
@@ -74,5 +74,5 @@ DispatchShutdown (
* [ C28171 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28171-function-has-more-than-one-page-macro-instance)
## Semmle-specific notes
-**Function templates: known false negative.** The query excludes `FunctionTemplateInstantiation` functions when locating the enclosing function for each `PAGED_CODE` / `PAGED_CODE_LOCKED` macro invocation. The exclusion was added to avoid duplicate findings caused by per-instantiation line attribution drift. As a side effect, a duplicate `PAGED_CODE` inside the body of a C++ function template that is only ever observed as instantiations (and not as a non-instantiated template entity in the extracted AST) will not be reported. C++ function templates are uncommon in WDM / KMDF drivers, but if you do use them and need this check, lift the duplicated `PAGED_CODE` macro into a non-templated helper or split the body so each path enters a distinct paged function.
+**C++ function template support.** When the same source-level `PAGED_CODE` macro is expanded into multiple `FunctionTemplateInstantiation` bodies, the query collapses all instantiations of a single source-level template into one match key (via the underlying `TemplateFunction`) so duplicates inside a templated paged function body are reported once at the source-level location. Specialisations and non-template-paged functions are excluded.
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
index 5025985a..60f16dc6 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
@@ -23,18 +23,15 @@
- Function templates: known false negative. The query excludes
- FunctionTemplateInstantiation functions when locating the
- enclosing function for each PAGED_CODE /
- PAGED_CODE_LOCKED macro invocation. The exclusion was added
- to avoid duplicate findings caused by per-instantiation line attribution
- drift. As a side effect, a duplicate PAGED_CODE inside the
- body of a C++ function template that is only ever observed as
- instantiations (and not as a non-instantiated template entity in the
- extracted AST) will not be reported. C++ function templates are uncommon
- in WDM / KMDF drivers, but if you do use them and need this check, lift
- the duplicated PAGED_CODE macro into a non-templated helper
- or split the body so each path enters a distinct paged function.
+ C++ function template support. When the same source-level
+ PAGED_CODE macro is expanded into multiple
+ FunctionTemplateInstantiation bodies, the query
+ collapses all instantiations of a single source-level template
+ into one match key (via the underlying
+ TemplateFunction) so duplicates inside a templated
+ paged function body are reported once at the source-level
+ location. Specialisations and non-template-paged functions are
+ excluded.
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
index 01511ee5..8f8098a0 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v2
+ * @query-version v3
*/
import cpp
From b2493b318be32216cbbf111ddf4fee69c9bc1f22 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 18:31:42 -0700
Subject: [PATCH 10/19] Fix MultiplePagedCode cross-file conflation FP
The previous fix projected FunctionTemplateInstantiation back to its
underlying TemplateFunction to deduplicate findings inside a templated
function body. However, the cpp extractor sometimes consolidates two
ODR-equivalent template definitions in different headers into a single
TemplateFunction entity. When two driver-private headers each defined
e.g. emplate Aggregator_SendProperty(...) containing one
PAGED_CODE(), my projection collapsed both definitions to one match
key and the query reported a spurious "duplicate" across the two
unrelated functions.
This change reverts the projection: getEnclosingPagedFunction() now
returns the concrete Function produced by
getStmt().getEnclosingFunction() (which can be a
FunctionTemplateInstantiation for templated bodies). The query joins
on enclosing-function identity AND requires the two PagedCodeMacro
invocations and the enclosing function to all share the same file, so
the cross-file conflation can no longer match. Same-file deduplication
across template instantiations within a single TU still produces a
single finding because the multiple (mi2, f) tuples project to one
mi2 at the SARIF level.
Validation:
* In-tree MultiplePagedCode test: diff +0/-0 (the existing
DispatchShutdown baseline TP is preserved).
* Out-of-tree C++ KMDF template DB: still reports 1 finding for the
templated duplicate PAGED_CODE, matching the pre-branch baseline.
* Large representative codebase that previously surfaced the cross-file
FP: now reports 0 findings (down from the spurious 1).
v3 -> v4.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
src/drivers/libraries/Page.qll | 58 +++++++------------
.../MultiplePagedCode/MultiplePagedCode.ql | 14 ++++-
2 files changed, 32 insertions(+), 40 deletions(-)
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index 561308b7..52f2a60f 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -118,46 +118,30 @@ class PagedCodeMacro extends MacroInvocation {
}
/**
- * Gets the source-level enclosing `PagedFunctionDeclaration` for this
- * macro invocation, deduplicating across template instantiations so
- * that each source-level function template body produces a single
- * match key regardless of how many instantiations the extractor
- * produced.
+ * Gets a paged enclosing function for this macro invocation, including
+ * `FunctionTemplateInstantiation` results when the macro lives inside a
+ * templated function body. Each instantiation is a distinct `Function`,
+ * so two `PagedCodeMacro` invocations are guaranteed to "share" one of
+ * these results only when they are inside the same instantiation body
+ * (not merely two ODR-equivalent template entities that the extractor
+ * may consolidate).
*
- * Three cases:
- * - **Non-templated function.** `getStmt().getEnclosingFunction()`
- * returns a unique non-instantiation `Function`, which is itself
- * the source-level entity.
- * - **C++ function template instantiations.** The cpp extractor
- * populates `getStmt()` with one expanded `Stmt` per instantiation;
- * each instantiation's enclosing function is a distinct
- * `FunctionTemplateInstantiation`. We project all of these back
- * to their underlying `TemplateFunction` via `getTemplate()`, so
- * a single source-level template collapses to one match key.
- * `PagedFunctionDeclaration`-ness is checked on the instantiation
- * (which has a concrete file location for the page-segment
- * heuristics to work against) rather than on the template entity.
- * - **Specialisations and non-template-paged functions** are excluded
- * by the `PagedFunctionDeclaration` requirement.
- *
- * The macro is routed through `getStmt()` rather than the stock
- * `MacroInvocation.getEnclosingFunction()` because the latter is built
- * on `getAnAffectedElement` (an expensive `inmacroexpansion ∪
- * macrolocationbind` join that scales poorly on large codebases).
- * `getStmt()` uses only the cheap `inmacroexpansion` relation.
- * `PAGED_CODE` / `PAGED_CODE_LOCKED` always expand to a statement-form
+ * Routed through `getStmt()` rather than the stock
+ * `MacroInvocation.getEnclosingFunction()` to avoid the expensive
+ * `getAnAffectedElement` join on large codebases. `PAGED_CODE` /
+ * `PAGED_CODE_LOCKED` always expand to a statement-form
* `NT_ASSERT_ASSUME(...)`, so `getStmt()` is well-defined.
+ *
+ * NB: callers that need to compare two macro invocations for "same
+ * source-level function" must also require the macros and the
+ * enclosing function to agree on `getFile()`. The cpp extractor
+ * sometimes consolidates two ODR-equivalent template definitions in
+ * different headers into a single `TemplateFunction` /
+ * `FunctionTemplateInstantiation` entity, which would otherwise allow
+ * a macro in one header to match an enclosing function in another.
*/
Function getEnclosingPagedFunction() {
- exists(Function rawEnclosing |
- rawEnclosing = this.getStmt().getEnclosingFunction() and
- rawEnclosing instanceof PagedFunctionDeclaration
- |
- not rawEnclosing instanceof FunctionTemplateInstantiation and
- result = rawEnclosing
- or
- rawEnclosing instanceof FunctionTemplateInstantiation and
- result = rawEnclosing.(FunctionTemplateInstantiation).getTemplate()
- )
+ result = this.getStmt().getEnclosingFunction() and
+ result instanceof PagedFunctionDeclaration
}
}
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
index 8f8098a0..4b1c4504 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.ql
@@ -18,7 +18,7 @@
* ca_ported
* wddst
* @scope domainspecific
- * @query-version v3
+ * @query-version v4
*/
import cpp
@@ -34,13 +34,21 @@ import drivers.libraries.Page
// `getAnAffectedElement()` and materializes a relation that scales poorly
// on large codebases, causing analysis timeouts. `getStmt()` uses only the
// cheaper `inmacroexpansion` relation and returns the unique outermost
-// `Stmt`, which gives a well-defined enclosing function without fanning
-// out across template instantiations.
+// `Stmt`.
+//
+// The same-file constraint on `mi`, `mi2` and `f` defends against ODR-
+// equivalent template entities that the cpp extractor sometimes
+// consolidates across headers (e.g. two driver-private headers each
+// defining `template Foo()`); without the constraint, the inner
+// `mi` could match a macro invocation in a sibling header that happens to
+// share the consolidated `Function` entity.
from PagedCodeMacro mi2, Function f
where
f = mi2.getEnclosingPagedFunction() and
+ f.getFile() = mi2.getFile() and
exists(PagedCodeMacro mi |
mi.getEnclosingPagedFunction() = f and
+ mi.getFile() = mi2.getFile() and
mi.getLocation().getStartLine() < mi2.getLocation().getStartLine()
)
select mi2,
From 2c3d0e810347416c9d855dcbebc40ea9369c9ff5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 29 Apr 2026 04:09:45 +0000
Subject: [PATCH 11/19] Pretty-print SARIF baselines compressed by #220
Agent-Logs-Url: https://github.com/microsoft/Windows-Driver-Developer-Supplemental-Tools/sessions/e23e0bbb-d5d4-4b2c-808b-de74c56ed9dc
Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.sarif | 796 ++++++----
.../queries/IrqlTooHigh/IrqlTooHigh.sarif | 1383 +++++++++++------
.../queries/IrqlTooLow/IrqlTooLow.sarif | 457 +++++-
3 files changed, 1811 insertions(+), 825 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index 9379bb24..b393f76d 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -2,342 +2,514 @@
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
- {
- "tool": {
- "driver": {
- "name": "CodeQL",
- "organization": "GitHub",
- "semanticVersion": "2.19.3",
- "notifications": [
- {
- "id": "cpp/baseline/expected-extracted-files",
- "name": "cpp/baseline/expected-extracted-files",
- "shortDescription": {
- "text": "Expected extracted files"
- },
- "fullDescription": {
- "text": "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration": {
- "enabled": true
- },
- "properties": {
- "tags": [
- "expected-extracted-files",
- "telemetry"
- ]
- }
- },
- {
- "id": "cpp/extractor/summary",
- "name": "cpp/extractor/summary",
- "shortDescription": {
- "text": "C++ extractor telemetry"
- },
- "fullDescription": {
- "text": "C++ extractor telemetry"
- },
- "defaultConfiguration": {
- "enabled": true
- }
- }
- ],
- "rules": [
- {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "name": "cpp/drivers/irql-float-state-mismatch",
- "shortDescription": {
- "text": "Irql Float State Mismatch"
- },
- "fullDescription": {
- "text": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."
- },
- "defaultConfiguration": {
- "enabled": true,
- "level": "warning"
- },
- "properties": {
- "tags": [
- "correctness"
- ],
- "description": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).",
- "feature.area": "Multiple",
- "id": "cpp/drivers/irql-float-state-mismatch",
- "impact": "Insecure Coding Practice",
- "kind": "problem",
- "name": "Irql Float State Mismatch",
- "opaqueid": "CQLD-C28111",
- "owner.email:": "sdat@microsoft.com",
- "platform": "Desktop",
- "precision": "medium",
- "problem.severity": "warning",
- "query-version": "v1",
- "repro.text": "The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.",
- "scope": "domainspecific"
- }
- }
+ {
+ "tool": {
+ "driver": {
+ "name": "CodeQL",
+ "organization": "GitHub",
+ "semanticVersion": "2.24.2",
+ "notifications": [
+ {
+ "id": "cpp/baseline/expected-extracted-files",
+ "name": "cpp/baseline/expected-extracted-files",
+ "shortDescription": {
+ "text": "Expected extracted files"
+ },
+ "fullDescription": {
+ "text": "Files appearing in the source archive that are expected to be extracted."
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ },
+ "properties": {
+ "tags": [
+ "expected-extracted-files",
+ "telemetry"
+ ]
+ }
+ },
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cli/platform",
+ "name": "cli/platform",
+ "shortDescription": {
+ "text": "Platform"
+ },
+ "fullDescription": {
+ "text": "Platform"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cpp/extractor/summary",
+ "name": "cpp/extractor/summary",
+ "shortDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "fullDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ }
+ ],
+ "rules": [
+ {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "name": "cpp/drivers/irql-float-state-mismatch",
+ "shortDescription": {
+ "text": "Irql Float State Mismatch"
+ },
+ "fullDescription": {
+ "text": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation)."
+ },
+ "defaultConfiguration": {
+ "enabled": true,
+ "level": "warning"
+ },
+ "help": {
+ "text": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n",
+ "markdown": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n"
+ },
+ "properties": {
+ "tags": [
+ "correctness",
+ "ca_ported"
+ ],
+ "description": "The IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).",
+ "feature.area": "Multiple",
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "impact": "Insecure Coding Practice",
+ "kind": "problem",
+ "name": "Irql Float State Mismatch",
+ "opaqueid": "CQLD-C28111",
+ "owner.email": "sdat@microsoft.com",
+ "platform": "Desktop",
+ "precision": "medium",
+ "problem.severity": "warning",
+ "query-version": "v5",
+ "repro.text": "The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.",
+ "scope": "domainspecific"
+ }
+ }
+ ]
+ },
+ "extensions": [
+ {
+ "name": "microsoft/windows-drivers",
+ "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
+ "locations": [
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
]
+ }
},
- "extensions": [
- {
- "name": "microsoft/windows-drivers",
- "semanticVersion": "1.3.0+ffa7244da2c2fe57cdf6260be5d8b90e7c335336",
- "locations": [
- {
- "uri": "file:///C:/codeql-home/WDDST/src/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/codeql-home/WDDST/src/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- },
- {
- "name": "codeql/cpp-all",
- "semanticVersion": "3.1.0+d42788844f7ec0a6b9832140313cc2318e513987",
- "locations": [
- {
- "uri": "file:///C:/Users/jronstadt/.codeql/packages/codeql/cpp-all/3.1.0/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/Users/jronstadt/.codeql/packages/codeql/cpp-all/3.1.0/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- }
- ]
- },
- "invocations": [
{
- "toolExecutionNotifications": [
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "message": {
- "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
- "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
- },
- "level": "note",
- "timeUtc": "2025-01-17T05:02:26.230274500Z",
- "descriptor": {
- "id": "cpp/extractor/summary",
- "index": 1
- },
- "properties": {
- "attributes": {
- "cache-hits": 0,
- "cache-misses": 1,
- "extractor-failures": 1,
- "extractor-successes": 0,
- "trap-caching": "disabled"
- },
- "visibility": {
- "statusPage": false,
- "telemetry": true
- }
- }
- }
- ],
- "executionSuccessful": true
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
}
- ],
- "artifacts": [
+ ]
+ },
+ {
+ "name": "codeql/cpp-all",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
+ "locations": [
{
- "location": {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "invocations": [
+ {
+ "toolExecutionNotifications": [
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
"uri": "driver/driver_snippet.c",
"uriBaseId": "%SRCROOT%",
"index": 0
+ }
}
+ }
+ ],
+ "message": {
+ "text": ""
},
- {
- "location": {
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
"uri": "driver/fail_driver1.h",
"uriBaseId": "%SRCROOT%",
"index": 1
+ }
}
+ }
+ ],
+ "message": {
+ "text": ""
},
- {
- "location": {
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
"uri": "driver/fail_driver1.c",
"uriBaseId": "%SRCROOT%",
"index": 2
+ }
}
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
}
- ],
- "results": [
- {
- "ruleId": "cpp/drivers/irql-float-state-mismatch",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "index": 0
- },
- "message": {
- "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 23,
- "startColumn": 38,
- "endColumn": 46
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "b3909ff165022b51:1",
- "primaryLocationStartColumnFingerprint": "29"
- }
+ },
+ {
+ "message": {
+ "text": ""
},
- {
- "ruleId": "cpp/drivers/irql-float-state-mismatch",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-float-state-mismatch",
- "index": 0
- },
- "message": {
- "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 23,
- "startColumn": 37,
- "endColumn": 46
- }
- }
- }
+ "level": "none",
+ "timeUtc": "2026-04-28T23:26:00.575823400Z",
+ "descriptor": {
+ "id": "cli/file-coverage-baseline",
+ "index": 1
+ },
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 288
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-28T23:26:00.581682100Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
+ "properties": {
+ "attributes": {
+ "arch": "amd64",
+ "name": "Windows 11",
+ "version": "10.0"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
+ "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
+ },
+ "level": "note",
+ "timeUtc": "2026-04-28T23:26:39.590845200Z",
+ "descriptor": {
+ "id": "cpp/extractor/summary",
+ "index": 3
+ },
+ "properties": {
+ "attributes": {
+ "cache-hits": 0,
+ "cache-misses": 1,
+ "compilers": [
+ {
+ "program": "cl",
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
+ }
],
- "partialFingerprints": {
- "primaryLocationLineHash": "b3909ff165022b51:1",
- "primaryLocationStartColumnFingerprint": "28"
- }
+ "extractor-failures": 1,
+ "extractor-successes": 0,
+ "trap-caching": "disabled"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ }
+ ],
+ "executionSuccessful": true
+ }
+ ],
+ "artifacts": [
+ {
+ "location": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
+ }
+ }
+ ],
+ "results": [
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (0) does not match the irql level for the restore operation (2)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 112,
+ "startColumn": 33,
+ "endColumn": 36
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "32de180444120f36:1",
+ "primaryLocationStartColumnFingerprint": "28"
+ }
+ },
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 66,
+ "startColumn": 38,
+ "endColumn": 46
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "ff98177eaaf7d309:1",
+ "primaryLocationStartColumnFingerprint": "29"
+ }
+ },
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 66,
+ "startColumn": 37,
+ "endColumn": 46
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "ff98177eaaf7d309:1",
+ "primaryLocationStartColumnFingerprint": "28"
+ }
+ },
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 23,
+ "startColumn": 38,
+ "endColumn": 46
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "b3909ff165022b51:1",
+ "primaryLocationStartColumnFingerprint": "29"
+ }
+ },
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (1) does not match the irql level for the restore operation (0)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 23,
+ "startColumn": 37,
+ "endColumn": 46
+ }
}
+ }
],
- "columnKind": "utf16CodeUnits",
- "properties": {
- "semmle.formatSpecifier": "sarifv2.1.0"
+ "partialFingerprints": {
+ "primaryLocationLineHash": "b3909ff165022b51:1",
+ "primaryLocationStartColumnFingerprint": "28"
}
+ }
+ ],
+ "columnKind": "utf16CodeUnits",
+ "properties": {
+ "semmle.formatSpecifier": "sarifv2.1.0"
}
+ }
]
-}
\ No newline at end of file
+}
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
index 6cdc3298..a1a5d724 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
@@ -2,528 +2,911 @@
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
- {
- "tool": {
- "driver": {
- "name": "CodeQL",
- "organization": "GitHub",
- "semanticVersion": "2.18.4",
- "notifications": [
- {
- "id": "cpp/baseline/expected-extracted-files",
- "name": "cpp/baseline/expected-extracted-files",
- "shortDescription": {
- "text": "Expected extracted files"
- },
- "fullDescription": {
- "text": "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration": {
- "enabled": true
- },
- "properties": {
- "tags": [
- "expected-extracted-files",
- "telemetry"
- ]
- }
- },
- {
- "id": "cpp/extractor/summary",
- "name": "cpp/extractor/summary",
- "shortDescription": {
- "text": "C++ extractor telemetry"
- },
- "fullDescription": {
- "text": "C++ extractor telemetry"
- },
- "defaultConfiguration": {
- "enabled": true
- }
- }
- ],
- "rules": [
- {
- "id": "cpp/drivers/irql-too-high",
- "name": "cpp/drivers/irql-too-high",
- "shortDescription": {
- "text": "IRQL too high (C28121)"
- },
- "fullDescription": {
- "text": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements."
- },
- "defaultConfiguration": {
- "enabled": true,
- "level": "warning"
- },
- "properties": {
- "tags": [
- "correctness",
- "wddst"
- ],
- "description": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.",
- "feature.area": "Multiple",
- "id": "cpp/drivers/irql-too-high",
- "impact": "Exploitable Design",
- "kind": "problem",
- "name": "IRQL too high (C28121)",
- "opaqueid": "CQLD-C28121",
- "owner.email": "sdat@microsoft.com",
- "platform": "Desktop",
- "precision": "medium",
- "problem.severity": "warning",
- "query-version": "v2",
- "repro.text": "The following function call is taking place at an IRQL too high for what the call target is annotated as.",
- "scope": "domainspecific",
- "security.severity": "Low"
- }
- }
+ {
+ "tool": {
+ "driver": {
+ "name": "CodeQL",
+ "organization": "GitHub",
+ "semanticVersion": "2.24.2",
+ "notifications": [
+ {
+ "id": "cpp/baseline/expected-extracted-files",
+ "name": "cpp/baseline/expected-extracted-files",
+ "shortDescription": {
+ "text": "Expected extracted files"
+ },
+ "fullDescription": {
+ "text": "Files appearing in the source archive that are expected to be extracted."
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ },
+ "properties": {
+ "tags": [
+ "expected-extracted-files",
+ "telemetry"
+ ]
+ }
+ },
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cli/platform",
+ "name": "cli/platform",
+ "shortDescription": {
+ "text": "Platform"
+ },
+ "fullDescription": {
+ "text": "Platform"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cpp/extractor/summary",
+ "name": "cpp/extractor/summary",
+ "shortDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "fullDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ }
+ ],
+ "rules": [
+ {
+ "id": "cpp/drivers/irql-too-high",
+ "name": "cpp/drivers/irql-too-high",
+ "shortDescription": {
+ "text": "IRQL too high (C28121)"
+ },
+ "fullDescription": {
+ "text": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements."
+ },
+ "defaultConfiguration": {
+ "enabled": true,
+ "level": "warning"
+ },
+ "help": {
+ "text": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n",
+ "markdown": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"
+ },
+ "properties": {
+ "tags": [
+ "correctness",
+ "ca_ported",
+ "wddst"
+ ],
+ "description": "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.",
+ "feature.area": "Multiple",
+ "id": "cpp/drivers/irql-too-high",
+ "impact": "Exploitable Design",
+ "kind": "problem",
+ "name": "IRQL too high (C28121)",
+ "opaqueid": "CQLD-C28121",
+ "owner.email": "sdat@microsoft.com",
+ "platform": "Desktop",
+ "precision": "medium",
+ "problem.severity": "warning",
+ "query-version": "v5",
+ "repro.text": "The following function call is taking place at an IRQL too high for what the call target is annotated as.",
+ "scope": "domainspecific",
+ "security.severity": "Low"
+ }
+ }
+ ]
+ },
+ "extensions": [
+ {
+ "name": "microsoft/windows-drivers",
+ "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
+ "locations": [
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
]
+ }
},
- "extensions": [
- {
- "name": "microsoft/windows-drivers",
- "semanticVersion": "1.2.0+ebba6989b75fe7ac336c358d0838781e7b17e5c2",
- "locations": [
- {
- "uri": "file:///C:/codeql-home/WDDST/src/",
- "description": {
- "text": "The QL pack root directory."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackRoot"
- ]
- }
- },
- {
- "uri": "file:///C:/codeql-home/WDDST/src/qlpack.yml",
- "description": {
- "text": "The QL pack definition file."
- },
- "properties": {
- "tags": [
- "CodeQL/LocalPackDefinitionFile"
- ]
- }
- }
- ]
- }
- ]
- },
- "invocations": [
{
- "toolExecutionNotifications": [
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.h",
- "uriBaseId": "%SRCROOT%",
- "index": 2
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
- }
- }
- ],
- "message": {
- "text": ""
- },
- "level": "none",
- "descriptor": {
- "id": "cpp/baseline/expected-extracted-files",
- "index": 0
- },
- "properties": {
- "formattedMessage": {
- "text": ""
- }
- }
- },
- {
- "message": {
- "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
- "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
- },
- "level": "note",
- "timeUtc": "2024-10-16T03:27:35.793+00:00",
- "descriptor": {
- "id": "cpp/extractor/summary",
- "index": 1
- },
- "properties": {
- "attributes": {
- "cache-hits": 0,
- "cache-misses": 1,
- "extractor-failures": 1,
- "extractor-successes": 0,
- "trap-caching": "disabled"
- },
- "visibility": {
- "statusPage": false,
- "telemetry": true
- }
- }
- }
- ],
- "executionSuccessful": true
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
}
- ],
- "artifacts": [
+ ]
+ },
+ {
+ "name": "codeql/cpp-all",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
+ "locations": [
{
- "location": {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "invocations": [
+ {
+ "toolExecutionNotifications": [
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
"uri": "driver/driver_snippet.c",
"uriBaseId": "%SRCROOT%",
"index": 0
+ }
}
+ }
+ ],
+ "message": {
+ "text": ""
},
- {
- "location": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- }
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
},
- {
- "location": {
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
"uri": "driver/fail_driver1.h",
"uriBaseId": "%SRCROOT%",
"index": 2
+ }
}
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
}
- ],
- "results": [
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[TestInner1](1): IRQL potentially too high at call to [TestInner2](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 42,
- "startColumn": 12,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "1defbc9e59f0310b:1",
- "primaryLocationStartColumnFingerprint": "7"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 41,
- "startColumn": 10,
- "endColumn": 20
- }
- },
- "message": {
- "text": "TestInner1"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 42,
- "startColumn": 12,
- "endColumn": 22
- }
- },
- "message": {
- "text": "TestInner2"
- }
- }
- ]
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
},
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[TestInner2](1): IRQL potentially too high at call to [TestInner4](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 36,
- "startColumn": 14,
- "endColumn": 24
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "7ae2af586e0dd70a:1",
- "primaryLocationStartColumnFingerprint": "9"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 26,
- "startColumn": 10,
- "endColumn": 20
- }
- },
- "message": {
- "text": "TestInner2"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/driver_snippet.c",
- "uriBaseId": "%SRCROOT%",
- "index": 0
- },
- "region": {
- "startLine": 36,
- "startColumn": 14,
- "endColumn": 24
- }
- },
- "message": {
- "text": "TestInner4"
- }
- }
- ]
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
},
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[DpcForIsrRoutine](1): IRQL potentially too high at call to [IoGetInitialStack](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 366,
- "startColumn": 5,
- "endColumn": 22
- }
- }
- }
- ],
- "partialFingerprints": {
- "primaryLocationLineHash": "48e9dbeaff18e9e7:1",
- "primaryLocationStartColumnFingerprint": "0"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 347,
- "endColumn": 17
- }
- },
- "message": {
- "text": "DpcForIsrRoutine"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 366,
- "startColumn": 5,
- "endColumn": 22
- }
- },
- "message": {
- "text": "IoGetInitialStack"
- }
- }
- ]
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
},
- {
- "ruleId": "cpp/drivers/irql-too-high",
- "ruleIndex": 0,
- "rule": {
- "id": "cpp/drivers/irql-too-high",
- "index": 0
- },
- "message": {
- "text": "[CompletionRoutine](1): IRQL potentially too high at call to [KeSetEvent](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
- },
- "locations": [
- {
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 324,
- "startColumn": 5,
- "endColumn": 15
- }
- }
- }
+ "level": "none",
+ "timeUtc": "2026-04-28T23:20:15.559452300Z",
+ "descriptor": {
+ "id": "cli/file-coverage-baseline",
+ "index": 1
+ },
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 289
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-28T23:20:15.563108200Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
+ "properties": {
+ "attributes": {
+ "arch": "amd64",
+ "name": "Windows 11",
+ "version": "10.0"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
+ "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
+ },
+ "level": "note",
+ "timeUtc": "2026-04-28T23:20:55.172937400Z",
+ "descriptor": {
+ "id": "cpp/extractor/summary",
+ "index": 3
+ },
+ "properties": {
+ "attributes": {
+ "cache-hits": 0,
+ "cache-misses": 1,
+ "compilers": [
+ {
+ "program": "cl",
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
+ }
],
- "partialFingerprints": {
- "primaryLocationLineHash": "779dfb1bf8eb10c3:1",
- "primaryLocationStartColumnFingerprint": "0"
- },
- "relatedLocations": [
- {
- "id": 1,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 303,
- "endColumn": 18
- }
- },
- "message": {
- "text": "CompletionRoutine"
- }
- },
- {
- "id": 2,
- "physicalLocation": {
- "artifactLocation": {
- "uri": "driver/fail_driver1.c",
- "uriBaseId": "%SRCROOT%",
- "index": 1
- },
- "region": {
- "startLine": 324,
- "startColumn": 5,
- "endColumn": 15
- }
- },
- "message": {
- "text": "KeSetEvent"
- }
- }
- ]
+ "extractor-failures": 1,
+ "extractor-successes": 0,
+ "trap-caching": "disabled"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
}
+ }
],
- "columnKind": "utf16CodeUnits",
- "properties": {
- "semmle.formatSpecifier": "sarifv2.1.0"
+ "executionSuccessful": true
+ }
+ ],
+ "artifacts": [
+ {
+ "location": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
}
+ }
+ ],
+ "results": [
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooHigh_globalReassigned](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 150,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "b144babee8b922b:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 147,
+ "startColumn": 6,
+ "endColumn": 41
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooHigh_globalReassigned"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 150,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "PassiveOnly_TooHigh"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooHigh_byReference](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 138,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "c860f155ed9fe979:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 133,
+ "startColumn": 6,
+ "endColumn": 36
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooHigh_byReference"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 138,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "PassiveOnly_TooHigh"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooHigh_increment](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 126,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "bf3c3ea7c818ee5f:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 121,
+ "startColumn": 6,
+ "endColumn": 34
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooHigh_increment"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 126,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "PassiveOnly_TooHigh"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooHigh_compoundAssignment](1): IRQL potentially too high at call to [PassiveOnly_TooHigh](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 115,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "b8558f6fccea75ce:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 110,
+ "startColumn": 6,
+ "endColumn": 43
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooHigh_compoundAssignment"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 115,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "PassiveOnly_TooHigh"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[TestInner1](1): IRQL potentially too high at call to [TestInner2](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 42,
+ "startColumn": 12,
+ "endColumn": 22
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "1defbc9e59f0310b:1",
+ "primaryLocationStartColumnFingerprint": "7"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 41,
+ "startColumn": 10,
+ "endColumn": 20
+ }
+ },
+ "message": {
+ "text": "TestInner1"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 42,
+ "startColumn": 12,
+ "endColumn": 22
+ }
+ },
+ "message": {
+ "text": "TestInner2"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[TestInner2](1): IRQL potentially too high at call to [TestInner4](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 36,
+ "startColumn": 14,
+ "endColumn": 24
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "7ae2af586e0dd70a:1",
+ "primaryLocationStartColumnFingerprint": "9"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 26,
+ "startColumn": 10,
+ "endColumn": 20
+ }
+ },
+ "message": {
+ "text": "TestInner2"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 36,
+ "startColumn": 14,
+ "endColumn": 24
+ }
+ },
+ "message": {
+ "text": "TestInner4"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[DpcForIsrRoutine](1): IRQL potentially too high at call to [IoGetInitialStack](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 379,
+ "startColumn": 5,
+ "endColumn": 22
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "48e9dbeaff18e9e7:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 360,
+ "endColumn": 17
+ }
+ },
+ "message": {
+ "text": "DpcForIsrRoutine"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 379,
+ "startColumn": 5,
+ "endColumn": 22
+ }
+ },
+ "message": {
+ "text": "IoGetInitialStack"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-high",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-high",
+ "index": 0
+ },
+ "message": {
+ "text": "[CompletionRoutine](1): IRQL potentially too high at call to [KeSetEvent](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 337,
+ "startColumn": 5,
+ "endColumn": 15
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "779dfb1bf8eb10c3:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 316,
+ "endColumn": 18
+ }
+ },
+ "message": {
+ "text": "CompletionRoutine"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ },
+ "region": {
+ "startLine": 337,
+ "startColumn": 5,
+ "endColumn": 15
+ }
+ },
+ "message": {
+ "text": "KeSetEvent"
+ }
+ }
+ ]
+ }
+ ],
+ "columnKind": "utf16CodeUnits",
+ "properties": {
+ "semmle.formatSpecifier": "sarifv2.1.0"
}
+ }
]
-}
\ No newline at end of file
+}
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
index d5b95a21..99e2f346 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
@@ -7,7 +7,7 @@
"driver": {
"name": "CodeQL",
"organization": "GitHub",
- "semanticVersion": "2.15.4",
+ "semanticVersion": "2.24.2",
"notifications": [
{
"id": "cpp/baseline/expected-extracted-files",
@@ -27,6 +27,45 @@
"telemetry"
]
}
+ },
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cli/platform",
+ "name": "cli/platform",
+ "shortDescription": {
+ "text": "Platform"
+ },
+ "fullDescription": {
+ "text": "Platform"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cpp/extractor/summary",
+ "name": "cpp/extractor/summary",
+ "shortDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "fullDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
}
],
"rules": [
@@ -43,9 +82,14 @@
"enabled": true,
"level": "warning"
},
+ "help": {
+ "text": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n",
+ "markdown": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"
+ },
"properties": {
"tags": [
"correctness",
+ "ca_ported",
"wddst"
],
"description": "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.",
@@ -59,7 +103,7 @@
"platform": "Desktop",
"precision": "medium",
"problem.severity": "warning",
- "query-version": "v2",
+ "query-version": "v6",
"repro.text": "The following function call is taking place at an IRQL too low for what the call target is annotated as.",
"scope": "domainspecific",
"security.severity": "Low"
@@ -70,18 +114,56 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.1.0+2affc3c634804dac7504a483a378cc9ba22a0f0b",
+ "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
"locations": [
{
- "uri": "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
"description": {
"text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
}
},
{
- "uri": "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
"description": {
"text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "codeql/cpp-all",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
+ "locations": [
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
}
}
]
@@ -96,9 +178,9 @@
{
"physicalLocation": {
"artifactLocation": {
- "uri": "driver/fail_driver1.c",
+ "uri": "driver/driver_snippet.c",
"uriBaseId": "%SRCROOT%",
- "index": 1
+ "index": 0
}
}
}
@@ -122,9 +204,9 @@
{
"physicalLocation": {
"artifactLocation": {
- "uri": "driver/driver_snippet.c",
+ "uri": "driver/fail_driver1.h",
"uriBaseId": "%SRCROOT%",
- "index": 0
+ "index": 1
}
}
}
@@ -148,7 +230,7 @@
{
"physicalLocation": {
"artifactLocation": {
- "uri": "driver/fail_driver1.h",
+ "uri": "driver/fail_driver1.c",
"uriBaseId": "%SRCROOT%",
"index": 2
}
@@ -168,6 +250,79 @@
"text": ""
}
}
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-28T23:23:11.908037200Z",
+ "descriptor": {
+ "id": "cli/file-coverage-baseline",
+ "index": 1
+ },
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 308
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-28T23:23:11.915033800Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
+ "properties": {
+ "attributes": {
+ "arch": "amd64",
+ "name": "Windows 11",
+ "version": "10.0"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
+ "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
+ },
+ "level": "note",
+ "timeUtc": "2026-04-28T23:23:50.604873300Z",
+ "descriptor": {
+ "id": "cpp/extractor/summary",
+ "index": 3
+ },
+ "properties": {
+ "attributes": {
+ "cache-hits": 0,
+ "cache-misses": 1,
+ "compilers": [
+ {
+ "program": "cl",
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
+ }
+ ],
+ "extractor-failures": 1,
+ "extractor-successes": 0,
+ "trap-caching": "disabled"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
}
],
"executionSuccessful": true
@@ -183,20 +338,296 @@
},
{
"location": {
- "uri": "driver/fail_driver1.c",
+ "uri": "driver/fail_driver1.h",
"uriBaseId": "%SRCROOT%",
"index": 1
}
},
{
"location": {
- "uri": "driver/fail_driver1.h",
+ "uri": "driver/fail_driver1.c",
"uriBaseId": "%SRCROOT%",
"index": 2
}
}
],
"results": [
+ {
+ "ruleId": "cpp/drivers/irql-too-low",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-low",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooLow_globalReassigned](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 113,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "4e9bf712603567a:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 111,
+ "startColumn": 6,
+ "endColumn": 40
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooLow_globalReassigned"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 113,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "DispatchOnly_TooLow"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-low",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-low",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooLow_byReference](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 106,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "30d5b4e4b89956a4:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 102,
+ "startColumn": 6,
+ "endColumn": 35
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooLow_byReference"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 106,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "DispatchOnly_TooLow"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-low",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-low",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooLow_increment](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 97,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "dd920dbcc12ad933:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 93,
+ "startColumn": 6,
+ "endColumn": 33
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooLow_increment"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 97,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "DispatchOnly_TooLow"
+ }
+ }
+ ]
+ },
+ {
+ "ruleId": "cpp/drivers/irql-too-low",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-too-low",
+ "index": 0
+ },
+ "message": {
+ "text": "[failForIrqlTooLow_compoundAssignment](1): IRQL potentially too low at call to [DispatchOnly_TooLow](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 88,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "d830060d8a1428a7:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 84,
+ "startColumn": 6,
+ "endColumn": 42
+ }
+ },
+ "message": {
+ "text": "failForIrqlTooLow_compoundAssignment"
+ }
+ },
+ {
+ "id": 2,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 88,
+ "startColumn": 9,
+ "endColumn": 28
+ }
+ },
+ "message": {
+ "text": "DispatchOnly_TooLow"
+ }
+ }
+ ]
+ },
{
"ruleId": "cpp/drivers/irql-too-low",
"ruleIndex": 0,
@@ -342,4 +773,4 @@
}
}
]
-}
\ No newline at end of file
+}
From 4cacaf0d92da0d47dab3a6bd6640729cf07eec99 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 28 Apr 2026 22:10:23 -0700
Subject: [PATCH 12/19] Tidy up: indentation, ASCII-only comments, dedupe IFSM
where, refresh SARIF baselines
Style and consistency cleanups uncovered during the final code review,
plus baseline regeneration so all checked-in SARIF baselines have
consistent (2-space) pretty-printing and reflect the current CodeQL
build's output:
* Irql.qll
- whenConditionIsFalseAtCallSite: realign the new "!= NULL" and
"(arg & 0x1) 0" or-branches to match the indentation of the
pre-existing "Param != 0" / "Param == N" branches (one extra
leading space each before this change).
- isInConstantFalseBranch: indent the predicate body to match the
surrounding 1-space-leading column convention used throughout the
file.
* Page.qll: replace "MacroInvocation x MacroInvocation" en-quad with
ASCII "x" so the file is pure ASCII (matching the rest of the
codebase).
* IrqlSetTooHigh.ql: replace em-dash with "--" in the same-line
rationale comment for the lower-on-exit exemption.
* IrqlNotSaved.ql:
- Replace em-dash in the "Only track flow to assignment targets or
parameters" comment with a comma.
- Rewrite the "exists(sink.asParameter())" idiom as
"sink.asParameter() instanceof Parameter" for readability;
behaviour is unchanged.
* IrqlFloatStateMismatch.ql:
- Drop the now-redundant getName().matches("KeSave...") /
getName().matches("KeRestore...") constraints from the where
clause: the FloatStateFlow source/sink predicates already enforce
them, so saveCall and restoreCall are uniquely bound by their
arg(0) equalities. Adds a short explanatory comment.
- Refresh the comment on the irqlChangesBetween conjunct so it no
longer says "in the same function": the predicate now also
handles one-level wrapper / common-caller patterns.
* Adversarial driver_snippet.c comments (IrqlTooHigh, IrqlTooLow,
IrqlFloatStateMismatch): the original test headers described the
pre-fix predicate behaviour ("under the current predicate they are
not [flagged]" / "known false negative of the current
intraprocedural filter"). Those statements no longer reflect
reality: each adversarial case is now flagged by the corresponding
query. Rewrote the headers to describe what the test now exercises
(regression guards against the former FN classes).
* SARIF baselines: regenerated all six against the current CodeQL
build using the in-tree test runner, then pretty-printed with
2-space indent (matching the convention used by the majority of
checked-in baselines under src/drivers/). MPC's baseline previously
used a Jackson-style "key" : value formatting from the older
CodeQL 2.11.5; the regenerated file uses the modern "key": value
style consistent with the rest of the repo.
Validation: in-tree test runner reports +0/-0 for IrqlTooHigh,
IrqlTooLow, IrqlFloatStateMismatch, MultiplePagedCode, IrqlNotSaved,
and IrqlSetTooHigh. No query semantics changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.ql | 19 +-
.../IrqlFloatStateMismatch.sarif | 16 +-
.../IrqlFloatStateMismatch/driver_snippet.c | 15 +-
.../queries/IrqlNotSaved/IrqlNotSaved.ql | 4 +-
.../queries/IrqlNotSaved/IrqlNotSaved.sarif | 600 ++++++++++++------
.../queries/IrqlSetTooHigh/IrqlSetTooHigh.ql | 2 +-
.../IrqlSetTooHigh/IrqlSetTooHigh.sarif | 68 +-
.../queries/IrqlTooHigh/IrqlTooHigh.sarif | 14 +-
.../queries/IrqlTooHigh/driver_snippet.c | 24 +-
.../queries/IrqlTooLow/IrqlTooLow.sarif | 38 +-
.../queries/IrqlTooLow/driver_snippet.c | 13 +-
src/drivers/libraries/Irql.qll | 154 ++---
src/drivers/libraries/Page.qll | 2 +-
.../MultiplePagedCode/MultiplePagedCode.sarif | 507 +++++++++++----
14 files changed, 994 insertions(+), 482 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 580d07ba..d22c9ff6 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -142,18 +142,23 @@ from
FunctionCall saveCall, FunctionCall restoreCall
where
FloatStateFlow::flow(source, sink) and
- saveCall.getTarget().getName().matches("KeSaveFloatingPointState") and
+ // FloatStateFlow's source/sink predicates already restrict the flow's
+ // endpoints to be the first arguments of KeSaveFloatingPointState /
+ // KeRestoreFloatingPointState. The two arg(0) equalities below
+ // uniquely bind `saveCall` and `restoreCall` (each Expr has exactly
+ // one parent FunctionCall), without re-stating the function-name
+ // constraints.
source.asIndirectExpr() = saveCall.getArgument(0) and
- restoreCall.getTarget().getName().matches("KeRestoreFloatingPointState") and
sink.asIndirectExpr() = restoreCall.getArgument(0) and
irqlSource = getPotentialExitIrqlAtCfn(source.asIndirectExpr()) and
irqlSink = getPotentialExitIrqlAtCfn(sink.asIndirectExpr()) and
irqlSink != irqlSource and
- // Only flag if there is an actual IRQL-changing call in the same function
- // between save and restore (in source order). If no IRQL-changing call
- // exists between them, the IRQL is invariant within a single invocation
- // and the mismatch is a may-analysis artifact from different hypothetical
- // entry IRQLs.
+ // Only flag if there is an actual IRQL-changing call between the save
+ // and the restore (in source order), in either the directly enclosing
+ // function or a one-level wrapper / common-caller. If no IRQL-changing
+ // call exists between them, the IRQL is invariant within a single
+ // invocation and the mismatch is a may-analysis artifact from
+ // different hypothetical entry IRQLs.
irqlChangesBetween(saveCall, restoreCall)
select sink.asIndirectExpr(),
"The irql level where the floating-point state was saved (" + irqlSource +
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index b393f76d..b85849e4 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -83,8 +83,8 @@
"level": "warning"
},
"help": {
- "text": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n",
- "markdown": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Known false negatives.** The query suppresses save / restore pairs when no IRQL-changing call sits between the save call and the restore call on a source line that lies textually within the enclosing function. This suppression eliminates a class of may-analysis false positives where the save and the restore are at the same IRQL within a single dynamic invocation but the IRQL inference reports different hypothetical entry IRQLs. The check has the following limitations:\n\n* **Cross-function save / restore.** When the save and the restore are routed through helper functions that wrap `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`, and the IRQL change happens in the caller, no in-function intermediate call is found and the mismatch is silently suppressed.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\nIf a real mismatch is being suppressed, eliminate the wrapper or add explicit `_IRQL_raises_` / `_IRQL_saves_global_` annotations to the helper so its IRQL behavior is visible without body inspection.\n\n"
+ "text": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** The position-based filter still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n",
+ "markdown": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** The position-based filter still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n"
},
"properties": {
"tags": [
@@ -112,7 +112,7 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
"locations": [
{
"uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
@@ -254,14 +254,14 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:26:00.575823400Z",
+ "timeUtc": "2026-04-29T04:38:29.808991Z",
"descriptor": {
"id": "cli/file-coverage-baseline",
"index": 1
},
"properties": {
"attributes": {
- "durationMilliseconds": 288
+ "durationMilliseconds": 253
},
"visibility": {
"statusPage": false,
@@ -274,7 +274,7 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:26:00.581682100Z",
+ "timeUtc": "2026-04-29T04:38:29.815492900Z",
"descriptor": {
"id": "cli/platform",
"index": 2
@@ -297,7 +297,7 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-04-28T23:26:39.590845200Z",
+ "timeUtc": "2026-04-29T04:39:07.709847200Z",
"descriptor": {
"id": "cpp/extractor/summary",
"index": 3
@@ -369,7 +369,7 @@
"index": 0
},
"region": {
- "startLine": 112,
+ "startLine": 111,
"startColumn": 33,
"endColumn": 36
}
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
index e660ed04..df0c6a26 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
@@ -92,14 +92,13 @@ void driver_utility_nested_block_good(void)
// =====================================================================
// Adversarial: cross-function save / restore via thin wrappers.
//
-// `irqlChangesBetween` requires `saveCall` and `restoreCall` to
-// share an enclosing function, so when the save and the restore
-// are routed through helper wrappers and the IRQL change happens
-// in the caller, the source-position filter never finds a `mid`
-// candidate. No finding is produced even though the IRQL at the
-// save (PASSIVE_LEVEL) differs from the IRQL at the restore
-// (DISPATCH_LEVEL). This is a known false negative of the
-// current intraprocedural filter.
+// `irqlChangesBetween` projects each call to an anchor line in either
+// the directly enclosing function or a one-level wrapper / common
+// caller, so when the save and the restore are routed through helper
+// wrappers and the IRQL change happens in the caller, the caller's
+// anchor lines bracket the `KeRaiseIrql` call and the mismatch is
+// flagged. The IRQL at the save (PASSIVE_LEVEL) differs from the IRQL
+// at the restore (DISPATCH_LEVEL) for this case.
// =====================================================================
static void save_fp_helper(PKFLOATING_SAVE pfs)
diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
index 9e08862e..160313dd 100644
--- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
+++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql
@@ -83,10 +83,10 @@ module IrqlSaveParameterFlowConfigurationConfig implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) {
- // Only track flow to assignment targets or parameters — not every node
+ // Only track flow to assignment targets or parameters, not every node.
exists(Variable v | v.getAnAssignedValue() = sink.asExpr())
or
- exists(sink.asParameter())
+ sink.asParameter() instanceof Parameter
}
}
module IrqlSaveParameterFlowConfiguration = DataFlow::Global;
diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif
index ebd33304..1dd6ed36 100644
--- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif
+++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif
@@ -1,219 +1,413 @@
{
- "$schema" : "https://json.schemastore.org/sarif-2.1.0.json",
- "version" : "2.1.0",
- "runs" : [ {
- "tool" : {
- "driver" : {
- "name" : "CodeQL",
- "organization" : "GitHub",
- "semanticVersion" : "2.14.4",
- "notifications" : [ {
- "id" : "cpp/baseline/expected-extracted-files",
- "name" : "cpp/baseline/expected-extracted-files",
- "shortDescription" : {
- "text" : "Expected extracted files"
- },
- "fullDescription" : {
- "text" : "Files appearing in the source archive that are expected to be extracted."
- },
- "defaultConfiguration" : {
- "enabled" : true
- },
- "properties" : {
- "tags" : [ "expected-extracted-files", "telemetry" ]
- }
- } ],
- "rules" : [ {
- "id" : "cpp/drivers/irql-not-saved",
- "name" : "cpp/drivers/irql-not-saved",
- "shortDescription" : {
- "text" : "IRQL not saved (C28158)"
- },
- "fullDescription" : {
- "text" : "A variable annotated \\_IRQL\\_saves\\_ must have the IRQL saved into it."
- },
- "defaultConfiguration" : {
- "enabled" : true,
- "level" : "warning"
+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [
+ {
+ "tool": {
+ "driver": {
+ "name": "CodeQL",
+ "organization": "GitHub",
+ "semanticVersion": "2.24.2",
+ "notifications": [
+ {
+ "id": "cpp/baseline/expected-extracted-files",
+ "name": "cpp/baseline/expected-extracted-files",
+ "shortDescription": {
+ "text": "Expected extracted files"
+ },
+ "fullDescription": {
+ "text": "Files appearing in the source archive that are expected to be extracted."
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ },
+ "properties": {
+ "tags": [
+ "expected-extracted-files",
+ "telemetry"
+ ]
+ }
+ },
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cli/platform",
+ "name": "cli/platform",
+ "shortDescription": {
+ "text": "Platform"
+ },
+ "fullDescription": {
+ "text": "Platform"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cpp/extractor/summary",
+ "name": "cpp/extractor/summary",
+ "shortDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "fullDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ }
+ ],
+ "rules": [
+ {
+ "id": "cpp/drivers/irql-not-saved",
+ "name": "cpp/drivers/irql-not-saved",
+ "shortDescription": {
+ "text": "IRQL not saved (C28158)"
+ },
+ "fullDescription": {
+ "text": "A variable annotated \\_IRQL\\_saves\\_ must have the IRQL saved into it."
+ },
+ "defaultConfiguration": {
+ "enabled": true,
+ "level": "warning"
+ },
+ "help": {
+ "text": "# IRQL not saved (C28158)\r\nA parameter annotated _IRQL_saves_ must have the IRQL value saved to it.\r\n\r\n\r\n## Recommendation\r\nMake sure that any parameter annotated \"_IRQL_saves_\" has a code path where the current system IRQL is saved to it.\r\n\r\n\r\n## Example\r\nIn this example, the driver does not save the IRQL to a parameter annotated to have the IRQL saved to it:\r\n\r\n```c\r\n \r\n\t\tVOID IrqlNotSaved_fail(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) {\r\n\t\t\tKIRQL localIrql;\r\n\t\t\tKeAcquireSpinLock(myLock, &localIrql);\r\n\t\t}\r\n\t\t\r\n```\r\nThe driver should make sure to save the IRQL in the annotated parameter.\r\n\r\n```c\r\n\r\n\t\tVOID IrqlNotSaved_pass(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) {\r\n\t\t\tKeAcquireSpinLock(myLock, &outIrqlPass);\r\n\t\t}\r\n\t\t\r\n```\r\n\r\n## Semmle-specific notes\r\nThis version of the query only checks for functions that have no path where the IRQL is saved at all. In a future update, we will use the must-flow library to check for functions where there are _any_ paths where the IRQL is not saved.\r\n\r\nFalse positives may occur if UNREFERENCED_PARAMETER() is used on an annotated parameter.\r\n\r\n\r\n## References\r\n* [ C28158 warning - Windows Drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28158-no-irql-was-saved)\r\n",
+ "markdown": "# IRQL not saved (C28158)\r\nA parameter annotated _IRQL_saves_ must have the IRQL value saved to it.\r\n\r\n\r\n## Recommendation\r\nMake sure that any parameter annotated \"_IRQL_saves_\" has a code path where the current system IRQL is saved to it.\r\n\r\n\r\n## Example\r\nIn this example, the driver does not save the IRQL to a parameter annotated to have the IRQL saved to it:\r\n\r\n```c\r\n \r\n\t\tVOID IrqlNotSaved_fail(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) {\r\n\t\t\tKIRQL localIrql;\r\n\t\t\tKeAcquireSpinLock(myLock, &localIrql);\r\n\t\t}\r\n\t\t\r\n```\r\nThe driver should make sure to save the IRQL in the annotated parameter.\r\n\r\n```c\r\n\r\n\t\tVOID IrqlNotSaved_pass(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) {\r\n\t\t\tKeAcquireSpinLock(myLock, &outIrqlPass);\r\n\t\t}\r\n\t\t\r\n```\r\n\r\n## Semmle-specific notes\r\nThis version of the query only checks for functions that have no path where the IRQL is saved at all. In a future update, we will use the must-flow library to check for functions where there are _any_ paths where the IRQL is not saved.\r\n\r\nFalse positives may occur if UNREFERENCED_PARAMETER() is used on an annotated parameter.\r\n\r\n\r\n## References\r\n* [ C28158 warning - Windows Drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28158-no-irql-was-saved)\r\n"
+ },
+ "properties": {
+ "tags": [
+ "correctness",
+ "ca_ported",
+ "wddst"
+ ],
+ "description": "A variable annotated \\_IRQL\\_saves\\_ must have the IRQL saved into it.",
+ "feature.area": "Multiple",
+ "id": "cpp/drivers/irql-not-saved",
+ "impact": "Insecure Coding Practice",
+ "kind": "problem",
+ "name": "IRQL not saved (C28158)",
+ "opaqueid": "CQLD-C28158",
+ "owner.email": "sdat@microsoft.com",
+ "platform": "Desktop",
+ "precision": "medium",
+ "problem.severity": "warning",
+ "query-version": "v2",
+ "repro.text": "This function has a parameter annotated \\_IRQL\\_saves\\_, but does not have the system IRQL saved to it.",
+ "scope": "domainspecific",
+ "security.severity": "Low"
+ }
+ }
+ ]
+ },
+ "extensions": [
+ {
+ "name": "microsoft/windows-drivers",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
+ "locations": [
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
},
- "properties" : {
- "tags" : [ "correctness", "wddst" ],
- "description" : "A variable annotated \\_IRQL\\_saves\\_ must have the IRQL saved into it.",
- "feature.area" : "Multiple",
- "id" : "cpp/drivers/irql-not-saved",
- "impact" : "Insecure Coding Practice",
- "kind" : "problem",
- "name" : "IRQL not saved (C28158)",
- "opaqueid" : "CQLD-C28158",
- "owner.email" : "sdat@microsoft.com",
- "platform" : "Desktop",
- "precision" : "medium",
- "problem.severity" : "warning",
- "query-version" : "v1",
- "repro.text" : "This function has a parameter annotated \\_IRQL\\_saves\\_, but does not have the system IRQL saved to it.",
- "scope" : "domainspecific",
- "security.severity" : "Low"
+ {
+ "name": "codeql/cpp-all",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
+ "locations": [
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
}
- } ]
+ ]
},
- "extensions" : [ {
- "name" : "microsoft/windows-drivers",
- "semanticVersion" : "0.2.0+be14ce4fcaa9006e7636d8605fc53ea7c422a561",
- "locations" : [ {
- "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/",
- "description" : {
- "text" : "The QL pack root directory."
- }
- }, {
- "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
- "description" : {
- "text" : "The QL pack definition file."
- }
- } ]
- } ]
- },
- "invocations" : [ {
- "toolExecutionNotifications" : [ {
- "locations" : [ {
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/fail_driver1.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 1
+ "invocations": [
+ {
+ "toolExecutionNotifications": [
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-29T04:44:06.842402600Z",
+ "descriptor": {
+ "id": "cli/file-coverage-baseline",
+ "index": 1
+ },
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 268
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-29T04:44:06.848399600Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
+ "properties": {
+ "attributes": {
+ "arch": "amd64",
+ "name": "Windows 11",
+ "version": "10.0"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
+ "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
+ },
+ "level": "note",
+ "timeUtc": "2026-04-29T04:44:50.137416100Z",
+ "descriptor": {
+ "id": "cpp/extractor/summary",
+ "index": 3
+ },
+ "properties": {
+ "attributes": {
+ "cache-hits": 0,
+ "cache-misses": 1,
+ "compilers": [
+ {
+ "program": "cl",
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
+ }
+ ],
+ "extractor-failures": 1,
+ "extractor-successes": 0,
+ "trap-caching": "disabled"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
}
- }
- } ],
- "message" : {
- "text" : ""
- },
- "level" : "none",
- "descriptor" : {
- "id" : "cpp/baseline/expected-extracted-files",
- "index" : 0
- },
- "properties" : {
- "formattedMessage" : {
- "text" : ""
- }
+ ],
+ "executionSuccessful": true
}
- }, {
- "locations" : [ {
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
- }
+ ],
+ "artifacts": [
+ {
+ "location": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
}
- } ],
- "message" : {
- "text" : ""
},
- "level" : "none",
- "descriptor" : {
- "id" : "cpp/baseline/expected-extracted-files",
- "index" : 0
- },
- "properties" : {
- "formattedMessage" : {
- "text" : ""
+ {
+ "location": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
}
- }
- }, {
- "locations" : [ {
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/fail_driver1.h",
- "uriBaseId" : "%SRCROOT%",
- "index" : 2
- }
- }
- } ],
- "message" : {
- "text" : ""
- },
- "level" : "none",
- "descriptor" : {
- "id" : "cpp/baseline/expected-extracted-files",
- "index" : 0
},
- "properties" : {
- "formattedMessage" : {
- "text" : ""
+ {
+ "location": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
}
}
- } ],
- "executionSuccessful" : true
- } ],
- "artifacts" : [ {
- "location" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
- }
- }, {
- "location" : {
- "uri" : "driver/fail_driver1.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 1
- }
- }, {
- "location" : {
- "uri" : "driver/fail_driver1.h",
- "uriBaseId" : "%SRCROOT%",
- "index" : 2
- }
- } ],
- "results" : [ {
- "ruleId" : "cpp/drivers/irql-not-saved",
- "ruleIndex" : 0,
- "rule" : {
- "id" : "cpp/drivers/irql-not-saved",
- "index" : 0
- },
- "message" : {
- "text" : "The parameter [outIrqlFail](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it."
- },
- "locations" : [ {
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
+ ],
+ "results": [
+ {
+ "ruleId": "cpp/drivers/irql-not-saved",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-not-saved",
+ "index": 0
},
- "region" : {
- "startLine" : 51,
- "startColumn" : 44,
- "endColumn" : 55
- }
- }
- } ],
- "partialFingerprints" : {
- "primaryLocationLineHash" : "e054bbd9d7acc717:1",
- "primaryLocationStartColumnFingerprint" : "43"
- },
- "relatedLocations" : [ {
- "id" : 1,
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
+ "message": {
+ "text": "The parameter [outIrqlFail](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it."
},
- "region" : {
- "startLine" : 51,
- "startColumn" : 44,
- "endColumn" : 55
- }
- },
- "message" : {
- "text" : "outIrqlFail"
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 51,
+ "startColumn": 44,
+ "endColumn": 55
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "e054bbd9d7acc717:1",
+ "primaryLocationStartColumnFingerprint": "43"
+ },
+ "relatedLocations": [
+ {
+ "id": 1,
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 51,
+ "startColumn": 44,
+ "endColumn": 55
+ }
+ },
+ "message": {
+ "text": "outIrqlFail"
+ }
+ }
+ ]
}
- } ]
- } ],
- "columnKind" : "utf16CodeUnits",
- "properties" : {
- "semmle.formatSpecifier" : "sarifv2.1.0"
+ ],
+ "columnKind": "utf16CodeUnits",
+ "properties": {
+ "semmle.formatSpecifier": "sarifv2.1.0"
+ }
}
- } ]
-}
\ No newline at end of file
+ ]
+}
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
index 4b8bce83..0d5134b0 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.ql
@@ -39,7 +39,7 @@ where
irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement
or
// If we don't have an explicit max annotation but do raise the IRQL,
- // we treat the raised-to level as the implicit max —
+ // we treat the raised-to level as the implicit max --
// UNLESS the function has a _requires_min_ above the raises-to level,
// which indicates a "lower IRQL on exit" pattern (e.g. mutex release),
// not a ceiling.
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.sarif b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.sarif
index c806a95a..83b7330a 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.sarif
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.sarif
@@ -7,7 +7,7 @@
"driver": {
"name": "CodeQL",
"organization": "GitHub",
- "semanticVersion": "2.23.3",
+ "semanticVersion": "2.24.2",
"notifications": [
{
"id": "cpp/baseline/expected-extracted-files",
@@ -28,6 +28,19 @@
]
}
},
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
{
"id": "cli/platform",
"name": "cli/platform",
@@ -69,6 +82,10 @@
"enabled": true,
"level": "warning"
},
+ "help": {
+ "text": "# IRQL set too high (C28150)\nThe function has raised the IRQL to a level above what is allowed.\n\n\n## Recommendation\nA function has been annotated as having a max IRQL, but the execution of that function raises the IRQL above that maximum. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver tries to raise the IRQL to HIGH_LEVEL while in a dispatch routine. This should be avoided.\n\n```c\n\n\t\t\t// Within a dispatch routine\n\t\t\tKeRaiseIrql(HIGH_LEVEL, &oldIRQL);\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28150 warning - Windows Drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28150-function-causes-irq-level-to-be-set-above-max)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Lower-on-exit pattern: known false negative.** When a function has no `_IRQL_always_function_max_` but does carry an `_IRQL_raises_(R)` annotation, the query treats `R` as the implicit ceiling for the function body. A function annotated as both `_IRQL_requires_min_(M)` and `_IRQL_raises_(R)` with `M > R` is interpreted as a \"lower IRQL on exit\" pattern (for example a wrapper around a mutex or spin-lock release that runs at `DISPATCH_LEVEL` on entry and returns at `PASSIVE_LEVEL`). For these functions the implicit ceiling is suppressed entirely, because `R` describes the exit IRQL rather than a maximum.\n\nThis means that a buggy \"lower-on-exit\" function whose body raises the IRQL above `M` at some intermediate point will *not* be flagged. If the function actually has a maximum that should be enforced along the body, declare it explicitly with `_IRQL_always_function_max_(MAX)` so the query has a concrete ceiling to check against.\n\n",
+ "markdown": "# IRQL set too high (C28150)\nThe function has raised the IRQL to a level above what is allowed.\n\n\n## Recommendation\nA function has been annotated as having a max IRQL, but the execution of that function raises the IRQL above that maximum. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver tries to raise the IRQL to HIGH_LEVEL while in a dispatch routine. This should be avoided.\n\n```c\n\n\t\t\t// Within a dispatch routine\n\t\t\tKeRaiseIrql(HIGH_LEVEL, &oldIRQL);\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28150 warning - Windows Drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28150-function-causes-irq-level-to-be-set-above-max)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Lower-on-exit pattern: known false negative.** When a function has no `_IRQL_always_function_max_` but does carry an `_IRQL_raises_(R)` annotation, the query treats `R` as the implicit ceiling for the function body. A function annotated as both `_IRQL_requires_min_(M)` and `_IRQL_raises_(R)` with `M > R` is interpreted as a \"lower IRQL on exit\" pattern (for example a wrapper around a mutex or spin-lock release that runs at `DISPATCH_LEVEL` on entry and returns at `PASSIVE_LEVEL`). For these functions the implicit ceiling is suppressed entirely, because `R` describes the exit IRQL rather than a maximum.\n\nThis means that a buggy \"lower-on-exit\" function whose body raises the IRQL above `M` at some intermediate point will *not* be flagged. If the function actually has a maximum that should be enforced along the body, declare it explicitly with `_IRQL_always_function_max_(MAX)` so the query has a concrete ceiling to check against.\n\n"
+ },
"properties": {
"tags": [
"correctness",
@@ -86,7 +103,7 @@
"platform": "Desktop",
"precision": "medium",
"problem.severity": "warning",
- "query-version": "v1",
+ "query-version": "v2",
"repro.text": "The following statement exits at an IRQL too high for the function it is contained in.",
"scope": "domainspecific",
"security.severity": "Low"
@@ -97,10 +114,10 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.8.1+801b2d9a470acb3a6f2beddebaff099855c9ac8e",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
"locations": [
{
- "uri": "file:///D:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
"description": {
"text": "The QL pack root directory."
},
@@ -111,7 +128,7 @@
}
},
{
- "uri": "file:///D:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
"description": {
"text": "The QL pack definition file."
},
@@ -125,10 +142,10 @@
},
{
"name": "codeql/cpp-all",
- "semanticVersion": "4.2.0+2409bcc0d62644acbc432900bc59c2e3ff33bd56",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
"locations": [
{
- "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/4.2.0/",
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
"description": {
"text": "The QL pack root directory."
},
@@ -139,7 +156,7 @@
}
},
{
- "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/4.2.0/qlpack.yml",
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
"description": {
"text": "The QL pack definition file."
},
@@ -236,15 +253,34 @@
},
{
"message": {
- "text": "On the Windows 11 (amd64; 10.0) platform.",
- "markdown": "On the Windows 11 (amd64; 10.0) platform."
+ "text": ""
},
"level": "none",
- "timeUtc": "2026-01-23T07:54:15.471875500Z",
+ "timeUtc": "2026-04-29T04:47:08.489157300Z",
"descriptor": {
- "id": "cli/platform",
+ "id": "cli/file-coverage-baseline",
"index": 1
},
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 312
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-29T04:47:08.494163300Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
"properties": {
"attributes": {
"arch": "amd64",
@@ -263,10 +299,10 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-01-23T15:54:25.920679Z",
+ "timeUtc": "2026-04-29T04:47:58.301890800Z",
"descriptor": {
"id": "cpp/extractor/summary",
- "index": 2
+ "index": 3
},
"properties": {
"attributes": {
@@ -275,7 +311,7 @@
"compilers": [
{
"program": "cl",
- "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35222 for x64"
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
}
],
"extractor-failures": 1,
@@ -599,4 +635,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
index a1a5d724..6f5b52c9 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.sarif
@@ -83,8 +83,8 @@
"level": "warning"
},
"help": {
- "text": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n",
- "markdown": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"
+ "text": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).\n\n",
+ "markdown": "# IRQL too high (C28121)\nThe function is not permitted to be called at the current IRQ level. The current level is too high.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is at too high of an IRQL to acquire a spinlock:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(HIGH_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful not to raise the IRQL too high:\n\n```c\n\n\t\t\tNTSTATUS \n\t\t\tIrqlTooHigh(PKSPIN_LOCK myLock, PKIRQL oldIrql){\n\t\t\t\tNTSTATUS status;\n\t\t\t\tKIRQL lockIrql;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, oldIrql);\n\t\t\t\tKeAcquireSpinLock(myLock, &lockIrql);\n\t\t\t\tKeReleaseSpinLock(myLock, &lockIrql);\n\t\t\t\tKeLowerIrql(*oldIrql);\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28121 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28121-irq-execution-too-high)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).\n\n"
},
"properties": {
"tags": [
@@ -114,7 +114,7 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
"locations": [
{
"uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
@@ -256,14 +256,14 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:20:15.559452300Z",
+ "timeUtc": "2026-04-29T04:31:57.790909200Z",
"descriptor": {
"id": "cli/file-coverage-baseline",
"index": 1
},
"properties": {
"attributes": {
- "durationMilliseconds": 289
+ "durationMilliseconds": 317
},
"visibility": {
"statusPage": false,
@@ -276,7 +276,7 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:20:15.563108200Z",
+ "timeUtc": "2026-04-29T04:31:57.796908700Z",
"descriptor": {
"id": "cli/platform",
"index": 2
@@ -299,7 +299,7 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-04-28T23:20:55.172937400Z",
+ "timeUtc": "2026-04-29T04:32:37.806676200Z",
"descriptor": {
"id": "cpp/extractor/summary",
"index": 3
diff --git a/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c b/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
index a83e1d9a..30976e53 100644
--- a/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlTooHigh/driver_snippet.c
@@ -78,16 +78,16 @@ passForIrqlTooHigh(PKIRQL oldIrql){
// =====================================================================
// Adversarial cases for `isInConstantFalseBranch` (Irql.qll).
//
-// These cases probe a known limitation of the predicate that
-// suppresses calls inside `if (b)` for variables that look
-// "constantly FALSE": it only inspects plain `=` AssignExpr in
-// the same enclosing function. Compound assignments, increments,
-// pass-by-reference mutation, and globals reassigned in other
-// functions all bypass this check, causing the call to be
-// silently suppressed (a false negative).
+// These cases ensure the predicate that suppresses calls inside
+// `if (b)` for variables that look "constantly FALSE" does not
+// accidentally drop legitimate findings when `b` is in fact mutated
+// at runtime via:
+// - a compound assignment (|=, &=, +=, ...);
+// - an increment / decrement (++, --);
+// - a pass-by-reference helper that takes its address;
+// - a separate function (when `b` is a file-scope global).
//
-// Each adversarial case below should, in principle, be flagged as
-// IRQL-too-high; under the current predicate they are not.
+// Each adversarial case below should be flagged as IRQL-too-high.
// =====================================================================
_IRQL_requires_(PASSIVE_LEVEL)
@@ -141,9 +141,9 @@ void failForIrqlTooHigh_byReference(PKIRQL oldIrql){
}
// Adversarial: file-scope global, reassigned only from other
-// functions. The constant-FALSE branch check looks for
-// AssignExprs only inside `failForIrqlTooHigh_globalReassigned`
-// and finds none.
+// functions. A naive intra-function-only mutation check would
+// fail to see the reassignment in the initialiser routine and
+// silently drop the finding.
void failForIrqlTooHigh_globalReassigned(PKIRQL oldIrql){
KeRaiseIrql(DISPATCH_LEVEL, oldIrql);
if (g_DispatchSafe_TooHigh) {
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
index 99e2f346..7ce307a5 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.sarif
@@ -83,8 +83,8 @@
"level": "warning"
},
"help": {
- "text": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n",
- "markdown": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Known false negatives.** The query suppresses calls inside an `if (b)` block when `b` is a variable initialized to `FALSE` / `0` with no plain `=` assignment to it visible in the same enclosing function. This suppression is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`, but it is too lax. The following mutations of `b` all bypass the check, so the call inside the branch may be silently dropped even when `b` is in fact true at runtime:\n\n* compound assignments such as `b |= 1`, `b &= mask`, `b += value` (the predicate looks only for `AssignExpr`, which represents plain `=` assignments; compound forms are `AssignOperation`);\n* increment / decrement (`b++`, `--b`) which is `CrementOperation`, not an assignment;\n* pass-by-reference helpers such as `SetFlag(&b)`, where the mutation is invisible to a syntactic scan of the enclosing function;\n* file-scope or global flags whose only mutation lives in a different function (such as a one-time initialization routine).\nIf you rely on a runtime flag to gate IRQL-sensitive code and the call is incorrectly suppressed, work around the limitation by replacing the gated call with a direct, annotated call site or by rewriting the condition so the predicate fails (for example, use `!= 0` against a value the predicate cannot constant-fold).\n\n"
+ "text": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).\n\n",
+ "markdown": "# IRQL too low (C28120)\nThe function is not permitted to be called at the current IRQ level. The current level is too low.\n\n\n## Recommendation\nThe driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.\n\n\n## Example\nIn this example, the driver is calling a DDI that must be called at DISPATCH_LEVEL or higher:\n\n```c\n\n\t\t\t// Within a standard thread running at APC_LEVEL:\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\nThe driver should be careful to only call from a DISPATCH_LEVEL context:\n\n```c\n\n\t\t\t// Within a work loop running at DISPATCH_LEVEL\n\t\t\tif (KeShouldYieldProcessor())\n\t\t\t{\n\t\t\t\tKeLowerIrql(PASSIVE_LEVEL);\n\t\t\t}\n\t\t\t\n\t\t\n```\n\n## References\n* [ C28120 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28120-irql-execution-too-low)\n* [ IRQL annotations for drivers ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/irql-annotations-for-drivers)\n\n## Semmle-specific notes\nThis query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.\n\nThis query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.\n\nFor information on how to annotate your functions with information about how they adjust the IRQL, see \"IRQL annotations for drivers\" in the references section.\n\n**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).\n\n"
},
"properties": {
"tags": [
@@ -114,7 +114,7 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.9.0+2515238ad8912d03a18aab75fcacace2a4f4d307",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
"locations": [
{
"uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
@@ -256,14 +256,14 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:23:11.908037200Z",
+ "timeUtc": "2026-04-29T04:35:27.144286700Z",
"descriptor": {
"id": "cli/file-coverage-baseline",
"index": 1
},
"properties": {
"attributes": {
- "durationMilliseconds": 308
+ "durationMilliseconds": 271
},
"visibility": {
"statusPage": false,
@@ -276,7 +276,7 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-28T23:23:11.915033800Z",
+ "timeUtc": "2026-04-29T04:35:27.147284600Z",
"descriptor": {
"id": "cli/platform",
"index": 2
@@ -299,7 +299,7 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-04-28T23:23:50.604873300Z",
+ "timeUtc": "2026-04-29T04:36:08.306667Z",
"descriptor": {
"id": "cpp/extractor/summary",
"index": 3
@@ -371,7 +371,7 @@
"index": 0
},
"region": {
- "startLine": 113,
+ "startLine": 112,
"startColumn": 9,
"endColumn": 28
}
@@ -392,7 +392,7 @@
"index": 0
},
"region": {
- "startLine": 111,
+ "startLine": 110,
"startColumn": 6,
"endColumn": 40
}
@@ -410,7 +410,7 @@
"index": 0
},
"region": {
- "startLine": 113,
+ "startLine": 112,
"startColumn": 9,
"endColumn": 28
}
@@ -440,7 +440,7 @@
"index": 0
},
"region": {
- "startLine": 106,
+ "startLine": 105,
"startColumn": 9,
"endColumn": 28
}
@@ -461,7 +461,7 @@
"index": 0
},
"region": {
- "startLine": 102,
+ "startLine": 101,
"startColumn": 6,
"endColumn": 35
}
@@ -479,7 +479,7 @@
"index": 0
},
"region": {
- "startLine": 106,
+ "startLine": 105,
"startColumn": 9,
"endColumn": 28
}
@@ -509,7 +509,7 @@
"index": 0
},
"region": {
- "startLine": 97,
+ "startLine": 96,
"startColumn": 9,
"endColumn": 28
}
@@ -530,7 +530,7 @@
"index": 0
},
"region": {
- "startLine": 93,
+ "startLine": 92,
"startColumn": 6,
"endColumn": 33
}
@@ -548,7 +548,7 @@
"index": 0
},
"region": {
- "startLine": 97,
+ "startLine": 96,
"startColumn": 9,
"endColumn": 28
}
@@ -578,7 +578,7 @@
"index": 0
},
"region": {
- "startLine": 88,
+ "startLine": 87,
"startColumn": 9,
"endColumn": 28
}
@@ -599,7 +599,7 @@
"index": 0
},
"region": {
- "startLine": 84,
+ "startLine": 83,
"startColumn": 6,
"endColumn": 42
}
@@ -617,7 +617,7 @@
"index": 0
},
"region": {
- "startLine": 88,
+ "startLine": 87,
"startColumn": 9,
"endColumn": 28
}
diff --git a/src/drivers/general/queries/IrqlTooLow/driver_snippet.c b/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
index 30628305..b133df8e 100644
--- a/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlTooLow/driver_snippet.c
@@ -56,13 +56,12 @@ IrqlHighTestFunction(){
// =====================================================================
// Adversarial cases for `isInConstantFalseBranch` (Irql.qll).
//
-// Symmetric to the IrqlTooHigh cases: the enclosing function is
-// at PASSIVE_LEVEL but the call inside `if (b)` requires
-// DISPATCH_LEVEL. The predicate suppresses these calls because
-// the variable looks constantly FALSE, even when in fact it has
-// been mutated through a compound assignment, an increment, a
-// pass-by-reference helper, or in a separate function (for a
-// global).
+// Symmetric to the IrqlTooHigh cases: the enclosing function is at
+// PASSIVE_LEVEL but the call inside `if (b)` requires DISPATCH_LEVEL.
+// Each case mutates `b` in a way that a naive constant-FALSE check
+// can miss (compound assignment, increment, pass-by-reference, or a
+// file-scope global reassigned in another function), so the predicate
+// must not blindly suppress the inner call.
// =====================================================================
_IRQL_requires_(DISPATCH_LEVEL)
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index 7ad9a7b9..3a5dfb43 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -236,24 +236,24 @@
// "Param == 0" is false when arg is nonzero
paramName = cond.regexpCapture("(\\w+)\\s*==\\s*0", 1) and
call.getArgument(paramIdx).getValue() != "0"
- or
- // "Param != NULL" is false when arg is 0/NULL
- paramName = cond.regexpCapture("(\\w+)\\s*!=\\s*NULL", 1) and
- call.getArgument(paramIdx).getValue() = "0"
- or
- // "((Param & 0x1)) 0" -- bitwise mask check.
- // False when bit 0 is clear and op is "!=", or bit 0 is set and op is "==".
- exists(string op, int argVal |
- paramName =
- cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 1) and
- op = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 2) and
- argVal = call.getArgument(paramIdx).getValue().toInt() and
- (
- op = "!=" and argVal.bitAnd(1) = 0
- or
- op = "==" and argVal.bitAnd(1) != 0
- )
- )
+ or
+ // "Param != NULL" is false when arg is 0/NULL
+ paramName = cond.regexpCapture("(\\w+)\\s*!=\\s*NULL", 1) and
+ call.getArgument(paramIdx).getValue() = "0"
+ or
+ // "((Param & 0x1)) 0" -- bitwise mask check.
+ // False when bit 0 is clear and op is "!=", or bit 0 is set and op is "==".
+ exists(string op, int argVal |
+ paramName =
+ cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 1) and
+ op = cond.regexpCapture(".*\\(\\s*(\\w+)\\s*&\\s*0x1\\s*\\).*(==|!=)\\s*0.*", 2) and
+ argVal = call.getArgument(paramIdx).getValue().toInt() and
+ (
+ op = "!=" and argVal.bitAnd(1) = 0
+ or
+ op = "==" and argVal.bitAnd(1) != 0
+ )
+ )
)
)
}
@@ -925,65 +925,65 @@
)
}
-/**
- * Holds if `call` is located inside the "then" branch of an `if` statement
- * whose condition is a compile-time-constant `FALSE` (0) value, or a
- * non-`static` local variable that is initialized to `0` / `FALSE`,
- * never assigned (with any assignment operator) or incremented /
- * decremented in the enclosing function, and whose address is never
- * taken.
- *
- * This detects patterns like:
- * ```
- * BOOLEAN bFalse = FALSE;
- * if (bFalse) { KeAcquireSpinLockAtDpcLevel(...); } // dead branch
- * ```
- * Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK, etc.).
- *
- * The conservative-by-default conditions on the variable case avoid
- * silently dropping legitimate findings when the runtime value of the
- * variable cannot be proven to remain `FALSE`:
- *
- * - `LocalVariable v` excludes file-scope and namespace globals,
- * which can be reassigned from any other function in the
- * translation unit (or even another TU).
- * - `not v.isStatic()` excludes function-static variables, whose
- * value persists across calls and could be set by a previous
- * invocation.
- * - The `Assignment` predicate matches plain `=` (`AssignExpr`) and
- * all compound operators (`AssignOperation`: `|=`, `&=`, `+=`,
- * etc.); the original `AssignExpr`-only check was too narrow.
- * - `CrementOperation` covers `++` and `--`, which are not modeled
- * as assignments in the cpp library.
- * - Bailing out when the variable's address is taken
- * (`AddressOfExpr`) prevents missing mutations performed by
- * callees through a pointer (e.g., `SetFlag(&bFalse)`).
- */
-predicate isInConstantFalseBranch(FunctionCall call) {
- exists(IfStmt ifStmt |
- ifStmt.getThen().getAChild*() = call and
- (
- // Condition is a literal 0 / false (or any compile-time constant 0).
- ifStmt.getCondition().getValue() = "0"
- or
- // Condition is a variable access to a non-static local variable
- // that is initialized to 0/FALSE and never mutated.
- exists(LocalVariable v |
- ifStmt.getCondition().(VariableAccess).getTarget() = v and
- not v.isStatic() and
- v.getInitializer().getExpr().getValue() = "0" and
- not exists(Assignment a |
- a.getLValue().(VariableAccess).getTarget() = v and
- a.getEnclosingFunction() = call.getEnclosingFunction()
- ) and
- not exists(CrementOperation co |
- co.getOperand().(VariableAccess).getTarget() = v and
- co.getEnclosingFunction() = call.getEnclosingFunction()
- ) and
- not exists(AddressOfExpr ao |
- ao.getOperand().(VariableAccess).getTarget() = v
+ /**
+ * Holds if `call` is located inside the "then" branch of an `if` statement
+ * whose condition is a compile-time-constant `FALSE` (0) value, or a
+ * non-`static` local variable that is initialized to `0` / `FALSE`,
+ * never assigned (with any assignment operator) or incremented /
+ * decremented in the enclosing function, and whose address is never
+ * taken.
+ *
+ * This detects patterns like:
+ * ```
+ * BOOLEAN bFalse = FALSE;
+ * if (bFalse) { KeAcquireSpinLockAtDpcLevel(...); } // dead branch
+ * ```
+ * Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK, etc.).
+ *
+ * The conservative-by-default conditions on the variable case avoid
+ * silently dropping legitimate findings when the runtime value of the
+ * variable cannot be proven to remain `FALSE`:
+ *
+ * - `LocalVariable v` excludes file-scope and namespace globals,
+ * which can be reassigned from any other function in the
+ * translation unit (or even another TU).
+ * - `not v.isStatic()` excludes function-static variables, whose
+ * value persists across calls and could be set by a previous
+ * invocation.
+ * - The `Assignment` predicate matches plain `=` (`AssignExpr`) and
+ * all compound operators (`AssignOperation`: `|=`, `&=`, `+=`,
+ * etc.); the original `AssignExpr`-only check was too narrow.
+ * - `CrementOperation` covers `++` and `--`, which are not modeled
+ * as assignments in the cpp library.
+ * - Bailing out when the variable's address is taken
+ * (`AddressOfExpr`) prevents missing mutations performed by
+ * callees through a pointer (e.g., `SetFlag(&bFalse)`).
+ */
+ predicate isInConstantFalseBranch(FunctionCall call) {
+ exists(IfStmt ifStmt |
+ ifStmt.getThen().getAChild*() = call and
+ (
+ // Condition is a literal 0 / false (or any compile-time constant 0).
+ ifStmt.getCondition().getValue() = "0"
+ or
+ // Condition is a variable access to a non-static local variable
+ // that is initialized to 0/FALSE and never mutated.
+ exists(LocalVariable v |
+ ifStmt.getCondition().(VariableAccess).getTarget() = v and
+ not v.isStatic() and
+ v.getInitializer().getExpr().getValue() = "0" and
+ not exists(Assignment a |
+ a.getLValue().(VariableAccess).getTarget() = v and
+ a.getEnclosingFunction() = call.getEnclosingFunction()
+ ) and
+ not exists(CrementOperation co |
+ co.getOperand().(VariableAccess).getTarget() = v and
+ co.getEnclosingFunction() = call.getEnclosingFunction()
+ ) and
+ not exists(AddressOfExpr ao |
+ ao.getOperand().(VariableAccess).getTarget() = v
+ )
)
)
)
- )
-}
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index 52f2a60f..e13d284a 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -110,7 +110,7 @@ class PagedFunctionDeclaration extends Function {
* a `PagedFunctionDeclaration`. Pre-filtering the population at the class
* level (rather than as joined `where`-clause predicates) lets the optimizer
* materialize a small relation and avoid the full
- * `MacroInvocation × MacroInvocation` Cartesian product on large corpora.
+ * `MacroInvocation x MacroInvocation` Cartesian product on large corpora.
*/
class PagedCodeMacro extends MacroInvocation {
PagedCodeMacro() {
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.sarif b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.sarif
index 41a84ed4..94f41707 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.sarif
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.sarif
@@ -1,114 +1,393 @@
-{
- "$schema" : "https://json.schemastore.org/sarif-2.1.0.json",
- "version" : "2.1.0",
- "runs" : [ {
- "tool" : {
- "driver" : {
- "name" : "CodeQL",
- "organization" : "GitHub",
- "semanticVersion" : "2.11.5",
- "rules" : [ {
- "id" : "cpp/drivers/multiple-paged-code",
- "name" : "cpp/drivers/multiple-paged-code",
- "shortDescription" : {
- "text" : "Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED"
- },
- "fullDescription" : {
- "text" : "The function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This can cause issues when debugging, using Code Analysis, or running on checked builds."
- },
- "defaultConfiguration" : {
- "enabled" : true,
- "level" : "warning"
- },
- "properties" : {
- "tags" : [ "correctness", "wddst" ],
- "description" : "The function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This can cause issues when debugging, using Code Analysis, or running on checked builds.",
- "feature.area" : "Multiple",
- "id" : "cpp/drivers/multiple-paged-code",
- "impact" : "Insecure Coding Practice",
- "kind" : "problem",
- "name" : "Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED",
- "opaqueid" : "CQLD-C28171",
- "owner.email" : "sdat@microsoft.com",
- "platform" : "Desktop",
- "precision" : "high",
- "problem.severity" : "warning",
- "query-version" : "v1",
- "repro.text" : "The following code locations are duplicate PAGED_CODE() calls within a function.",
- "scope" : "domainspecific",
- "security.severity" : "Low"
- }
- } ]
- },
- "extensions" : [ {
- "name" : "microsoft/windows-drivers",
- "semanticVersion" : "0.1.0+933e876f096a70922173e4d5ad604d99d4481af4",
- "locations" : [ {
- "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/",
- "description" : {
- "text" : "The QL pack root directory."
- }
- }, {
- "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
- "description" : {
- "text" : "The QL pack definition file."
- }
- } ]
- }, {
- "name" : "legacy-upgrades",
- "semanticVersion" : "0.0.0",
- "locations" : [ {
- "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/",
- "description" : {
- "text" : "The QL pack root directory."
- }
- }, {
- "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/qlpack.yml",
- "description" : {
- "text" : "The QL pack definition file."
- }
- } ]
- } ]
- },
- "artifacts" : [ {
- "location" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
- }
- } ],
- "results" : [ {
- "ruleId" : "cpp/drivers/multiple-paged-code",
- "ruleIndex" : 0,
- "rule" : {
- "id" : "cpp/drivers/multiple-paged-code",
- "index" : 0
- },
- "message" : {
- "text" : "Functions in a paged section must have exactly one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro"
- },
- "locations" : [ {
- "physicalLocation" : {
- "artifactLocation" : {
- "uri" : "driver/driver_snippet.c",
- "uriBaseId" : "%SRCROOT%",
- "index" : 0
- },
- "region" : {
- "startLine" : 50,
- "startColumn" : 5,
- "endColumn" : 17
- }
- }
- } ],
- "partialFingerprints" : {
- "primaryLocationLineHash" : "c7556935fb8cd898:1",
- "primaryLocationStartColumnFingerprint" : "0"
- }
- } ],
- "columnKind" : "utf16CodeUnits",
- "properties" : {
- "semmle.formatSpecifier" : "sarifv2.1.0"
- }
- } ]
-}
\ No newline at end of file
+{
+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [
+ {
+ "tool": {
+ "driver": {
+ "name": "CodeQL",
+ "organization": "GitHub",
+ "semanticVersion": "2.24.2",
+ "notifications": [
+ {
+ "id": "cpp/baseline/expected-extracted-files",
+ "name": "cpp/baseline/expected-extracted-files",
+ "shortDescription": {
+ "text": "Expected extracted files"
+ },
+ "fullDescription": {
+ "text": "Files appearing in the source archive that are expected to be extracted."
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ },
+ "properties": {
+ "tags": [
+ "expected-extracted-files",
+ "telemetry"
+ ]
+ }
+ },
+ {
+ "id": "cli/file-coverage-baseline",
+ "name": "cli/file-coverage-baseline",
+ "shortDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "fullDescription": {
+ "text": "File coverage baseline telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cli/platform",
+ "name": "cli/platform",
+ "shortDescription": {
+ "text": "Platform"
+ },
+ "fullDescription": {
+ "text": "Platform"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ },
+ {
+ "id": "cpp/extractor/summary",
+ "name": "cpp/extractor/summary",
+ "shortDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "fullDescription": {
+ "text": "C++ extractor telemetry"
+ },
+ "defaultConfiguration": {
+ "enabled": true
+ }
+ }
+ ],
+ "rules": [
+ {
+ "id": "cpp/drivers/multiple-paged-code",
+ "name": "cpp/drivers/multiple-paged-code",
+ "shortDescription": {
+ "text": "Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED"
+ },
+ "fullDescription": {
+ "text": "The function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This can cause issues when debugging, using Code Analysis, or running on checked builds."
+ },
+ "defaultConfiguration": {
+ "enabled": true,
+ "level": "warning"
+ },
+ "help": {
+ "text": "# Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED\nThe function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This warning indicates that there is more than one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro in a function. This error is reported at the second or subsequent instances of the PAGED_CODE or PAGED_CODE_LOCKED macro.\n\n\n## Recommendation\nRemove all but one PAGED_CODE OR PAGED_CODE_LOCKED macro.\n\n\n## Example\n\n```c\n// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT license.\r\n\r\n\r\n//Macros to enable or disable a code section that may or maynot conflict with this test.\r\n#define SET_DISPATCH 1\r\n#define SET_PAGE_CODE 1\r\n\r\n\r\n_Dispatch_type_(IRP_MJ_CLEANUP) \r\nDRIVER_DISPATCH DispatchCleanup;\r\n\r\n_Dispatch_type_(IRP_MJ_SHUTDOWN)\r\nDRIVER_DISPATCH DispatchShutdown;\r\n\r\n#ifndef __cplusplus\r\n#pragma alloc_text (PAGE, DispatchCleanup)\r\n#pragma alloc_text (PAGE, DispatchShutdown)\r\n#endif\r\n\r\n\r\n//Template\r\nvoid top_level_call(){\r\n}\r\n\r\n//Passes\r\nNTSTATUS\r\nDispatchCleanup (\r\n PDEVICE_OBJECT DriverObject,\r\n PIRP Irp\r\n )\r\n{\r\n UNREFERENCED_PARAMETER(DriverObject);\r\n UNREFERENCED_PARAMETER(Irp);\r\n PAGED_CODE();\r\n \r\n return STATUS_SUCCESS;\r\n}\r\n\r\n//Fails\r\nNTSTATUS\r\nDispatchShutdown (\r\n PDEVICE_OBJECT DriverObject,\r\n PIRP Irp\r\n )\r\n{\r\n UNREFERENCED_PARAMETER(DriverObject);\r\n UNREFERENCED_PARAMETER(Irp);\r\n PAGED_CODE();\r\n PAGED_CODE();\r\n \r\n return STATUS_SUCCESS;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\n```\n\n## References\n* [ C28171 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28171-function-has-more-than-one-page-macro-instance)\n\n## Semmle-specific notes\n**C++ function template support.** When the same source-level `PAGED_CODE` macro is expanded into multiple `FunctionTemplateInstantiation` bodies, the query collapses all instantiations of a single source-level template into one match key (via the underlying `TemplateFunction`) so duplicates inside a templated paged function body are reported once at the source-level location. Specialisations and non-template-paged functions are excluded.\n\n",
+ "markdown": "# Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED\nThe function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This warning indicates that there is more than one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro in a function. This error is reported at the second or subsequent instances of the PAGED_CODE or PAGED_CODE_LOCKED macro.\n\n\n## Recommendation\nRemove all but one PAGED_CODE OR PAGED_CODE_LOCKED macro.\n\n\n## Example\n\n```c\n// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT license.\r\n\r\n\r\n//Macros to enable or disable a code section that may or maynot conflict with this test.\r\n#define SET_DISPATCH 1\r\n#define SET_PAGE_CODE 1\r\n\r\n\r\n_Dispatch_type_(IRP_MJ_CLEANUP) \r\nDRIVER_DISPATCH DispatchCleanup;\r\n\r\n_Dispatch_type_(IRP_MJ_SHUTDOWN)\r\nDRIVER_DISPATCH DispatchShutdown;\r\n\r\n#ifndef __cplusplus\r\n#pragma alloc_text (PAGE, DispatchCleanup)\r\n#pragma alloc_text (PAGE, DispatchShutdown)\r\n#endif\r\n\r\n\r\n//Template\r\nvoid top_level_call(){\r\n}\r\n\r\n//Passes\r\nNTSTATUS\r\nDispatchCleanup (\r\n PDEVICE_OBJECT DriverObject,\r\n PIRP Irp\r\n )\r\n{\r\n UNREFERENCED_PARAMETER(DriverObject);\r\n UNREFERENCED_PARAMETER(Irp);\r\n PAGED_CODE();\r\n \r\n return STATUS_SUCCESS;\r\n}\r\n\r\n//Fails\r\nNTSTATUS\r\nDispatchShutdown (\r\n PDEVICE_OBJECT DriverObject,\r\n PIRP Irp\r\n )\r\n{\r\n UNREFERENCED_PARAMETER(DriverObject);\r\n UNREFERENCED_PARAMETER(Irp);\r\n PAGED_CODE();\r\n PAGED_CODE();\r\n \r\n return STATUS_SUCCESS;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\n```\n\n## References\n* [ C28171 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28171-function-has-more-than-one-page-macro-instance)\n\n## Semmle-specific notes\n**C++ function template support.** When the same source-level `PAGED_CODE` macro is expanded into multiple `FunctionTemplateInstantiation` bodies, the query collapses all instantiations of a single source-level template into one match key (via the underlying `TemplateFunction`) so duplicates inside a templated paged function body are reported once at the source-level location. Specialisations and non-template-paged functions are excluded.\n\n"
+ },
+ "properties": {
+ "tags": [
+ "correctness",
+ "ca_ported",
+ "wddst"
+ ],
+ "description": "The function has more than one instance of PAGED_CODE or PAGED_CODE_LOCKED. This can cause issues when debugging, using Code Analysis, or running on checked builds.",
+ "feature.area": "Multiple",
+ "id": "cpp/drivers/multiple-paged-code",
+ "impact": "Insecure Coding Practice",
+ "kind": "problem",
+ "name": "Multiple instances of PAGED_CODE or PAGED_CODE_LOCKED",
+ "opaqueid": "CQLD-C28171",
+ "owner.email": "sdat@microsoft.com",
+ "platform": "Desktop",
+ "precision": "high",
+ "problem.severity": "warning",
+ "query-version": "v4",
+ "repro.text": "The following code locations are duplicate PAGED_CODE() calls within a function.",
+ "scope": "domainspecific",
+ "security.severity": "Low"
+ }
+ }
+ ]
+ },
+ "extensions": [
+ {
+ "name": "microsoft/windows-drivers",
+ "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
+ "locations": [
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "codeql/cpp-all",
+ "semanticVersion": "7.0.0+c5329f6f3863621c140ea7abd5954860e96c8bf1",
+ "locations": [
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/",
+ "description": {
+ "text": "The QL pack root directory."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackRoot"
+ ]
+ }
+ },
+ {
+ "uri": "file:///C:/Users/natede/.codeql/packages/codeql/cpp-all/7.0.0/qlpack.yml",
+ "description": {
+ "text": "The QL pack definition file."
+ },
+ "properties": {
+ "tags": [
+ "CodeQL/LocalPackDefinitionFile"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "invocations": [
+ {
+ "toolExecutionNotifications": [
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
+ }
+ }
+ }
+ ],
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "descriptor": {
+ "id": "cpp/baseline/expected-extracted-files",
+ "index": 0
+ },
+ "properties": {
+ "formattedMessage": {
+ "text": ""
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-29T04:41:39.691983100Z",
+ "descriptor": {
+ "id": "cli/file-coverage-baseline",
+ "index": 1
+ },
+ "properties": {
+ "attributes": {
+ "durationMilliseconds": 270
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": ""
+ },
+ "level": "none",
+ "timeUtc": "2026-04-29T04:41:39.700982700Z",
+ "descriptor": {
+ "id": "cli/platform",
+ "index": 2
+ },
+ "properties": {
+ "attributes": {
+ "arch": "amd64",
+ "name": "Windows 11",
+ "version": "10.0"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ },
+ {
+ "message": {
+ "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.",
+ "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
+ },
+ "level": "note",
+ "timeUtc": "2026-04-29T04:42:21.983112500Z",
+ "descriptor": {
+ "id": "cpp/extractor/summary",
+ "index": 3
+ },
+ "properties": {
+ "attributes": {
+ "cache-hits": 0,
+ "cache-misses": 1,
+ "compilers": [
+ {
+ "program": "cl",
+ "version": "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35724 for x64"
+ }
+ ],
+ "extractor-failures": 1,
+ "extractor-successes": 0,
+ "trap-caching": "disabled"
+ },
+ "visibility": {
+ "statusPage": false,
+ "telemetry": true
+ }
+ }
+ }
+ ],
+ "executionSuccessful": true
+ }
+ ],
+ "artifacts": [
+ {
+ "location": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.h",
+ "uriBaseId": "%SRCROOT%",
+ "index": 1
+ }
+ },
+ {
+ "location": {
+ "uri": "driver/fail_driver1.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 2
+ }
+ }
+ ],
+ "results": [
+ {
+ "ruleId": "cpp/drivers/multiple-paged-code",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/multiple-paged-code",
+ "index": 0
+ },
+ "message": {
+ "text": "Functions in a paged section must have exactly one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 50,
+ "startColumn": 5,
+ "endColumn": 17
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "c7556935fb8cd898:1",
+ "primaryLocationStartColumnFingerprint": "0"
+ }
+ }
+ ],
+ "columnKind": "utf16CodeUnits",
+ "properties": {
+ "semmle.formatSpecifier": "sarifv2.1.0"
+ }
+ }
+ ]
+}
From 39dd725fc01992bf14a42934229a3cc1fd7bf25b Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Wed, 29 Apr 2026 13:12:33 -0700
Subject: [PATCH 13/19] IFSM: add AST-loop OR-branch to irqlChangesBetween for
intra-function loop and re-entrant cases
The `irqlChangesBetween` predicate previously decided whether an
IRQL-changing call sits between a save and a restore using only
source-line position via the `anchorLineForCall` mechanism. This
correctly handles cross-function and acyclic in-function cases but
trivially fails on loops where the restore is textually above the save
(the bracketing line range is empty), even though at runtime the
loop back-edge means each iteration's restore is preceded by every
IRQL-changing call in the loop body.
This change adds a second disjunct to `irqlChangesBetween` that uses
AST-loop containment (`Loop.getStmt().getAChild*()`): when the save,
restore, and an IRQL-changing call all share a loop body in their
common enclosing function, the predicate fires. Combining the two
branches with OR is strictly additive and cannot regress any existing
true positive.
CFG-based reachability was rejected for two reasons documented during
investigation: BasicBlock CFG forward-reach is truncated in the
extracted DBs we test against, and ControlFlowNode forward reach
breaks at `if (call(...))` boundaries (the canonical IFSM pattern).
AST-loop containment sidesteps both issues by relying on a densely
populated AST relation that reflects the syntactic loop body.
Documents the residual limitation: the upstream IRQL analysis library
does not consistently bind `getPotentialExitIrqlAtCfn` at the
argument expression of `KeSaveFloatingPointState` when the call is
inside a loop body, so the `irqlSource != irqlSink` filter still
rejects the loop case before `irqlChangesBetween` is consulted.
Recovering this true positive requires improvements to the IRQL
analysis library, not just to this query. `driver_utility_loop_bad`
is retained in `driver_snippet.c` as a documented known false
negative so any future improvement to the IRQL library will be
detected via SARIF diff.
Refreshes `IrqlFloatStateMismatch.qhelp`, regenerates the rendered
`IrqlFloatStateMismatch.md`, refreshes the in-tree
`IrqlFloatStateMismatch.sarif` (rule-help text), and bumps
`@query-version` from v5 to v6.
Local test diff: +0/-0 (loop FN does not fire due to upstream
binding limitation; no existing TP is regressed).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.md | 4 +-
.../IrqlFloatStateMismatch.qhelp | 21 +++--
.../IrqlFloatStateMismatch.ql | 93 +++++++++++++++----
.../IrqlFloatStateMismatch.sarif | 18 ++--
.../IrqlFloatStateMismatch/driver_snippet.c | 36 +++++++
5 files changed, 134 insertions(+), 38 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
index 334e1566..80a99f6b 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
@@ -56,9 +56,9 @@ Correct example
## Semmle-specific notes
**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).
-**Remaining limitations.** The position-based filter still does not detect:
+**Remaining limitations.** Despite the source-position and AST-loop branches, the predicate still does not detect:
* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.
* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.
-* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.
+* **Loops where the restore is textually before the save.** The AST-loop branch of `irqlChangesBetween` correctly recognises that all three calls (save, restore, and an IRQL-changing call) sit inside the same loop body and would fire on this pattern. However, the upstream IRQL analysis library used to compute the IRQL at the save and restore sites does not consistently bind a value at the argument expression of `KeSaveFloatingPointState` when the call is inside a loop body, so the `irqlSource != irqlSink` filter rejects these cases before `irqlChangesBetween` is consulted. Recovering this true positive requires improvements to the IRQL analysis library and not just to this query.
* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
index 97f3323a..b950c391 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
@@ -75,8 +75,8 @@
where one side is a helper and the other is direct).
- Remaining limitations. The position-based filter still does
- not detect:
+ Remaining limitations. Despite the source-position and
+ AST-loop branches, the predicate still does not detect:
-
@@ -96,11 +96,18 @@
-
Loops where the restore is textually before the save.
- The filter compares source line numbers; in a loop body
- whose first statement is the restore and last statement is
- the save (with the IRQL change after the save), the line
- range becomes empty and no intermediate IRQL change is
- seen.
+ The AST-loop branch of
irqlChangesBetween
+ correctly recognises that all three calls (save, restore,
+ and an IRQL-changing call) sit inside the same loop body and
+ would fire on this pattern. However, the upstream IRQL
+ analysis library used to compute the IRQL at the save and
+ restore sites does not consistently bind a value at the
+ argument expression of KeSaveFloatingPointState
+ when the call is inside a loop body, so the
+ irqlSource != irqlSink filter rejects these
+ cases before irqlChangesBetween is consulted.
+ Recovering this true positive requires improvements to the
+ IRQL analysis library and not just to this query.
-
Wrapper chains longer than one level. Only one level
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index d22c9ff6..6ecd3e9d 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -17,7 +17,7 @@
* @tags correctness
* ca_ported
* @scope domainspecific
- * @query-version v5
+ * @query-version v6
*/
import cpp
@@ -101,30 +101,66 @@ private int anchorLineForCall(Function f, FunctionCall fc) {
}
/**
- * Holds if there is an IRQL-changing call in some function `f` whose
- * source line lies between the save anchor and the restore anchor in
- * `f`. The anchor mechanism (see `anchorLineForCall`) lets `f` be:
+ * Holds if there is an IRQL-changing call between `saveCall` and
+ * `restoreCall` in some function `f`. This predicate is a sanity filter
+ * applied on top of the dataflow result: dataflow has already shown the
+ * floating-point buffer flows from `saveCall` to `restoreCall`, and this
+ * predicate ensures there is at least one IRQL transition that could
+ * actually run between them. Without it the query would emit the pure
+ * may-analysis artifact where two save / restore sites are compared at
+ * different hypothetical entry IRQLs but no IRQL transition can happen
+ * between them at runtime.
*
- * - the enclosing function of both `saveCall` and `restoreCall`
- * (the original same-function case),
- * - the common caller that calls thin save / restore helper
- * wrappers,
- * - the enclosing function of one of the two calls when the other
- * is in a one-level helper called from it (asymmetric case).
+ * Two complementary disjuncts cooperate:
*
- * The dataflow library has already established that the floating-
- * point buffer flows from `saveCall` to `restoreCall`; this predicate
- * is purely a sanity filter to suppress the pure may-analysis
- * artifact where two save / restore sites are compared at different
- * hypothetical entry IRQLs but no IRQL transition can actually happen
- * at runtime between them.
+ * 1. **Source-position branch.** For some `f`, an IRQL-changing call
+ * `mid` in `f` lies on a source line bracketed by the anchor lines
+ * of `saveCall` and `restoreCall` (see `anchorLineForCall`). The
+ * anchor mechanism lets `f` be the directly enclosing function of
+ * both calls or a one-level wrapper / common caller, which covers
+ * the cross-function case that intra-procedural CFG cannot reach.
*
- * The position-based check (rather than a CFG-reachability check) is
- * required because the cpp control-flow graph in some extracted
- * databases does not transitively connect calls across statement
- * boundaries, which would silently eliminate true positives.
+ * 2. **AST-loop branch.** All three calls (`saveCall`, `restoreCall`,
+ * `mid`) sit inside the body of the same loop in their common
+ * enclosing function. The loop back-edge means that at runtime
+ * each iteration's `restoreCall` can be preceded by the previous
+ * iteration's `saveCall` with `mid` between them, so an
+ * IRQL-changing `mid` anywhere in the loop body is a real
+ * transition between save and restore even when `restoreCall` is
+ * textually above `saveCall`. Source-line position alone cannot
+ * express this: when the restore is textually earlier than the
+ * save the bracketing line range is empty and branch (1) trivially
+ * fails.
+ *
+ * The two branches are disjoint in spirit: branch (1) handles
+ * cross-function and acyclic in-function cases; branch (2) handles
+ * intra-function loops and re-entrant patterns. Combining them is
+ * strictly additive (can only enable more findings, never suppress one
+ * that branch (1) would have flagged), so existing true positives are
+ * preserved.
+ *
+ * Why not full intra-procedural CFG reachability instead of branch (1)?
+ * The cpp control-flow graph in some extracted databases does not
+ * transitively connect calls across certain statement boundaries (in
+ * particular, forward reachability across `if (call(...))` conditions
+ * is unreliable in our extracted DBs), which would silently eliminate
+ * true positives that branch (1) catches via source-line bracketing.
+ * AST-loop containment in branch (2) sidesteps this by relying on the
+ * AST `Loop.getStmt().getAChild*()` relation, which is densely
+ * populated and reflects the syntactic loop body directly.
+ *
+ * Caveat: branch (2) cooperates with `irqlSource != irqlSink` only when
+ * the IRQL-analysis library binds `getPotentialExitIrqlAtCfn` at the
+ * argument expression of `KeSaveFloatingPointState`. In our current
+ * extracted DBs that binding is not always produced for `save` calls
+ * inside loop bodies, so some real-world loop true positives may
+ * still be filtered out by the upstream IRQL filter even when this
+ * predicate fires; recovering those will require improvements to
+ * the IRQL analysis library itself.
*/
predicate irqlChangesBetween(FunctionCall saveCall, FunctionCall restoreCall) {
+ // Branch 1: source-line bracketing in a function `f` that anchors
+ // both calls (directly enclosing or one-level wrapper / common caller).
exists(Function f, int saveLine, int restoreLine, FunctionCall mid |
saveLine = anchorLineForCall(f, saveCall) and
restoreLine = anchorLineForCall(f, restoreCall) and
@@ -135,6 +171,23 @@ predicate irqlChangesBetween(FunctionCall saveCall, FunctionCall restoreCall) {
mid != saveCall and
mid != restoreCall
)
+ or
+ // Branch 2: all three calls live inside the body of the same loop in
+ // their shared enclosing function. The loop back-edge makes any
+ // IRQL-changing call in the body a real transition between save and
+ // restore on a subsequent iteration, even when source-line position
+ // would put restore before save.
+ exists(Function f, Loop l, FunctionCall mid |
+ f = saveCall.getEnclosingFunction() and
+ f = restoreCall.getEnclosingFunction() and
+ f = mid.getEnclosingFunction() and
+ isIrqlChangingCall(mid) and
+ mid != saveCall and
+ mid != restoreCall and
+ l.getStmt().getAChild*() = saveCall.getEnclosingStmt() and
+ l.getStmt().getAChild*() = restoreCall.getEnclosingStmt() and
+ l.getStmt().getAChild*() = mid.getEnclosingStmt()
+ )
}
from
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index b85849e4..64ec6030 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -83,8 +83,8 @@
"level": "warning"
},
"help": {
- "text": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** The position-based filter still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n",
- "markdown": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** The position-based filter still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The filter compares source line numbers; in a loop body whose first statement is the restore and last statement is the save (with the IRQL change after the save), the line range becomes empty and no intermediate IRQL change is seen.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n"
+ "text": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** Despite the source-position and AST-loop branches, the predicate still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The AST-loop branch of `irqlChangesBetween` correctly recognises that all three calls (save, restore, and an IRQL-changing call) sit inside the same loop body and would fire on this pattern. However, the upstream IRQL analysis library used to compute the IRQL at the save and restore sites does not consistently bind a value at the argument expression of `KeSaveFloatingPointState` when the call is inside a loop body, so the `irqlSource != irqlSink` filter rejects these cases before `irqlChangesBetween` is consulted. Recovering this true positive requires improvements to the IRQL analysis library and not just to this query.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n",
+ "markdown": "# Irql Float State Mismatch\nThe IRQL where the floating-point state was saved does not match the current IRQL (for this restore operation).\n\n\n## Recommendation\nThe IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state. Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.\n\n\n## Example\nExample of incorrect code. Floating point state was saved at APC_LEVEL but restored at PASSIVE_LEVEL\n\n```c\n \n\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\tvoid driver_utility_bad(void)\n\t\t{\n\t\t\tKIRQL oldIRQL;\n\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t// running at APC level\n\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t{\n\t\t\t\tKeLowerIrql(oldIRQL); // lower back to PASSIVE_LEVEL\n\t\t\t\t// ...\n\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t}\n\t\t}\n\t\t\n```\nCorrect example\n\n```c\n \n\t\t\t_IRQL_requires_(PASSIVE_LEVEL) \n\t\t\tvoid driver_utility_good(void)\n\t\t\t{\n\t\t\t\t// running at APC level\n\t\t\t\tKFLOATING_SAVE FloatBuf;\n\t\t\t\tKIRQL oldIRQL;\n\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\n\t\t\t\tif (KeSaveFloatingPointState(&FloatBuf))\n\t\t\t\t{\n\t\t\t\t\tKeLowerIrql(oldIRQL);\n\t\t\t\t\t// ...\n\t\t\t\t\tKeRaiseIrql(APC_LEVEL, &oldIRQL);\n\t\t\t\t\tKeRestoreFloatingPointState(&FloatBuf);\n\t\t\t\t}\n\t\t\t}\n\t\t\n```\n\n## References\n* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)\n\n## Semmle-specific notes\n**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).\n\n**Remaining limitations.** Despite the source-position and AST-loop branches, the predicate still does not detect:\n\n* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.\n* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.\n* **Loops where the restore is textually before the save.** The AST-loop branch of `irqlChangesBetween` correctly recognises that all three calls (save, restore, and an IRQL-changing call) sit inside the same loop body and would fire on this pattern. However, the upstream IRQL analysis library used to compute the IRQL at the save and restore sites does not consistently bind a value at the argument expression of `KeSaveFloatingPointState` when the call is inside a loop body, so the `irqlSource != irqlSink` filter rejects these cases before `irqlChangesBetween` is consulted. Recovering this true positive requires improvements to the IRQL analysis library and not just to this query.\n* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.\n"
},
"properties": {
"tags": [
@@ -102,7 +102,7 @@
"platform": "Desktop",
"precision": "medium",
"problem.severity": "warning",
- "query-version": "v5",
+ "query-version": "v6",
"repro.text": "The IRQL at which the driver is executing when it restores a floating-point state is different than the IRQL at which it was executing when it saved the floating-point state.\n Because the IRQL at which the driver runs determines how the floating-point state is saved, the driver must be executing at the same IRQL when it calls the functions to save and to restore the floating-point state.",
"scope": "domainspecific"
}
@@ -112,7 +112,7 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.9.0+a76f8551b47f01adada99ddc44a5ea4fa9839fca",
+ "semanticVersion": "1.9.0+4cacaf0d92da0d47dab3a6bd6640729cf07eec99",
"locations": [
{
"uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
@@ -254,14 +254,14 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-29T04:38:29.808991Z",
+ "timeUtc": "2026-04-29T20:06:00.500637300Z",
"descriptor": {
"id": "cli/file-coverage-baseline",
"index": 1
},
"properties": {
"attributes": {
- "durationMilliseconds": 253
+ "durationMilliseconds": 197
},
"visibility": {
"statusPage": false,
@@ -274,7 +274,7 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-29T04:38:29.815492900Z",
+ "timeUtc": "2026-04-29T20:06:00.504647400Z",
"descriptor": {
"id": "cli/platform",
"index": 2
@@ -297,7 +297,7 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-04-29T04:39:07.709847200Z",
+ "timeUtc": "2026-04-29T20:06:43.926354300Z",
"descriptor": {
"id": "cpp/extractor/summary",
"index": 3
@@ -512,4 +512,4 @@
}
}
]
-}
+}
\ No newline at end of file
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
index df0c6a26..b4ac74b6 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/driver_snippet.c
@@ -123,3 +123,39 @@ void driver_utility_cross_function_bad(void)
restore_fp_helper(&FloatBuf);
KeLowerIrql(oldIRQL);
}
+
+// =====================================================================
+// Documentation: a loop where the restore is textually above the save.
+//
+// At runtime, each iteration's `KeRestoreFloatingPointState` is preceded
+// by the previous iteration's `KeSaveFloatingPointState` via the loop
+// back-edge, with `KeLowerIrql` in between, so the IRQL at the save
+// (PASSIVE_LEVEL) does not match the IRQL at the restore (APC_LEVEL).
+// Source-line position alone cannot see this because the half-open
+// range [saveLine, restoreLine] is empty when the restore is textually
+// earlier than the save in the function body. The AST-loop branch of
+// `irqlChangesBetween` recognises this case and would fire here, but
+// in our currently extracted DBs the upstream IRQL analysis library
+// does not bind `getPotentialExitIrqlAtCfn` at the argument expression
+// of `KeSaveFloatingPointState` when the save is inside a loop body,
+// so the source-IRQL filter still rejects this case and the finding
+// is suppressed. This function is retained as a documented known
+// false negative; recovering it requires improvements to the IRQL
+// analysis library and not just to this query.
+// =====================================================================
+_IRQL_requires_(PASSIVE_LEVEL)
+void driver_utility_loop_bad(void)
+{
+ KFLOATING_SAVE FloatBuf;
+ KIRQL oldIRQL;
+
+ KeRaiseIrql(APC_LEVEL, &oldIRQL);
+
+ for (int i = 0; i < 2; i++)
+ {
+ KeRestoreFloatingPointState(&FloatBuf);
+ KeLowerIrql(PASSIVE_LEVEL);
+ KeSaveFloatingPointState(&FloatBuf);
+ KeRaiseIrql(APC_LEVEL, &oldIRQL);
+ }
+}
From ad1379a1c190c646c8047ea20f40cd5b9da49701 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Thu, 30 Apr 2026 10:56:31 -0700
Subject: [PATCH 14/19] Irql.qll: add loop-body AST fallback to
getPotentialExitIrqlAtCfn
The recursive cascade in `getPotentialExitIrqlAtCfn` returns no value
for argument-expression CFNs of function calls reached via a loop
back-edge in some extracted databases. When the cascade is empty,
downstream queries that consume the result either drop the relevant
finding (because their `irqlSource = getPotentialExitIrqlAtCfn(...)`
binding fails) or fire spuriously (because they treat empty as
out-of-range). This is the upstream complement to the IFSM
`irqlChangesBetween` AST-loop OR-branch added in 39dd725.
Fix: rename the existing predicate body to a private
`getPotentialExitIrqlAtCfnRaw` helper and introduce a public wrapper
that returns Raw's bindings unchanged, plus -- only when Raw yields
no value at all -- a single-step AST-level fallback that returns the
cascade's IRQL at the closest source-line preceding sibling Stmt.
The fallback is restricted to CFNs whose enclosing Stmt sits inside
a loop body, which is the empirical failure mode and avoids
over-approximating on linear branching code.
Layering preserves existing semantics on every input where Raw binds:
the wrapper agrees with Raw setwise there, so no query that previously
bound correctly can regress. The only behavioural change is to fill
in silence with one conservative value derived from textually-preceding
code in the loop body.
Internal callers inside Irql.qll that participated in the recursive
stratum (getIrqlLevel for the three save-globals classes and
functionExitIrql) are switched to call Raw directly so the wrapper's
negation does not cycle back through them.
Validation:
Local IFSM TestDB: the documented "known false negative"
`driver_utility_loop_bad` at driver_snippet.c:156 (a for-loop where
the restore is textually above the save) now fires as a true positive,
recovered exactly as the source comment block at lines 127-145
predicted would require improvements to the IRQL analysis library.
SARIF baseline updated to include the new finding.
Out-of-tree corpora (clean cache, --ram tuned per DB): for the five
queries that call this predicate and have non-zero baseline:
* IrqlFunctionNotAnnotated, IrqlInconsistentWithRequired,
IrqlTooHigh, IrqlTooLow: identical findings before and after on
both small corpora.
* KeSetEventIrql: one fewer finding on the larger of the two small
corpora (a true false-positive suppression in a worker-thread
routine where a release-spinlock immediately precedes a SetEvent
inside a `for(;;)` loop body; the cascade was empty pre-fix and the
KeSetEvent query treated empty as out-of-range, warning spuriously).
The fallback walks back to the release sibling stmt, binds PASSIVE,
and the warning is correctly silenced.
Sanity-check queries that do not call the predicate (IrqlNotUsed,
IrqlCancelRoutine) are unchanged, confirming the rename did not
perturb unrelated paths.
Performance: no measurable wall-time regression observed on either
small corpus.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.sarif | 72 +++++++++++++-
src/drivers/libraries/Irql.qll | 96 ++++++++++++++++---
2 files changed, 152 insertions(+), 16 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
index 64ec6030..b2bf15de 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.sarif
@@ -112,7 +112,7 @@
"extensions": [
{
"name": "microsoft/windows-drivers",
- "semanticVersion": "1.9.0+4cacaf0d92da0d47dab3a6bd6640729cf07eec99",
+ "semanticVersion": "1.9.0+39dd725fc01992bf14a42934229a3cc1fd7bf25b",
"locations": [
{
"uri": "file:///F:/source/repos/Windows-Driver-Developer-Supplemental-Tools/src/",
@@ -254,14 +254,14 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-29T20:06:00.500637300Z",
+ "timeUtc": "2026-04-29T20:46:26.236012500Z",
"descriptor": {
"id": "cli/file-coverage-baseline",
"index": 1
},
"properties": {
"attributes": {
- "durationMilliseconds": 197
+ "durationMilliseconds": 233
},
"visibility": {
"statusPage": false,
@@ -274,7 +274,7 @@
"text": ""
},
"level": "none",
- "timeUtc": "2026-04-29T20:06:00.504647400Z",
+ "timeUtc": "2026-04-29T20:46:26.241012400Z",
"descriptor": {
"id": "cli/platform",
"index": 2
@@ -297,7 +297,7 @@
"markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed."
},
"level": "note",
- "timeUtc": "2026-04-29T20:06:43.926354300Z",
+ "timeUtc": "2026-04-29T20:47:05.794926800Z",
"descriptor": {
"id": "cpp/extractor/summary",
"index": 3
@@ -350,6 +350,68 @@
}
],
"results": [
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (0) does not match the irql level for the restore operation (1).\nThe irql level where the floating-point state was saved (2) does not match the irql level for the restore operation (1)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 156,
+ "startColumn": 38,
+ "endColumn": 46
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "7203877b7e98c247:1",
+ "primaryLocationStartColumnFingerprint": "29"
+ }
+ },
+ {
+ "ruleId": "cpp/drivers/irql-float-state-mismatch",
+ "ruleIndex": 0,
+ "rule": {
+ "id": "cpp/drivers/irql-float-state-mismatch",
+ "index": 0
+ },
+ "message": {
+ "text": "The irql level where the floating-point state was saved (0) does not match the irql level for the restore operation (1).\nThe irql level where the floating-point state was saved (2) does not match the irql level for the restore operation (1)."
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "driver/driver_snippet.c",
+ "uriBaseId": "%SRCROOT%",
+ "index": 0
+ },
+ "region": {
+ "startLine": 156,
+ "startColumn": 37,
+ "endColumn": 46
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "7203877b7e98c247:1",
+ "primaryLocationStartColumnFingerprint": "28"
+ }
+ },
{
"ruleId": "cpp/drivers/irql-float-state-mismatch",
"ruleIndex": 0,
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index 3a5dfb43..55076190 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -534,13 +534,13 @@
* "the IRQL before the corresponding save global call."
*/
int getIrqlLevel() {
- result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor()))
+ result = any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaise().getAPredecessor()))
}
-
+
int getIrqlLevelExplicit() {
result = any(getExplicitExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor()))
}
-
+
/** Returns the matching call to a function that saved the IRQL. */
IrqlSaveCall getMostRecentRaise() {
result =
@@ -614,7 +614,7 @@
*/
int getIrqlLevel() {
result =
- any(getPotentialExitIrqlAtCfn(this.getMostRecentRaiseInterprocedural().getAPredecessor()))
+ any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaiseInterprocedural().getAPredecessor()))
}
int getIrqlLevelExplicit() {
@@ -665,13 +665,13 @@
* "the IRQL before the corresponding save global call."
*/
int getIrqlLevel() {
- result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor()))
+ result = any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaise().getAPredecessor()))
}
-
+
int getIrqlLevelExplicit() {
result = any(getExplicitExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor()))
}
-
+
/**
* Returns the matching call to a function that saved the IRQL to a global state.
*
@@ -735,10 +735,17 @@
/**
* Pre-computed summary: the potential exit IRQL of function `f`,
* computed once per function rather than re-discovered per call site.
+ *
+ * Calls the Raw cascade directly rather than the public wrapper so
+ * that this internal building block stays inside a single recursive
+ * stratum with the cascade. The wrapper layers an AST-level fallback
+ * over Raw using a negation, which would otherwise cycle back through
+ * here. Equivalent to the historical pre-wrapper behaviour because
+ * the wrapper agrees with Raw on every input where Raw binds.
*/
pragma[nomagic]
private int functionExitIrql(Function f) {
- result = getPotentialExitIrqlAtCfn(getAnExitPointOfFunction(f))
+ result = getPotentialExitIrqlAtCfnRaw(getAnExitPointOfFunction(f))
}
/**
@@ -765,9 +772,38 @@
* - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function.
* - Failing all this, we set the IRQL to 0.
*
+ * Layering note: this public predicate wraps the recursive cascade
+ * `getPotentialExitIrqlAtCfnRaw` with a single AST-level fallback
+ * (`astLevelExitIrqlFallback`) that activates only when the cascade
+ * yields no value at all. The fallback walks one source-line step
+ * back to the closest preceding sibling Stmt and returns the cascade's
+ * IRQL there. This recovers binding for argument-expression CFNs of
+ * function calls inside loop bodies, where the cpp CFG in some
+ * extracted databases is too sparse for the cascade's predecessor walk
+ * to converge. The fallback is restricted to CFNs inside loop bodies
+ * (the empirical failure mode), keeping it from over-approximating on
+ * linear branching code where the cascade's silence may be hiding
+ * IRQL-changing work that an AST-level scan cannot see. When the
+ * cascade already binds, this wrapper returns exactly the cascade's
+ * result set: the fallback never widens an existing binding.
+ *
* Not implemented: _IRQL_limited_to_
*/
int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) {
+ result = getPotentialExitIrqlAtCfnRaw(cfn)
+ or
+ not exists(getPotentialExitIrqlAtCfnRaw(cfn)) and
+ result = astLevelExitIrqlFallback(cfn)
+ }
+
+ /**
+ * Internal recursive cascade for `getPotentialExitIrqlAtCfn`. Behaves
+ * exactly like the historical `getPotentialExitIrqlAtCfn` did before
+ * the AST fallback wrapper was introduced. Callers should use
+ * `getPotentialExitIrqlAtCfn` instead, which additionally consults
+ * `astLevelExitIrqlFallback` when this cascade yields no value.
+ */
+ private int getPotentialExitIrqlAtCfnRaw(ControlFlowNode cfn) {
if cfn instanceof KeRaiseIrqlCall
then result = cfn.(KeRaiseIrqlCall).getIrqlLevel()
else
@@ -788,18 +824,18 @@
if
cfn instanceof FunctionCall and
cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction
- then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
+ then result = getPotentialExitIrqlAtCfnRaw(cfn.getAPredecessor())
else
if cfn instanceof FunctionCall
then result = functionExitIrql(cfn.(FunctionCall).getTarget())
else
if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor())
- then result = getPotentialExitIrqlAtCfn(cfn.getAPredecessor())
+ then result = getPotentialExitIrqlAtCfnRaw(cfn.getAPredecessor())
else
if exists(callerPredecessor(cfn.getControlFlowScope()))
then
result =
- getPotentialExitIrqlAtCfn(callerPredecessor(cfn.getControlFlowScope()))
+ getPotentialExitIrqlAtCfnRaw(callerPredecessor(cfn.getControlFlowScope()))
else
if
cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and
@@ -808,6 +844,44 @@
else result = 0
}
+ /**
+ * AST-level fallback for `getPotentialExitIrqlAtCfn`. Walks to the
+ * closest source-line preceding sibling Stmt of `cfn`'s enclosing Stmt
+ * (within the same parent Stmt) and returns the cascade's IRQL there.
+ * Yields no value when there is no preceding sibling at the same
+ * nesting level (e.g. `cfn` is the first stmt in its block) or when
+ * the cascade also yields no value at that sibling.
+ *
+ * Restricted to CFNs whose enclosing Stmt sits inside a loop body. The
+ * cascade's CFG-predecessor walk is reliable on linear control flow but
+ * empirically can fail to bind on argument-expression CFNs of function
+ * calls reached via a loop back-edge; this fallback exists to recover
+ * binding for that specific case. Restricting to loops avoids
+ * supplying coarse single-value approximations on linear code where the
+ * cascade's silence (when it does occur) often reflects branching that
+ * the AST-level scan cannot reason about (e.g. an if-stmt whose body
+ * raises and lowers IRQL).
+ *
+ * Consulted by `getPotentialExitIrqlAtCfn` only when the cascade
+ * returns no value at all, so this never widens an existing binding;
+ * it only fills in silence with a single conservative IRQL value
+ * derived from textually-preceding code in the loop body.
+ */
+ private int astLevelExitIrqlFallback(ControlFlowNode cfn) {
+ exists(Stmt cfnStmt, Stmt prev, Loop l |
+ cfnStmt = cfn.getEnclosingStmt() and
+ cfnStmt.getParent+() = l and
+ prev.getParentStmt() = cfnStmt.getParentStmt() and
+ prev.getLocation().getStartLine() < cfnStmt.getLocation().getStartLine() and
+ not exists(Stmt closer |
+ closer.getParentStmt() = cfnStmt.getParentStmt() and
+ closer.getLocation().getStartLine() < cfnStmt.getLocation().getStartLine() and
+ closer.getLocation().getStartLine() > prev.getLocation().getStartLine()
+ ) and
+ result = getPotentialExitIrqlAtCfnRaw(prev)
+ )
+ }
+
/*
* Similar to above, but only exit points where the Irql is explicit
*/
From 65e632887ebb95a924f7f63aa72016e9ba09eb98 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Fri, 1 May 2026 00:55:40 -0700
Subject: [PATCH 15/19] IrqlFloatStateMismatch: pragma[inline_late] on
irqlChangesBetween
The `irqlChangesBetween/2` predicate is the hottest single predicate in
the IFSM query at HEAD (~109 s of CPU and 3.43 M result tuples in the
18-query suite measurement on the WDS sample database, accounting for
roughly a quarter of the IFSM query's total cost).
Without a planner hint, the predicate is materialized as a standalone
relation over every `(FunctionCall, FunctionCall)` pair in the codebase
that satisfies its constraints, and only then intersected with the
~25-row dataflow result set produced by `FloatStateFlow::flow`. With
`pragma[inline_late]` plus the matching `bindingset[saveCall,
restoreCall]`, the body is specialized at the single call site after
the dataflow result has bound both arguments, so the predicate body is
evaluated only on the small set of dataflow-derived pairs.
Validation on the WDS sample database (single-query run, cold cache):
- SARIF result count for cpp/drivers/irql-float-state-mismatch: 0
(matches the HEAD baseline of 0; correctness preserved)
- `irqlChangesBetween` no longer appears as a discrete predicate in
the evaluator log (it has been fully inlined into its call site)
- New top single-query predicate: 28.9 s, vs 109 s for the
standalone `irqlChangesBetween` in the baseline suite measurement
This is a planner-hint change only. The predicate body is byte-for-byte
unchanged, so the set of `(saveCall, restoreCall)` pairs the predicate
admits (and therefore the set of `select` rows the query produces) is
unchanged on every database. The `bindingset` is honest: the only
caller (line 215) binds both arguments via the `FloatStateFlow::flow`
result and the `asIndirectExpr` constraints in the same `where` clause.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../IrqlFloatStateMismatch.ql | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 6ecd3e9d..3dcd4895 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -157,7 +157,23 @@ private int anchorLineForCall(Function f, FunctionCall fc) {
* still be filtered out by the upstream IRQL filter even when this
* predicate fires; recovering those will require improvements to
* the IRQL analysis library itself.
+ *
+ * Performance note: `pragma[inline_late]` lets the planner specialize
+ * this predicate at its call site after the dataflow result has bound
+ * `saveCall` and `restoreCall`. Without it, the body would otherwise
+ * be materialized over every (saveCall, restoreCall) pair in the
+ * codebase that satisfies the constraints (millions of tuples on
+ * large drivers), only to be intersected with a much smaller dataflow
+ * result set afterwards. With it, the body is evaluated only for the
+ * dataflow-derived pairs, turning a codebase-wide enumeration into a
+ * per-pair check. The accompanying `bindingset` records the calling
+ * convention required by `inline_late` (both arguments bound at the
+ * call site, which is satisfied by the `from` clause below).
+ * Semantics are unchanged — both annotations are planner hints, not
+ * logical changes.
*/
+bindingset[saveCall, restoreCall]
+pragma[inline_late]
predicate irqlChangesBetween(FunctionCall saveCall, FunctionCall restoreCall) {
// Branch 1: source-line bracketing in a function `f` that anchors
// both calls (directly enclosing or one-level wrapper / common caller).
From 9a8eba13eb5bc17efcb371144738541c6de39bed Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Tue, 5 May 2026 17:19:06 -0700
Subject: [PATCH 16/19] [AI] More IRQL correctness tweaks
---
.../IrqlFloatStateMismatch.ql | 33 ----------
.../IrqlInconsistentWithRequired.ql | 9 ++-
src/drivers/libraries/Irql.qll | 66 +++++++++++++++----
3 files changed, 61 insertions(+), 47 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 3dcd4895..0c1cb036 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -42,39 +42,6 @@ module FloatStateFlowConfig implements DataFlow::ConfigSig {
module FloatStateFlow = DataFlow::Global;
-/**
- * Holds if `fc` is a call that may change the IRQL. This includes the
- * IRQL primitives (KeRaiseIrql, KeLowerIrql, KfRaiseIrql, KfLowerIrql,
- * etc.), functions annotated with _IRQL_raises_ or
- * _IRQL_saves_global_ / _IRQL_restores_global_, and functions whose
- * body itself transitively contains an IRQL-changing call (i.e.,
- * unannotated wrapper helpers).
- *
- * The transitive closure over the call graph is necessary to avoid
- * false negatives where a driver wraps the IRQL primitives in a helper
- * function without the appropriate SAL annotations.
- */
-predicate isIrqlChangingFunction(Function f) {
- f instanceof IrqlChangesFunction
- or
- exists(FunctionCall inner |
- inner.getEnclosingFunction() = f and
- isIrqlChangingCall(inner)
- )
-}
-
-predicate isIrqlChangingCall(FunctionCall fc) {
- fc instanceof KeRaiseIrqlCall
- or
- fc instanceof KeLowerIrqlCall
- or
- fc instanceof RestoresGlobalIrqlCall
- or
- fc instanceof SavesGlobalIrqlCall
- or
- isIrqlChangingFunction(fc.getTarget())
-}
-
/**
* Gets a source line in `f` that anchors `fc` from `f`'s perspective:
*
diff --git a/src/drivers/general/queries/IrqlInconsistentWithRequired/IrqlInconsistentWithRequired.ql b/src/drivers/general/queries/IrqlInconsistentWithRequired/IrqlInconsistentWithRequired.ql
index 344f01e0..6c32239c 100644
--- a/src/drivers/general/queries/IrqlInconsistentWithRequired/IrqlInconsistentWithRequired.ql
+++ b/src/drivers/general/queries/IrqlInconsistentWithRequired/IrqlInconsistentWithRequired.ql
@@ -30,7 +30,14 @@ where
entryCfn = f.getBlock() and
irqlLevelEntry = getPotentialExitIrqlAtCfn(entryCfn) and
irqlLevelExit = getPotentialExitIrqlAtCfn(exitCfn) and
- irqlLevelEntry != irqlLevelExit
+ irqlLevelEntry != irqlLevelExit and
+ // Soundness filter: only flag if `f` actually contains an IRQL-changing
+ // call (directly or transitively through a wrapper). This is necessary
+ // due to our IRQL CFG analysis producing ranges of potential IRQLs.
+ exists(FunctionCall fc |
+ fc.getEnclosingFunction() = f and
+ isIrqlChangingCall(fc)
+ )
select f,
"Possible IRQL level at function completion inconsistent with the required IRQL level for some path. Irql level expected: "
+ irqlLevelEntry + ". Irql level found: " + irqlLevelExit +
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index 55076190..bc1e6205 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -534,7 +534,7 @@
* "the IRQL before the corresponding save global call."
*/
int getIrqlLevel() {
- result = any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaise().getAPredecessor()))
+ result = any(getPotentialExitIrqlAtCfnInternal(this.getMostRecentRaise().getAPredecessor()))
}
int getIrqlLevelExplicit() {
@@ -614,7 +614,7 @@
*/
int getIrqlLevel() {
result =
- any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaiseInterprocedural().getAPredecessor()))
+ any(getPotentialExitIrqlAtCfnInternal(this.getMostRecentRaiseInterprocedural().getAPredecessor()))
}
int getIrqlLevelExplicit() {
@@ -665,7 +665,7 @@
* "the IRQL before the corresponding save global call."
*/
int getIrqlLevel() {
- result = any(getPotentialExitIrqlAtCfnRaw(this.getMostRecentRaise().getAPredecessor()))
+ result = any(getPotentialExitIrqlAtCfnInternal(this.getMostRecentRaise().getAPredecessor()))
}
int getIrqlLevelExplicit() {
@@ -723,7 +723,7 @@
)
or
not exists(Expr child | child = e1.getAChild() or child = e2.getAChild())
- }
+}
/** Utility function to get all exit points of a function. */
pragma[nomagic]
@@ -745,7 +745,7 @@
*/
pragma[nomagic]
private int functionExitIrql(Function f) {
- result = getPotentialExitIrqlAtCfnRaw(getAnExitPointOfFunction(f))
+ result = getPotentialExitIrqlAtCfnInternal(getAnExitPointOfFunction(f))
}
/**
@@ -790,9 +790,9 @@
* Not implemented: _IRQL_limited_to_
*/
int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) {
- result = getPotentialExitIrqlAtCfnRaw(cfn)
+ result = getPotentialExitIrqlAtCfnInternal(cfn)
or
- not exists(getPotentialExitIrqlAtCfnRaw(cfn)) and
+ not exists(getPotentialExitIrqlAtCfnInternal(cfn)) and
result = astLevelExitIrqlFallback(cfn)
}
@@ -803,7 +803,7 @@
* `getPotentialExitIrqlAtCfn` instead, which additionally consults
* `astLevelExitIrqlFallback` when this cascade yields no value.
*/
- private int getPotentialExitIrqlAtCfnRaw(ControlFlowNode cfn) {
+ private int getPotentialExitIrqlAtCfnInternal(ControlFlowNode cfn) {
if cfn instanceof KeRaiseIrqlCall
then result = cfn.(KeRaiseIrqlCall).getIrqlLevel()
else
@@ -824,18 +824,18 @@
if
cfn instanceof FunctionCall and
cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction
- then result = getPotentialExitIrqlAtCfnRaw(cfn.getAPredecessor())
+ then result = getPotentialExitIrqlAtCfnInternal(cfn.getAPredecessor())
else
if cfn instanceof FunctionCall
then result = functionExitIrql(cfn.(FunctionCall).getTarget())
else
if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor())
- then result = getPotentialExitIrqlAtCfnRaw(cfn.getAPredecessor())
+ then result = getPotentialExitIrqlAtCfnInternal(cfn.getAPredecessor())
else
if exists(callerPredecessor(cfn.getControlFlowScope()))
then
result =
- getPotentialExitIrqlAtCfnRaw(callerPredecessor(cfn.getControlFlowScope()))
+ getPotentialExitIrqlAtCfnInternal(callerPredecessor(cfn.getControlFlowScope()))
else
if
cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and
@@ -878,7 +878,7 @@
closer.getLocation().getStartLine() < cfnStmt.getLocation().getStartLine() and
closer.getLocation().getStartLine() > prev.getLocation().getStartLine()
) and
- result = getPotentialExitIrqlAtCfnRaw(prev)
+ result = getPotentialExitIrqlAtCfnInternal(prev)
)
}
@@ -1060,4 +1060,44 @@
)
)
)
- }
\ No newline at end of file
+ }
+ /**
+ * Holds if `fc` is a call that may change the IRQL. This includes the
+ * IRQL primitives (KeRaiseIrql, KeLowerIrql, KfRaiseIrql, KfLowerIrql,
+ * etc., recognized via the `Ke*Irql*Call` and `*GlobalIrqlCall`
+ * classes), functions annotated with `_IRQL_raises_` or
+ * `_IRQL_saves_global_` / `_IRQL_restores_global_`, and functions
+ * whose body itself transitively contains an IRQL-changing call (i.e.,
+ * unannotated wrapper helpers).
+ *
+ * The transitive closure over the call graph is necessary to avoid
+ * false negatives where a driver wraps the IRQL primitives in a helper
+ * function without the appropriate SAL annotations.
+ *
+ * Lifted from `IrqlFloatStateMismatch.ql` so other queries (e.g.
+ * `IrqlInconsistentWithRequired`) can use the same soundness check.
+ */
+ predicate isIrqlChangingCall(FunctionCall fc) {
+ fc instanceof KeRaiseIrqlCall
+ or
+ fc instanceof KeLowerIrqlCall
+ or
+ fc instanceof RestoresGlobalIrqlCall
+ or
+ fc instanceof SavesGlobalIrqlCall
+ or
+ isIrqlChangingFunction(fc.getTarget())
+ }
+
+ /**
+ * Holds if `f` directly or transitively contains an IRQL-changing call.
+ * See `isIrqlChangingCall`.
+ */
+ predicate isIrqlChangingFunction(Function f) {
+ f instanceof IrqlChangesFunction
+ or
+ exists(FunctionCall inner |
+ inner.getEnclosingFunction() = f and
+ isIrqlChangingCall(inner)
+ )
+ }
\ No newline at end of file
From 7848c04c85f183ad0323804a9d726da0eb500342 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Wed, 6 May 2026 17:08:41 -0700
Subject: [PATCH 17/19] [AI] Reduce verbosity of AI comments + other cleanup.
---
.../IrqlFloatStateMismatch.md | 12 +-
.../IrqlFloatStateMismatch.qhelp | 71 +++----
.../IrqlFloatStateMismatch.ql | 105 ++++------
.../queries/IrqlSetTooHigh/IrqlSetTooHigh.md | 4 +-
.../IrqlSetTooHigh/IrqlSetTooHigh.qhelp | 33 ++--
.../queries/IrqlTooHigh/IrqlTooHigh.md | 2 +-
.../queries/IrqlTooHigh/IrqlTooHigh.qhelp | 25 ++-
.../general/queries/IrqlTooLow/IrqlTooLow.md | 2 +-
.../queries/IrqlTooLow/IrqlTooLow.qhelp | 25 ++-
src/drivers/libraries/Irql.qll | 186 ++++++++----------
src/drivers/libraries/Page.qll | 35 ++--
src/drivers/libraries/Suppression.qll | 16 +-
.../MultiplePagedCode/MultiplePagedCode.md | 4 +-
.../MultiplePagedCode/MultiplePagedCode.qhelp | 18 +-
.../MultiplePagedCode/driver_snippet.c | 2 +-
15 files changed, 246 insertions(+), 294 deletions(-)
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
index 80a99f6b..187e787c 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.md
@@ -54,11 +54,11 @@ Correct example
* [ C28111 ](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28111-floating-point-irql-mismatch)
## Semmle-specific notes
-**Wrapper / common-caller pattern.** The query reasons about IRQL-changing calls between save and restore not only when both calls share an enclosing function, but also when they sit inside one-level helper wrappers that are called from a common caller (for example, thin `save_fp_helper` / `restore_fp_helper` functions that simply forward to `KeSaveFloatingPointState` / `KeRestoreFloatingPointState`). In those cases the intermediate IRQL transition is searched in the common caller (or in either helper's enclosing function for the asymmetric case where one side is a helper and the other is direct).
+**Wrapper / common-caller pattern.** The query searches for IRQL-changing calls between save and restore in either their shared enclosing function, or — when one or both endpoints sit inside a thin one-level helper (e.g. `save_fp_helper` forwarding to `KeSaveFloatingPointState`) — in the common caller of those helpers.
-**Remaining limitations.** Despite the source-position and AST-loop branches, the predicate still does not detect:
+**Known false negatives:**
-* **IRQL changes performed deep inside helper bodies.** If the helper function itself raises or lowers the IRQL after the save (or before the restore), the change is not visible from the common caller's source-position view, and no intermediate IRQL change is found. Annotating the helper with `_IRQL_raises_` or `_IRQL_saves_global_` makes its IRQL behavior visible without body inspection.
-* **Indirect calls.** IRQL changes performed by an indirect call (function pointer or dispatch-table call) between save and restore are not detected, because the predicate only inspects the static call target.
-* **Loops where the restore is textually before the save.** The AST-loop branch of `irqlChangesBetween` correctly recognises that all three calls (save, restore, and an IRQL-changing call) sit inside the same loop body and would fire on this pattern. However, the upstream IRQL analysis library used to compute the IRQL at the save and restore sites does not consistently bind a value at the argument expression of `KeSaveFloatingPointState` when the call is inside a loop body, so the `irqlSource != irqlSink` filter rejects these cases before `irqlChangesBetween` is consulted. Recovering this true positive requires improvements to the IRQL analysis library and not just to this query.
-* **Wrapper chains longer than one level.** Only one level of wrapping is currently modelled (the helper is called directly from the common caller). Multi-level wrappers require the same annotation hint described above, or a direct call site.
+* **IRQL changes deep inside helper bodies.** If a helper raises/lowers IRQL between its entry and the save/restore primitive it forwards to, that change isn't visible from the common caller. Annotate the helper with `_IRQL_raises_` / `_IRQL_saves_global_` to make its IRQL behavior visible without body inspection.
+* **Indirect calls.** IRQL changes via function pointer or dispatch-table dispatch are not recognized; the predicate inspects only the static call target.
+* **Loops where restore is textually before save.** The AST-loop branch of `irqlChangesBetween` correctly recognizes such patterns, but the upstream IRQL cascade does not always bind at `KeSaveFloatingPointState`'s argument expression inside loop bodies, so the `irqlSource != irqlSink` filter rejects them before this predicate fires. Recovering this case needs work in `Irql.qll`.
+* **Wrapper chains longer than one level.** Only one level of helper wrapping is modelled. Multi-level wrappers need the annotation hint above, or a direct call site.
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
index b950c391..362074ae 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.qhelp
@@ -61,60 +61,49 @@
+
- Wrapper / common-caller pattern. The query reasons about
- IRQL-changing calls between save and restore not only when both
- calls share an enclosing function, but also when they sit inside
- one-level helper wrappers that are called from a common caller
- (for example, thin save_fp_helper /
- restore_fp_helper functions that simply forward to
- KeSaveFloatingPointState /
- KeRestoreFloatingPointState). In those cases the
- intermediate IRQL transition is searched in the common caller
- (or in either helper's enclosing function for the asymmetric case
- where one side is a helper and the other is direct).
+ Wrapper / common-caller pattern. The query searches for
+ IRQL-changing calls between save and restore in either their
+ shared enclosing function, or — when one or both endpoints
+ sit inside a thin one-level helper (e.g.
+ save_fp_helper forwarding to
+ KeSaveFloatingPointState) — in the common
+ caller of those helpers.
- Remaining limitations. Despite the source-position and
- AST-loop branches, the predicate still does not detect:
+ Known false negatives:
-
- IRQL changes performed deep inside helper bodies.
- If the helper function itself raises or lowers the IRQL after
- the save (or before the restore), the change is not visible
- from the common caller's source-position view, and no
- intermediate IRQL change is found. Annotating the helper with
-
_IRQL_raises_ or _IRQL_saves_global_
- makes its IRQL behavior visible without body inspection.
+ IRQL changes deep inside helper bodies. If a helper
+ raises/lowers IRQL between its entry and the save/restore
+ primitive it forwards to, that change isn't visible from
+ the common caller. Annotate the helper with
+ _IRQL_raises_ /
+ _IRQL_saves_global_ to make its IRQL behavior
+ visible without body inspection.
-
- Indirect calls. IRQL changes performed by an indirect
- call (function pointer or dispatch-table call) between save
- and restore are not detected, because the predicate only
- inspects the static call target.
+ Indirect calls. IRQL changes via function pointer or
+ dispatch-table dispatch are not recognized; the predicate
+ inspects only the static call target.
-
- Loops where the restore is textually before the save.
- The AST-loop branch of
irqlChangesBetween
- correctly recognises that all three calls (save, restore,
- and an IRQL-changing call) sit inside the same loop body and
- would fire on this pattern. However, the upstream IRQL
- analysis library used to compute the IRQL at the save and
- restore sites does not consistently bind a value at the
- argument expression of KeSaveFloatingPointState
- when the call is inside a loop body, so the
- irqlSource != irqlSink filter rejects these
- cases before irqlChangesBetween is consulted.
- Recovering this true positive requires improvements to the
- IRQL analysis library and not just to this query.
+ Loops where restore is textually before save. The
+ AST-loop branch of irqlChangesBetween
+ correctly recognizes such patterns, but the upstream IRQL
+ cascade does not always bind at
+ KeSaveFloatingPointState's argument expression
+ inside loop bodies, so the
+ irqlSource != irqlSink filter rejects them
+ before this predicate fires. Recovering this case needs
+ work in Irql.qll.
-
Wrapper chains longer than one level. Only one level
- of wrapping is currently modelled (the helper is called
- directly from the common caller). Multi-level wrappers
- require the same annotation hint described above, or a
- direct call site.
+ of helper wrapping is modelled. Multi-level wrappers need
+ the annotation hint above, or a direct call site.
diff --git a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
index 0c1cb036..1ef306dc 100644
--- a/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
+++ b/src/drivers/general/queries/IrqlFloatStateMismatch/IrqlFloatStateMismatch.ql
@@ -43,6 +43,8 @@ module FloatStateFlowConfig implements DataFlow::ConfigSig {
module FloatStateFlow = DataFlow::Global;
/**
+ * --- AI-generated ---
+ *
* Gets a source line in `f` that anchors `fc` from `f`'s perspective:
*
* - If `fc`'s enclosing function is `f`, the anchor is `fc`'s own
@@ -68,76 +70,53 @@ private int anchorLineForCall(Function f, FunctionCall fc) {
}
/**
- * Holds if there is an IRQL-changing call between `saveCall` and
- * `restoreCall` in some function `f`. This predicate is a sanity filter
- * applied on top of the dataflow result: dataflow has already shown the
- * floating-point buffer flows from `saveCall` to `restoreCall`, and this
- * predicate ensures there is at least one IRQL transition that could
- * actually run between them. Without it the query would emit the pure
- * may-analysis artifact where two save / restore sites are compared at
- * different hypothetical entry IRQLs but no IRQL transition can happen
- * between them at runtime.
+ * --- AI-generated ---
+ *
+ * Holds if some IRQL-changing call could run between `saveCall` and
+ * `restoreCall` at runtime. Used as a sanity filter on top of the
+ * dataflow result: dataflow already paired save -> restore, but
+ * without this filter we'd flag pairs whose hypothetical entry IRQLs
+ * differ even though no actual IRQL transition runs between them.
*
- * Two complementary disjuncts cooperate:
+ * Two additive disjuncts:
*
- * 1. **Source-position branch.** For some `f`, an IRQL-changing call
- * `mid` in `f` lies on a source line bracketed by the anchor lines
- * of `saveCall` and `restoreCall` (see `anchorLineForCall`). The
- * anchor mechanism lets `f` be the directly enclosing function of
- * both calls or a one-level wrapper / common caller, which covers
- * the cross-function case that intra-procedural CFG cannot reach.
+ * 1. **Source-position branch.** A `FunctionCall` `mid` syntactically
+ * inside some `f` has `isIrqlChangingCall(mid)` and lies on a
+ * source line bracketed by `anchorLineForCall(f, save/restoreCall)`.
+ * Two cross-function reach mechanisms with different depth bounds
+ * cooperate: `anchorLineForCall` walks at most one call-graph edge
+ * (we need a concrete line in `f` to anchor each endpoint), but
+ * `isIrqlChangingCall` is transitively recursive through
+ * `isIrqlChangingFunction`, so `mid`'s target can chain through any
+ * number of wrappers before reaching a primitive (`KeRaiseIrql`,
+ * `_IRQL_raises_`, etc.).
*
- * 2. **AST-loop branch.** All three calls (`saveCall`, `restoreCall`,
- * `mid`) sit inside the body of the same loop in their common
- * enclosing function. The loop back-edge means that at runtime
- * each iteration's `restoreCall` can be preceded by the previous
- * iteration's `saveCall` with `mid` between them, so an
- * IRQL-changing `mid` anywhere in the loop body is a real
- * transition between save and restore even when `restoreCall` is
- * textually above `saveCall`. Source-line position alone cannot
- * express this: when the restore is textually earlier than the
- * save the bracketing line range is empty and branch (1) trivially
- * fails.
+ * 2. **AST-loop branch.** All three calls share an enclosing loop body
+ * in the same function. The back-edge makes any IRQL-changing call
+ * in the loop a real transition between save and restore on a
+ * subsequent iteration, including when restore is textually above
+ * save (which makes branch 1's range empty).
*
- * The two branches are disjoint in spirit: branch (1) handles
- * cross-function and acyclic in-function cases; branch (2) handles
- * intra-function loops and re-entrant patterns. Combining them is
- * strictly additive (can only enable more findings, never suppress one
- * that branch (1) would have flagged), so existing true positives are
- * preserved.
+ * We use source-line bracketing rather than CFG reachability because
+ * the extracted cpp CFG can drop forward edges across `if (call(...))`
+ * and similar boundaries, silently losing TPs. The AST relation in
+ * branch 2 is densely populated and avoids that gap.
*
- * Why not full intra-procedural CFG reachability instead of branch (1)?
- * The cpp control-flow graph in some extracted databases does not
- * transitively connect calls across certain statement boundaries (in
- * particular, forward reachability across `if (call(...))` conditions
- * is unreliable in our extracted DBs), which would silently eliminate
- * true positives that branch (1) catches via source-line bracketing.
- * AST-loop containment in branch (2) sidesteps this by relying on the
- * AST `Loop.getStmt().getAChild*()` relation, which is densely
- * populated and reflects the syntactic loop body directly.
+ * Caveat: `getPotentialExitIrqlAtCfn` doesn't always bind at save-call
+ * argument expressions inside loop bodies in current extracted DBs, so
+ * branch 2 can fire correctly while the upstream `irqlSource != irqlSink`
+ * still filters it out. Recovering those needs work in `Irql.qll`.
*
- * Caveat: branch (2) cooperates with `irqlSource != irqlSink` only when
- * the IRQL-analysis library binds `getPotentialExitIrqlAtCfn` at the
- * argument expression of `KeSaveFloatingPointState`. In our current
- * extracted DBs that binding is not always produced for `save` calls
- * inside loop bodies, so some real-world loop true positives may
- * still be filtered out by the upstream IRQL filter even when this
- * predicate fires; recovering those will require improvements to
- * the IRQL analysis library itself.
+ * Performance: `pragma[inline_late]` + `bindingset[saveCall, restoreCall]`
+ * specialize this per call site after dataflow has bound the endpoints,
+ * turning a codebase-wide enumeration of (save, restore) pairs into a
+ * per-pair check. Both annotations are planner hints; semantics unchanged.
*
- * Performance note: `pragma[inline_late]` lets the planner specialize
- * this predicate at its call site after the dataflow result has bound
- * `saveCall` and `restoreCall`. Without it, the body would otherwise
- * be materialized over every (saveCall, restoreCall) pair in the
- * codebase that satisfies the constraints (millions of tuples on
- * large drivers), only to be intersected with a much smaller dataflow
- * result set afterwards. With it, the body is evaluated only for the
- * dataflow-derived pairs, turning a codebase-wide enumeration into a
- * per-pair check. The accompanying `bindingset` records the calling
- * convention required by `inline_late` (both arguments bound at the
- * call site, which is satisfied by the `from` clause below).
- * Semantics are unchanged — both annotations are planner hints, not
- * logical changes.
+ * --- Human comments ---
+ *
+ * Branch (1) wound up like this for perf reasons as well; a transitive
+ * check across all of the helper's internals gets expensive and in practice
+ * if there are helper functions involved they're pretty shallow.
*/
bindingset[saveCall, restoreCall]
pragma[inline_late]
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
index 0a0e26ce..13ddd8fa 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.md
@@ -28,7 +28,5 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
-**Lower-on-exit pattern: known false negative.** When a function has no `_IRQL_always_function_max_` but does carry an `_IRQL_raises_(R)` annotation, the query treats `R` as the implicit ceiling for the function body. A function annotated as both `_IRQL_requires_min_(M)` and `_IRQL_raises_(R)` with `M > R` is interpreted as a "lower IRQL on exit" pattern (for example a wrapper around a mutex or spin-lock release that runs at `DISPATCH_LEVEL` on entry and returns at `PASSIVE_LEVEL`). For these functions the implicit ceiling is suppressed entirely, because `R` describes the exit IRQL rather than a maximum.
-
-This means that a buggy "lower-on-exit" function whose body raises the IRQL above `M` at some intermediate point will *not* be flagged. If the function actually has a maximum that should be enforced along the body, declare it explicitly with `_IRQL_always_function_max_(MAX)` so the query has a concrete ceiling to check against.
+**Lower-on-exit pattern: known false negative.** A function annotated `_IRQL_requires_min_(M)` + `_IRQL_raises_(R)` with `M > R` is treated as "raises only at exit" (e.g. a wrapper around a spin-lock or mutex release that enters at `DISPATCH_LEVEL` and returns at `PASSIVE_LEVEL`): the query suppresses the implicit ceiling so `R` is read as the exit IRQL rather than a body-wide maximum. Consequently a buggy lower-on-exit function whose body raises IRQL above `M` in the middle is not flagged. To enforce a body-wide maximum, declare it explicitly with `_IRQL_always_function_max_(MAX)`.
diff --git a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
index 68ddf1d4..f3b44cb9 100644
--- a/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
+++ b/src/drivers/general/queries/IrqlSetTooHigh/IrqlSetTooHigh.qhelp
@@ -36,26 +36,21 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
- Lower-on-exit pattern: known false negative. When a function has
- no _IRQL_always_function_max_ but does carry an
- _IRQL_raises_(R) annotation, the query treats R
- as the implicit ceiling for the function body. A function annotated as
- both _IRQL_requires_min_(M) and
- _IRQL_raises_(R) with M > R is interpreted
- as a "lower IRQL on exit" pattern (for example a wrapper around a mutex
- or spin-lock release that runs at DISPATCH_LEVEL on entry
- and returns at PASSIVE_LEVEL). For these functions the
- implicit ceiling is suppressed entirely, because R describes
- the exit IRQL rather than a maximum.
-
-
- This means that a buggy "lower-on-exit" function whose body raises the
- IRQL above M at some intermediate point will not be
- flagged. If the function actually has a maximum that should be enforced
- along the body, declare it explicitly with
- _IRQL_always_function_max_(MAX) so the query has a concrete
- ceiling to check against.
+ Lower-on-exit pattern: known false negative. A function
+ annotated _IRQL_requires_min_(M) +
+ _IRQL_raises_(R) with M > R is
+ treated as "raises only at exit" (e.g. a wrapper around a
+ spin-lock or mutex release that enters at
+ DISPATCH_LEVEL and returns at
+ PASSIVE_LEVEL): the query suppresses the
+ implicit ceiling so R is read as the exit IRQL
+ rather than a body-wide maximum. Consequently a buggy
+ lower-on-exit function whose body raises IRQL above
+ M in the middle is not flagged. To enforce a
+ body-wide maximum, declare it explicitly with
+ _IRQL_always_function_max_(MAX).
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
index 98fb34dc..5dc5e8be 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.md
@@ -53,5 +53,5 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
-**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).
+**Dead-branch suppression.** The query suppresses calls inside `if (b)` when `b` is either a compile-time constant `0`, or a non-`static` local initialized to `FALSE`/`0` that is never reassigned, incremented/decremented, or address-taken in the enclosing function. Targets dead-branch patterns from NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`. The variable conditions are deliberately strict to avoid suppressing real findings on globals, function-statics, or values mutated through a pointer parameter.
diff --git a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
index 36f327c5..0dd309d5 100644
--- a/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
+++ b/src/drivers/general/queries/IrqlTooHigh/IrqlTooHigh.qhelp
@@ -60,20 +60,19 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
- Dead-branch suppression. The query suppresses calls inside an
- if (b) block when b is a non-static
- local variable initialized to FALSE / 0 that is
- never mutated (no =, no compound assignment, no
- ++ / --) and whose address is never taken.
- Compile-time constant 0 conditions are also suppressed.
- This is intended to silence dead-branch patterns produced by NDIS
- macros such as FILTER_ACQUIRE_LOCK(lock, bFalse); the
- conditions on the variable case are deliberately conservative to
- avoid silently dropping legitimate findings when the runtime value
- of the variable cannot be proven to remain FALSE
- (globals reassigned in another function, address-taken locals
- mutated through a pointer, compound mutation, etc.).
+ Dead-branch suppression. The query suppresses calls
+ inside if (b) when b is either a
+ compile-time constant 0, or a
+ non-static local initialized to
+ FALSE/0 that is never reassigned,
+ incremented/decremented, or address-taken in the enclosing
+ function. Targets dead-branch patterns from NDIS macros such
+ as FILTER_ACQUIRE_LOCK(lock, bFalse). The
+ variable conditions are deliberately strict to avoid
+ suppressing real findings on globals, function-statics, or
+ values mutated through a pointer parameter.
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
index 769216bd..23fb2c74 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.md
@@ -43,5 +43,5 @@ This query may provide false positives in cases where functions are not annotate
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
-**Dead-branch suppression.** The query suppresses calls inside an `if (b)` block when `b` is a non-`static` local variable initialized to `FALSE` / `0` that is never mutated (no `=`, no compound assignment, no `++` / `--`) and whose address is never taken. Compile-time constant `0` conditions are also suppressed. This is intended to silence dead-branch patterns produced by NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`; the conditions on the variable case are deliberately conservative to avoid silently dropping legitimate findings when the runtime value of the variable cannot be proven to remain `FALSE` (globals reassigned in another function, address-taken locals mutated through a pointer, compound mutation, etc.).
+**Dead-branch suppression.** The query suppresses calls inside `if (b)` when `b` is either a compile-time constant `0`, or a non-`static` local initialized to `FALSE`/`0` that is never reassigned, incremented/decremented, or address-taken in the enclosing function. Targets dead-branch patterns from NDIS macros such as `FILTER_ACQUIRE_LOCK(lock, bFalse)`. The variable conditions are deliberately strict to avoid suppressing real findings on globals, function-statics, or values mutated through a pointer parameter.
diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
index 86c7abe4..a62478d0 100644
--- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
+++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.qhelp
@@ -50,20 +50,19 @@
This query uses interprocedural data-flow analysis and can take a large amount of CPU time and memory to run.
This query may provide false positives in cases where functions are not annotated with their expected IRQL ranges or behaviors.
For information on how to annotate your functions with information about how they adjust the IRQL, see "IRQL annotations for drivers" in the references section.
+
- Dead-branch suppression. The query suppresses calls inside an
- if (b) block when b is a non-static
- local variable initialized to FALSE / 0 that is
- never mutated (no =, no compound assignment, no
- ++ / --) and whose address is never taken.
- Compile-time constant 0 conditions are also suppressed.
- This is intended to silence dead-branch patterns produced by NDIS
- macros such as FILTER_ACQUIRE_LOCK(lock, bFalse); the
- conditions on the variable case are deliberately conservative to
- avoid silently dropping legitimate findings when the runtime value
- of the variable cannot be proven to remain FALSE
- (globals reassigned in another function, address-taken locals
- mutated through a pointer, compound mutation, etc.).
+ Dead-branch suppression. The query suppresses calls
+ inside if (b) when b is either a
+ compile-time constant 0, or a
+ non-static local initialized to
+ FALSE/0 that is never reassigned,
+ incremented/decremented, or address-taken in the enclosing
+ function. Targets dead-branch patterns from NDIS macros such
+ as FILTER_ACQUIRE_LOCK(lock, bFalse). The
+ variable conditions are deliberately strict to avoid
+ suppressing real findings on globals, function-statics, or
+ values mutated through a pointer parameter.
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index bc1e6205..d6cd51f9 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -733,15 +733,18 @@
}
/**
+ * --- AI-generated ---
+ *
* Pre-computed summary: the potential exit IRQL of function `f`,
* computed once per function rather than re-discovered per call site.
*
- * Calls the Raw cascade directly rather than the public wrapper so
- * that this internal building block stays inside a single recursive
+ * Calls the Internal cascade directly rather than the public wrapper
+ * so that this internal building block stays inside a single recursive
* stratum with the cascade. The wrapper layers an AST-level fallback
- * over Raw using a negation, which would otherwise cycle back through
- * here. Equivalent to the historical pre-wrapper behaviour because
- * the wrapper agrees with Raw on every input where Raw binds.
+ * over Internal using a negation, which would otherwise cycle back
+ * through here. Equivalent to the historical pre-wrapper behaviour
+ * because the wrapper agrees with Internal on every input where
+ * Internal binds.
*/
pragma[nomagic]
private int functionExitIrql(Function f) {
@@ -749,6 +752,8 @@
}
/**
+ * --- AI-generated ---
+ *
* Gets the set of predecessor nodes from callers for function `callee`.
* This pre-computes the reverse call-graph edge for interprocedural analysis
* and is restricted to actual call sites.
@@ -772,18 +777,14 @@
* - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function.
* - Failing all this, we set the IRQL to 0.
*
- * Layering note: this public predicate wraps the recursive cascade
- * `getPotentialExitIrqlAtCfnRaw` with a single AST-level fallback
- * (`astLevelExitIrqlFallback`) that activates only when the cascade
- * yields no value at all. The fallback walks one source-line step
- * back to the closest preceding sibling Stmt and returns the cascade's
- * IRQL there. This recovers binding for argument-expression CFNs of
- * function calls inside loop bodies, where the cpp CFG in some
- * extracted databases is too sparse for the cascade's predecessor walk
- * to converge. The fallback is restricted to CFNs inside loop bodies
- * (the empirical failure mode), keeping it from over-approximating on
- * linear branching code where the cascade's silence may be hiding
- * IRQL-changing work that an AST-level scan cannot see. When the
+ * --- AI-generated (layering note) ---
+ *
+ * Layering: this wraps the recursive cascade
+ * `getPotentialExitIrqlAtCfnInternal` with `astLevelExitIrqlFallback`,
+ * which fires only when the cascade binds nothing. The fallback walks
+ * one source-line step back to the nearest preceding sibling Stmt, and
+ * is restricted to CFNs inside loop bodies (the empirical failure
+ * mode for argument-expression CFNs reached via a back-edge). When the
* cascade already binds, this wrapper returns exactly the cascade's
* result set: the fallback never widens an existing binding.
*
@@ -797,6 +798,8 @@
}
/**
+ * --- AI-generated ---
+ *
* Internal recursive cascade for `getPotentialExitIrqlAtCfn`. Behaves
* exactly like the historical `getPotentialExitIrqlAtCfn` did before
* the AST fallback wrapper was introduced. Callers should use
@@ -845,27 +848,22 @@
}
/**
- * AST-level fallback for `getPotentialExitIrqlAtCfn`. Walks to the
- * closest source-line preceding sibling Stmt of `cfn`'s enclosing Stmt
- * (within the same parent Stmt) and returns the cascade's IRQL there.
- * Yields no value when there is no preceding sibling at the same
- * nesting level (e.g. `cfn` is the first stmt in its block) or when
- * the cascade also yields no value at that sibling.
+ * --- AI-generated ---
+ *
+ * AST-level fallback for `getPotentialExitIrqlAtCfn`. Returns the
+ * cascade's IRQL at the closest preceding sibling Stmt of `cfn`'s
+ * enclosing Stmt within the same parent. No value when there is no
+ * preceding sibling, or when the cascade is also silent there.
*
- * Restricted to CFNs whose enclosing Stmt sits inside a loop body. The
- * cascade's CFG-predecessor walk is reliable on linear control flow but
- * empirically can fail to bind on argument-expression CFNs of function
- * calls reached via a loop back-edge; this fallback exists to recover
- * binding for that specific case. Restricting to loops avoids
- * supplying coarse single-value approximations on linear code where the
- * cascade's silence (when it does occur) often reflects branching that
- * the AST-level scan cannot reason about (e.g. an if-stmt whose body
- * raises and lowers IRQL).
+ * Restricted to CFNs inside a loop body — that's the empirical
+ * failure mode where the cascade's predecessor walk doesn't bind on
+ * argument-expression CFNs reached via a loop back-edge. Outside
+ * loops, the cascade's silence often reflects branching the AST scan
+ * can't see (e.g. an if-stmt whose body raises and lowers IRQL), so
+ * we don't fall back there.
*
- * Consulted by `getPotentialExitIrqlAtCfn` only when the cascade
- * returns no value at all, so this never widens an existing binding;
- * it only fills in silence with a single conservative IRQL value
- * derived from textually-preceding code in the loop body.
+ * Consulted by `getPotentialExitIrqlAtCfn` only when the cascade is
+ * silent; never widens an existing binding.
*/
private int astLevelExitIrqlFallback(ControlFlowNode cfn) {
exists(Stmt cfnStmt, Stmt prev, Loop l |
@@ -1000,38 +998,26 @@
}
/**
- * Holds if `call` is located inside the "then" branch of an `if` statement
- * whose condition is a compile-time-constant `FALSE` (0) value, or a
- * non-`static` local variable that is initialized to `0` / `FALSE`,
- * never assigned (with any assignment operator) or incremented /
- * decremented in the enclosing function, and whose address is never
- * taken.
+ * --- AI-generated ---
+ *
+ * Holds if `call` sits in the "then" branch of an `if` whose
+ * condition is either a compile-time-constant 0/FALSE, or a
+ * non-static local variable initialized to 0/FALSE that is never
+ * reassigned, incremented, or address-taken in the enclosing
+ * function.
*
- * This detects patterns like:
+ * Detects e.g.:
* ```
* BOOLEAN bFalse = FALSE;
* if (bFalse) { KeAcquireSpinLockAtDpcLevel(...); } // dead branch
* ```
- * Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK, etc.).
+ * Common in NDIS macros (FILTER_ACQUIRE_LOCK, NPROT_ACQUIRE_LOCK).
*
- * The conservative-by-default conditions on the variable case avoid
- * silently dropping legitimate findings when the runtime value of the
- * variable cannot be proven to remain `FALSE`:
- *
- * - `LocalVariable v` excludes file-scope and namespace globals,
- * which can be reassigned from any other function in the
- * translation unit (or even another TU).
- * - `not v.isStatic()` excludes function-static variables, whose
- * value persists across calls and could be set by a previous
- * invocation.
- * - The `Assignment` predicate matches plain `=` (`AssignExpr`) and
- * all compound operators (`AssignOperation`: `|=`, `&=`, `+=`,
- * etc.); the original `AssignExpr`-only check was too narrow.
- * - `CrementOperation` covers `++` and `--`, which are not modeled
- * as assignments in the cpp library.
- * - Bailing out when the variable's address is taken
- * (`AddressOfExpr`) prevents missing mutations performed by
- * callees through a pointer (e.g., `SetFlag(&bFalse)`).
+ * The strict mutation checks (LocalVariable, !isStatic, Assignment
+ * matching `=` and compound ops, CrementOperation, no AddressOfExpr)
+ * exist so we don't suppress findings when the variable could
+ * plausibly hold a non-FALSE value at runtime — i.e. globals,
+ * function-statics, or values written through a pointer parameter.
*/
predicate isInConstantFalseBranch(FunctionCall call) {
exists(IfStmt ifStmt |
@@ -1060,44 +1046,40 @@
)
)
)
- }
- /**
- * Holds if `fc` is a call that may change the IRQL. This includes the
- * IRQL primitives (KeRaiseIrql, KeLowerIrql, KfRaiseIrql, KfLowerIrql,
- * etc., recognized via the `Ke*Irql*Call` and `*GlobalIrqlCall`
- * classes), functions annotated with `_IRQL_raises_` or
- * `_IRQL_saves_global_` / `_IRQL_restores_global_`, and functions
- * whose body itself transitively contains an IRQL-changing call (i.e.,
- * unannotated wrapper helpers).
- *
- * The transitive closure over the call graph is necessary to avoid
- * false negatives where a driver wraps the IRQL primitives in a helper
- * function without the appropriate SAL annotations.
- *
- * Lifted from `IrqlFloatStateMismatch.ql` so other queries (e.g.
- * `IrqlInconsistentWithRequired`) can use the same soundness check.
- */
- predicate isIrqlChangingCall(FunctionCall fc) {
- fc instanceof KeRaiseIrqlCall
- or
- fc instanceof KeLowerIrqlCall
- or
- fc instanceof RestoresGlobalIrqlCall
- or
- fc instanceof SavesGlobalIrqlCall
- or
- isIrqlChangingFunction(fc.getTarget())
- }
-
- /**
- * Holds if `f` directly or transitively contains an IRQL-changing call.
- * See `isIrqlChangingCall`.
- */
- predicate isIrqlChangingFunction(Function f) {
- f instanceof IrqlChangesFunction
- or
- exists(FunctionCall inner |
- inner.getEnclosingFunction() = f and
- isIrqlChangingCall(inner)
- )
+ }
+ /**
+ * --- AI-generated ---
+ *
+ * Holds if `fc` is a call that may change the IRQL: an IRQL primitive
+ * (`Ke*Irql*Call`, `*GlobalIrqlCall`), a function annotated
+ * `_IRQL_raises_` / `_IRQL_saves_global_` / `_IRQL_restores_global_`,
+ * or any function whose body transitively contains such a call. The
+ * transitive closure catches unannotated wrapper helpers. Lifted from
+ * IFSM.ql so other queries (e.g. IIWR) can use the same soundness check.
+ */
+ predicate isIrqlChangingCall(FunctionCall fc) {
+ fc instanceof KeRaiseIrqlCall
+ or
+ fc instanceof KeLowerIrqlCall
+ or
+ fc instanceof RestoresGlobalIrqlCall
+ or
+ fc instanceof SavesGlobalIrqlCall
+ or
+ isIrqlChangingFunction(fc.getTarget())
+ }
+
+ /**
+ * --- AI-generated ---
+ *
+ * Holds if `f` directly or transitively contains an IRQL-changing call.
+ * See `isIrqlChangingCall`.
+ */
+ predicate isIrqlChangingFunction(Function f) {
+ f instanceof IrqlChangesFunction
+ or
+ exists(FunctionCall inner |
+ inner.getEnclosingFunction() = f and
+ isIrqlChangingCall(inner)
+ )
}
\ No newline at end of file
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index e13d284a..e6c97901 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -106,6 +106,8 @@ class PagedFunctionDeclaration extends Function {
}
/**
+ * --- AI-generated ---
+ *
* A `PAGED_CODE` or `PAGED_CODE_LOCKED` macro invocation that sits inside
* a `PagedFunctionDeclaration`. Pre-filtering the population at the class
* level (rather than as joined `where`-clause predicates) lets the optimizer
@@ -118,27 +120,22 @@ class PagedCodeMacro extends MacroInvocation {
}
/**
- * Gets a paged enclosing function for this macro invocation, including
- * `FunctionTemplateInstantiation` results when the macro lives inside a
- * templated function body. Each instantiation is a distinct `Function`,
- * so two `PagedCodeMacro` invocations are guaranteed to "share" one of
- * these results only when they are inside the same instantiation body
- * (not merely two ODR-equivalent template entities that the extractor
- * may consolidate).
+ * --- AI-generated ---
*
- * Routed through `getStmt()` rather than the stock
- * `MacroInvocation.getEnclosingFunction()` to avoid the expensive
- * `getAnAffectedElement` join on large codebases. `PAGED_CODE` /
- * `PAGED_CODE_LOCKED` always expand to a statement-form
- * `NT_ASSERT_ASSUME(...)`, so `getStmt()` is well-defined.
+ * Gets the paged enclosing function for this macro invocation,
+ * including template instantiations.
*
- * NB: callers that need to compare two macro invocations for "same
- * source-level function" must also require the macros and the
- * enclosing function to agree on `getFile()`. The cpp extractor
- * sometimes consolidates two ODR-equivalent template definitions in
- * different headers into a single `TemplateFunction` /
- * `FunctionTemplateInstantiation` entity, which would otherwise allow
- * a macro in one header to match an enclosing function in another.
+ * Routed through `getStmt()` (which always binds for `PAGED_CODE` /
+ * `PAGED_CODE_LOCKED`, since they expand to a stmt-form
+ * `NT_ASSERT_ASSUME`) to avoid the expensive `getAnAffectedElement`
+ * join used by the stock `MacroInvocation.getEnclosingFunction()`.
+ *
+ * NB: to compare two `PagedCodeMacro` invocations for "same
+ * source-level function", also require `getFile()` agreement —
+ * the extractor sometimes consolidates ODR-equivalent template
+ * definitions across headers into a single `Function` entity, which
+ * would otherwise allow a macro in one header to match an enclosing
+ * function in another.
*/
Function getEnclosingPagedFunction() {
result = this.getStmt().getEnclosingFunction() and
diff --git a/src/drivers/libraries/Suppression.qll b/src/drivers/libraries/Suppression.qll
index cf8f3b59..6ce949a7 100644
--- a/src/drivers/libraries/Suppression.qll
+++ b/src/drivers/libraries/Suppression.qll
@@ -3,6 +3,8 @@
import cpp
/**
+ * --- AI-generated ---
+ *
* Gets the minimum start line of a non-suppression Locatable in `f` that is
* strictly after `afterLine`. Pre-computing distinct lines avoids iterating
* over every Locatable individually in the aggregate.
@@ -22,6 +24,8 @@ private int nextNonSuppressionLine(File f, int afterLine) {
}
/**
+ * --- AI-generated ---
+ *
* Holds if `d` is a DisablePragma that falls within SuppressionPushPopSegment `s`.
*/
pragma[nomagic]
@@ -32,6 +36,8 @@ private predicate disableInSegment(DisablePragma d, SuppressionPushPopSegment s)
}
/**
+ * --- AI-generated ---
+ *
* Holds if `d` is a DisablePragma that is inside at least one push/pop segment.
*/
pragma[nomagic]
@@ -40,6 +46,8 @@ private predicate disableHasSegment(DisablePragma d) {
}
/**
+ * --- AI-generated ---
+ *
* Holds if a Location in file `f` spanning `startLine` to `endLine`
* falls inside at least one push/pop segment.
*/
@@ -75,6 +83,8 @@ abstract class CASuppression extends PreprocessorPragma {
abstract predicate appliesToLocation(Location l);
/**
+ * --- AI-generated ---
+ *
* Gets the scope of this suppression as a line range within a file.
* This is used by `hasLocationInfo` to define where the suppression applies
* without enumerating every Location in the database.
@@ -177,9 +187,11 @@ abstract class CASuppression extends PreprocessorPragma {
}
}
-/** Represents the scope covered by a given CA supression. */
+/** Represents the scope covered by a given CA suppression. */
class CASuppressionScope extends ElementBase instanceof CASuppression {
/**
+ * --- AI-generated ---
+ *
* Defines the location range covered by this suppression scope.
* Instead of iterating all Location objects, this uses pre-computed scope bounds
* to return the bounding box of the suppression region directly.
@@ -291,6 +303,8 @@ class DisablePragma extends CASuppression {
}
/**
+ * --- AI-generated ---
+ *
* The scope of a disable pragma: from the disable line to either the end of the
* enclosing push/pop segment, or the end of the file.
* Returns a single bounding range rather than enumerating every Location.
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
index fd899a3b..923ae1f1 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.md
@@ -13,7 +13,7 @@ Remove all but one PAGED_CODE OR PAGED_CODE_LOCKED macro.
// Licensed under the MIT license.
-//Macros to enable or disable a code section that may or maynot conflict with this test.
+// Macros to enable or disable a code section that may or may not conflict with this test.
#define SET_DISPATCH 1
#define SET_PAGE_CODE 1
@@ -74,5 +74,5 @@ DispatchShutdown (
* [ C28171 warning - Windows Drivers ](https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/28171-function-has-more-than-one-page-macro-instance)
## Semmle-specific notes
-**C++ function template support.** When the same source-level `PAGED_CODE` macro is expanded into multiple `FunctionTemplateInstantiation` bodies, the query collapses all instantiations of a single source-level template into one match key (via the underlying `TemplateFunction`) so duplicates inside a templated paged function body are reported once at the source-level location. Specialisations and non-template-paged functions are excluded.
+**C++ function template support.** When the same source-level `PAGED_CODE` is expanded into multiple template instantiations, the query collapses all instantiations into a single match key (via the underlying `TemplateFunction`) so a duplicate inside a templated paged function body is reported once at the source-level location. Specialisations and non-template paged functions are excluded.
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
index 60f16dc6..502c7025 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
+++ b/src/drivers/wdm/queries/MultiplePagedCode/MultiplePagedCode.qhelp
@@ -22,16 +22,16 @@
+
- C++ function template support. When the same source-level
- PAGED_CODE macro is expanded into multiple
- FunctionTemplateInstantiation bodies, the query
- collapses all instantiations of a single source-level template
- into one match key (via the underlying
- TemplateFunction) so duplicates inside a templated
- paged function body are reported once at the source-level
- location. Specialisations and non-template-paged functions are
- excluded.
+ C++ function template support. When the same
+ source-level PAGED_CODE is expanded into multiple
+ template instantiations, the query collapses all
+ instantiations into a single match key (via the underlying
+ TemplateFunction) so a duplicate inside a
+ templated paged function body is reported once at the
+ source-level location. Specialisations and non-template
+ paged functions are excluded.
diff --git a/src/drivers/wdm/queries/MultiplePagedCode/driver_snippet.c b/src/drivers/wdm/queries/MultiplePagedCode/driver_snippet.c
index 4bc016a1..7af85a9f 100644
--- a/src/drivers/wdm/queries/MultiplePagedCode/driver_snippet.c
+++ b/src/drivers/wdm/queries/MultiplePagedCode/driver_snippet.c
@@ -2,7 +2,7 @@
// Licensed under the MIT license.
-//Macros to enable or disable a code section that may or maynot conflict with this test.
+// Macros to enable or disable a code section that may or may not conflict with this test.
#define SET_DISPATCH 1
#define SET_PAGE_CODE 1
From 92c933ed8376cbab61b8af86df899e27fec584d9 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Thu, 7 May 2026 14:15:43 -0700
Subject: [PATCH 18/19] Refactor a Supression predicate into a class
---
src/drivers/libraries/Suppression.qll | 43 +++++++++++++--------------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/src/drivers/libraries/Suppression.qll b/src/drivers/libraries/Suppression.qll
index 6ce949a7..6a3231ea 100644
--- a/src/drivers/libraries/Suppression.qll
+++ b/src/drivers/libraries/Suppression.qll
@@ -2,27 +2,6 @@
// Licensed under the MIT license.
import cpp
-/**
- * --- AI-generated ---
- *
- * Gets the minimum start line of a non-suppression Locatable in `f` that is
- * strictly after `afterLine`. Pre-computing distinct lines avoids iterating
- * over every Locatable individually in the aggregate.
- */
-pragma[nomagic]
-private int nextNonSuppressionLine(File f, int afterLine) {
- afterLine = any(SuppressPragma sp | sp.getFile() = f).getLocation().getEndLine() and
- result =
- min(int line |
- exists(Locatable l |
- l.getFile() = f and
- not l instanceof CASuppression and
- line = l.getLocation().getStartLine() and
- line > afterLine
- )
- )
-}
-
/**
* --- AI-generated ---
*
@@ -256,10 +235,30 @@ class SuppressPragma extends CASuppression {
pragma[nomagic]
int getMinimumLocationOffset() {
exists(int nextLine |
- nextLine = nextNonSuppressionLine(this.getFile(), this.getLocation().getEndLine()) and
+ nextLine = nextNonSuppressionLine() and
result = nextLine - this.getLocation().getEndLine()
)
}
+
+ /**
+ * --- AI-generated ---
+ *
+ * Gets the minimum start line of a non-suppression Locatable in `f` that is
+ * strictly after `afterLine`. Pre-computing distinct lines avoids iterating
+ * over every Locatable individually in the aggregate.
+ */
+ pragma[nomagic]
+ private int nextNonSuppressionLine() {
+ result =
+ min(int line |
+ exists(Locatable l |
+ l.getFile() = this.getFile() and
+ not l instanceof CASuppression and
+ line = l.getLocation().getStartLine() and
+ line > this.getLocation().getEndLine()
+ )
+ )
+ }
}
/**
From 4bc222c7ce7f707508701af5e516de5a59867562 Mon Sep 17 00:00:00 2001
From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
Date: Thu, 7 May 2026 16:32:54 -0700
Subject: [PATCH 19/19] Address a few more review comments
---
src/drivers/libraries/Irql.qll | 1 -
src/drivers/libraries/Page.qll | 14 +++++++-------
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll
index d6cd51f9..34ce9267 100644
--- a/src/drivers/libraries/Irql.qll
+++ b/src/drivers/libraries/Irql.qll
@@ -13,7 +13,6 @@
*/
import cpp
- import semmle.code.cpp.controlflow.Dominance
import drivers.libraries.SAL
import drivers.wdm.libraries.WdmDrivers
import drivers.libraries.IrqlDataFlow
diff --git a/src/drivers/libraries/Page.qll b/src/drivers/libraries/Page.qll
index e6c97901..a2f3c827 100644
--- a/src/drivers/libraries/Page.qll
+++ b/src/drivers/libraries/Page.qll
@@ -113,10 +113,16 @@ class PagedFunctionDeclaration extends Function {
* level (rather than as joined `where`-clause predicates) lets the optimizer
* materialize a small relation and avoid the full
* `MacroInvocation x MacroInvocation` Cartesian product on large corpora.
+ *
+ * Routed through `getStmt()` (which always binds for `PAGED_CODE` /
+ * `PAGED_CODE_LOCKED`, since they expand to a stmt-form
+ * `NT_ASSERT_ASSUME`) to avoid the expensive `getAnAffectedElement`
+ * join used by the stock `MacroInvocation.getEnclosingFunction()`.
*/
class PagedCodeMacro extends MacroInvocation {
PagedCodeMacro() {
this.getMacroName() = ["PAGED_CODE", "PAGED_CODE_LOCKED"]
+ and this.getStmt().getEnclosingFunction() instanceof PagedFunctionDeclaration
}
/**
@@ -125,11 +131,6 @@ class PagedCodeMacro extends MacroInvocation {
* Gets the paged enclosing function for this macro invocation,
* including template instantiations.
*
- * Routed through `getStmt()` (which always binds for `PAGED_CODE` /
- * `PAGED_CODE_LOCKED`, since they expand to a stmt-form
- * `NT_ASSERT_ASSUME`) to avoid the expensive `getAnAffectedElement`
- * join used by the stock `MacroInvocation.getEnclosingFunction()`.
- *
* NB: to compare two `PagedCodeMacro` invocations for "same
* source-level function", also require `getFile()` agreement —
* the extractor sometimes consolidates ODR-equivalent template
@@ -138,7 +139,6 @@ class PagedCodeMacro extends MacroInvocation {
* function in another.
*/
Function getEnclosingPagedFunction() {
- result = this.getStmt().getEnclosingFunction() and
- result instanceof PagedFunctionDeclaration
+ result = this.getStmt().getEnclosingFunction()
}
}