Merge branch 'main' into java/refactor-dataflow-queries-1

This commit is contained in:
Anders Schack-Mulligen
2023-03-10 12:38:06 +01:00
committed by GitHub
777 changed files with 15815 additions and 10885 deletions

View File

@@ -1,5 +1,6 @@
using Xunit;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Collections.Generic;
using System;
using System.Linq;
@@ -75,6 +76,15 @@ namespace Semmle.Autobuild.Cpp.Tests
throw new ArgumentException("Missing RunProcess " + pattern);
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var ret = (this as IBuildActions).RunProcess(cmd, args, workingDirectory, env, out var stdout);
stdout.ForEach(line => onOutput(line));
return ret;
}
public IList<string> DirectoryDeleteIn = new List<string>();
void IBuildActions.DirectoryDelete(string dir, bool recursive)
@@ -184,6 +194,15 @@ namespace Semmle.Autobuild.Cpp.Tests
if (!DownloadFiles.Contains((address, fileName)))
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
}
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new TestDiagnosticWriter();
}
internal class TestDiagnosticWriter : IDiagnosticsWriter
{
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
}
/// <summary>
@@ -243,6 +262,7 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_DIAGNOSTIC_DIR"] = "";
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64";
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";

View File

@@ -1,4 +1,5 @@
using Semmle.Autobuild.Shared;
using Semmle.Util;
namespace Semmle.Autobuild.Cpp
{
@@ -21,7 +22,7 @@ namespace Semmle.Autobuild.Cpp
public class CppAutobuilder : Autobuilder<CppAutobuildOptions>
{
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options) { }
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options, new DiagnosticClassifier()) { }
public override BuildScript GetBuildScript()
{

View File

@@ -1,3 +1,7 @@
## 0.5.4
No user-facing changes.
## 0.5.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.5.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.5.3
lastReleaseVersion: 0.5.4

View File

@@ -456,6 +456,7 @@ module Impl<FullStateConfigSig Config> {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
pragma[assume_small_delta]
private predicate fwdFlow(NodeEx node, Cc cc) {
sourceNode(node, _) and
if hasSourceCallCtx() then cc = true else cc = false

View File

@@ -7,7 +7,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
DataFlowInternal::FullStateConfigSig
{
import Config
predicate isBarrier(DataFlow::Node node) {

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.5.4-dev
version: 0.5.5-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -186,7 +186,7 @@ class Declaration extends Locatable, @declaration {
predicate hasDefinition() { exists(this.getDefinition()) }
/** DEPRECATED: Use `hasDefinition` instead. */
predicate isDefined() { this.hasDefinition() }
deprecated predicate isDefined() { this.hasDefinition() }
/** Gets the preferred location of this declaration, if any. */
override Location getLocation() { none() }
@@ -619,11 +619,10 @@ private class DirectAccessHolder extends Element {
/**
* Like `couldAccessMember` but only contains derivations in which either
* (5.2), (5.3) or (5.4) must be invoked. In other words, the `this`
* parameter is not ignored. This restriction makes it feasible to fully
* enumerate this predicate even on large code bases. We check for 11.4 as
* part of (5.3), since this further limits the number of tuples produced by
* this predicate.
* parameter is not ignored. We check for 11.4 as part of (5.3), since
* this further limits the number of tuples produced by this predicate.
*/
pragma[inline]
predicate thisCouldAccessMember(Class memberClass, AccessSpecifier memberAccess, Class derived) {
// Only (5.4) is recursive, and chains of invocations of (5.4) can always
// be collapsed to one invocation by the transitivity of 11.2/4.
@@ -665,7 +664,9 @@ private class DirectAccessHolder extends Element {
// bypasses `p`. Then that path must be public, or we are in case 2.
exists(AccessSpecifier public | public.hasName("public") |
exists(Class between, Class p |
between.accessOfBaseMember(memberClass, memberAccess).hasName("protected") and
between
.accessOfBaseMember(pragma[only_bind_into](memberClass), memberAccess)
.hasName("protected") and
this.isFriendOfOrEqualTo(p) and
(
// This is case 1 from above. If `p` derives privately from `between`

View File

@@ -41,7 +41,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
* template on the first line would be `min<T>(T, T) -> T`.
*/
string getFullSignature() {
deprecated string getFullSignature() {
exists(string name, string templateArgs, string args |
result = name + templateArgs + args + " -> " + this.getType().toString() and
name = this.getQualifiedName() and

View File

@@ -159,7 +159,8 @@ class NameQualifyingElement extends Element, @namequalifyingelement {
* A special name-qualifying element. For example: `__super`.
*/
library class SpecialNameQualifyingElement extends NameQualifyingElement,
@specialnamequalifyingelement {
@specialnamequalifyingelement
{
/** Gets the name of this special qualifying element. */
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }

View File

@@ -12,7 +12,9 @@ predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunctio
*
* DEPRECATED: Use `DeallocationExpr` instead (this also includes `delete` expressions).
*/
predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getFreedExpr() }
deprecated predicate freeCall(FunctionCall fc, Expr arg) {
arg = fc.(DeallocationExpr).getFreedExpr()
}
/**
* Is e some kind of allocation or deallocation (`new`, `alloc`, `realloc`, `delete`, `free` etc)?

View File

@@ -456,6 +456,7 @@ module Impl<FullStateConfigSig Config> {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
pragma[assume_small_delta]
private predicate fwdFlow(NodeEx node, Cc cc) {
sourceNode(node, _) and
if hasSourceCallCtx() then cc = true else cc = false

View File

@@ -7,7 +7,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
DataFlowInternal::FullStateConfigSig
{
import Config
predicate isBarrier(DataFlow::Node node) {

View File

@@ -569,7 +569,8 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation,
* ```
*/
class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
@istriviallyconstructibleexpr {
@istriviallyconstructibleexpr
{
override string toString() { result = "__is_trivially_constructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" }
@@ -619,7 +620,8 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow
* bool v = __is_trivially_destructible(MyType);
* ```
*/
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr {
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr
{
override string toString() { result = "__is_trivially_destructible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" }
@@ -738,7 +740,8 @@ class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr
* ```
*/
class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
@hastrivialmoveconstructorexpr {
@hastrivialmoveconstructorexpr
{
override string toString() { result = "__has_trivial_move_constructor" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
@@ -1034,7 +1037,8 @@ class BuiltInOperationIsAggregate extends BuiltInOperation, @isaggregate {
* ```
*/
class BuiltInOperationHasUniqueObjectRepresentations extends BuiltInOperation,
@hasuniqueobjectrepresentations {
@hasuniqueobjectrepresentations
{
override string toString() { result = "__has_unique_object_representations" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUniqueObjectRepresentations" }
@@ -1107,7 +1111,8 @@ class BuiltInOperationIsLayoutCompatible extends BuiltInOperation, @islayoutcomp
* ```
*/
class BuiltInOperationIsPointerInterconvertibleBaseOf extends BuiltInOperation,
@ispointerinterconvertiblebaseof {
@ispointerinterconvertiblebaseof
{
override string toString() { result = "__is_pointer_interconvertible_base_of" }
override string getAPrimaryQlClass() {

View File

@@ -456,6 +456,7 @@ module Impl<FullStateConfigSig Config> {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
pragma[assume_small_delta]
private predicate fwdFlow(NodeEx node, Cc cc) {
sourceNode(node, _) and
if hasSourceCallCtx() then cc = true else cc = false

View File

@@ -7,7 +7,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
DataFlowInternal::FullStateConfigSig
{
import Config
predicate isBarrier(DataFlow::Node node) {

View File

@@ -1082,7 +1082,8 @@ module Opcode {
* See the `CallSideEffectInstruction` documentation for more details.
*/
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect {
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect
{
final override string toString() { result = "CallSideEffect" }
}
@@ -1092,7 +1093,8 @@ module Opcode {
* See the `CallReadSideEffectInstruction` documentation for more details.
*/
class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode,
TCallReadSideEffect {
TCallReadSideEffect
{
final override string toString() { result = "CallReadSideEffect" }
}
@@ -1102,7 +1104,8 @@ module Opcode {
* See the `IndirectReadSideEffectInstruction` documentation for more details.
*/
class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode,
TIndirectReadSideEffect {
TIndirectReadSideEffect
{
final override string toString() { result = "IndirectReadSideEffect" }
}
@@ -1112,7 +1115,8 @@ module Opcode {
* See the `IndirectMustWriteSideEffectInstruction` documentation for more details.
*/
class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
TIndirectMustWriteSideEffect {
TIndirectMustWriteSideEffect
{
final override string toString() { result = "IndirectMustWriteSideEffect" }
}
@@ -1122,7 +1126,8 @@ module Opcode {
* See the `IndirectMayWriteSideEffectInstruction` documentation for more details.
*/
class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
MayWriteOpcode, TIndirectMayWriteSideEffect {
MayWriteOpcode, TIndirectMayWriteSideEffect
{
final override string toString() { result = "IndirectMayWriteSideEffect" }
}
@@ -1132,7 +1137,8 @@ module Opcode {
* See the `BufferReadSideEffectInstruction` documentation for more details.
*/
class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode,
TBufferReadSideEffect {
TBufferReadSideEffect
{
final override string toString() { result = "BufferReadSideEffect" }
}
@@ -1142,7 +1148,8 @@ module Opcode {
* See the `BufferMustWriteSideEffectInstruction` documentation for more details.
*/
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
TBufferMustWriteSideEffect {
TBufferMustWriteSideEffect
{
final override string toString() { result = "BufferMustWriteSideEffect" }
}
@@ -1152,7 +1159,8 @@ module Opcode {
* See the `BufferMayWriteSideEffectInstruction` documentation for more details.
*/
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
MayWriteOpcode, TBufferMayWriteSideEffect {
MayWriteOpcode, TBufferMayWriteSideEffect
{
final override string toString() { result = "BufferMayWriteSideEffect" }
}
@@ -1162,7 +1170,8 @@ module Opcode {
* See the `SizedBufferReadSideEffectInstruction` documentation for more details.
*/
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode,
TSizedBufferReadSideEffect {
TSizedBufferReadSideEffect
{
final override string toString() { result = "SizedBufferReadSideEffect" }
}
@@ -1172,7 +1181,8 @@ module Opcode {
* See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details.
*/
class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
TSizedBufferMustWriteSideEffect {
TSizedBufferMustWriteSideEffect
{
final override string toString() { result = "SizedBufferMustWriteSideEffect" }
}
@@ -1182,7 +1192,8 @@ module Opcode {
* See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details.
*/
class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
MayWriteOpcode, TSizedBufferMayWriteSideEffect {
MayWriteOpcode, TSizedBufferMayWriteSideEffect
{
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
}
@@ -1192,7 +1203,8 @@ module Opcode {
* See the `InitializeDynamicAllocationInstruction` documentation for more details.
*/
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
TInitializeDynamicAllocation {
TInitializeDynamicAllocation
{
final override string toString() { result = "InitializeDynamicAllocation" }
}
@@ -1221,7 +1233,8 @@ module Opcode {
* See the `InlineAsmInstruction` documentation for more details.
*/
class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode,
MayReadOpcode, TInlineAsm {
MayReadOpcode, TInlineAsm
{
final override string toString() { result = "InlineAsm" }
final override predicate hasOperandInternal(OperandTag tag) {

View File

@@ -246,7 +246,8 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
}
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
AllocationMemoryLocation {
AllocationMemoryLocation
{
EntireAllocationMemoryLocation() { this = TEntireAllocationMemoryLocation(var, isMayAccess) }
final override string toStringInternal() { result = var.toString() }

View File

@@ -511,7 +511,8 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
* calls other than constructor calls.
*/
class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
TTranslatedArgumentExprSideEffect {
TTranslatedArgumentExprSideEffect
{
Expr arg;
TranslatedArgumentExprSideEffect() {
@@ -546,7 +547,8 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
* calls to non-static member functions.
*/
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
TTranslatedStructorQualifierSideEffect {
TTranslatedStructorQualifierSideEffect
{
TranslatedStructorQualifierSideEffect() {
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
index = -1

View File

@@ -34,7 +34,8 @@ abstract class TranslatedCondition extends TranslatedElement {
}
abstract class TranslatedFlexibleCondition extends TranslatedCondition, ConditionContext,
TTranslatedFlexibleCondition {
TTranslatedFlexibleCondition
{
TranslatedFlexibleCondition() { this = TTranslatedFlexibleCondition(expr) }
final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }

View File

@@ -75,7 +75,8 @@ abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInit
* The IR translation of a local variable declaration within a declaration statement.
*/
class TranslatedAutoVariableDeclarationEntry extends TranslatedLocalVariableDeclaration,
TranslatedDeclarationEntry {
TranslatedDeclarationEntry
{
StackVariable var;
TranslatedAutoVariableDeclarationEntry() { var = entry.getDeclaration() }
@@ -217,7 +218,8 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
* with a dynamic initializer.
*/
class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization {
TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization
{
IRVariableDeclarationEntry entry;
StaticLocalVariable var;

View File

@@ -131,7 +131,8 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
}
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
TTranslatedConditionValue {
TTranslatedConditionValue
{
TranslatedConditionValue() { this = TTranslatedConditionValue(expr) }
override TranslatedElement getChild(int id) { id = 0 and result = this.getCondition() }
@@ -326,7 +327,8 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad
* from the AST.
*/
class TranslatedSyntheticTemporaryObject extends TranslatedValueCategoryAdjustment,
TTranslatedSyntheticTemporaryObject {
TTranslatedSyntheticTemporaryObject
{
TranslatedSyntheticTemporaryObject() { this = TTranslatedSyntheticTemporaryObject(expr) }
override string toString() { result = "Temporary materialization of " + expr.toString() }
@@ -2302,7 +2304,8 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
* its initializer.
*/
class TranslatedTemporaryObjectExpr extends TranslatedNonConstantExpr,
TranslatedVariableInitialization {
TranslatedVariableInitialization
{
override TemporaryObjectExpr expr;
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {

View File

@@ -566,7 +566,8 @@ private TranslatedConstructorInitList getTranslatedConstructorInitList(Function
* instances for constructors can actually contain initializers.
*/
class TranslatedConstructorInitList extends TranslatedElement, InitializationContext,
TTranslatedConstructorInitList {
TTranslatedConstructorInitList
{
Function func;
TranslatedConstructorInitList() { this = TTranslatedConstructorInitList(func) }
@@ -637,7 +638,8 @@ private TranslatedDestructorDestructionList getTranslatedDestructorDestructionLi
* destructions.
*/
class TranslatedDestructorDestructionList extends TranslatedElement,
TTranslatedDestructorDestructionList {
TTranslatedDestructorDestructionList
{
Function func;
TranslatedDestructorDestructionList() { this = TTranslatedDestructorDestructionList(func) }

View File

@@ -9,7 +9,8 @@ private import InstructionTag
private import semmle.code.cpp.ir.internal.IRUtilities
class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
TTranslatedGlobalOrNamespaceVarInit, InitializationContext {
TTranslatedGlobalOrNamespaceVarInit, InitializationContext
{
GlobalOrNamespaceVariable var;
TranslatedGlobalOrNamespaceVarInit() { this = TTranslatedGlobalOrNamespaceVarInit(var) }

View File

@@ -440,7 +440,8 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
}
class TranslatedConstructorInitialization extends TranslatedDirectInitialization,
StructorCallContext {
StructorCallContext
{
override ConstructorCall expr;
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -528,7 +529,8 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
* explicit element in an initializer list.
*/
class TranslatedExplicitFieldInitialization extends TranslatedFieldInitialization,
InitializationContext, TTranslatedExplicitFieldInitialization {
InitializationContext, TTranslatedExplicitFieldInitialization
{
Expr expr;
TranslatedExplicitFieldInitialization() {
@@ -565,7 +567,8 @@ private string getZeroValue(Type type) {
* corresponding element in the initializer list.
*/
class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
TTranslatedFieldValueInitialization {
TTranslatedFieldValueInitialization
{
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -700,7 +703,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
* an explicit element in an initializer list.
*/
class TranslatedExplicitElementInitialization extends TranslatedElementInitialization,
TTranslatedExplicitElementInitialization, InitializationContext {
TTranslatedExplicitElementInitialization, InitializationContext
{
int elementIndex;
TranslatedExplicitElementInitialization() {
@@ -737,7 +741,8 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
* elements without corresponding elements in the initializer list.
*/
class TranslatedElementValueInitialization extends TranslatedElementInitialization,
TTranslatedElementValueInitialization {
TTranslatedElementValueInitialization
{
int elementIndex;
int elementCount;
@@ -881,7 +886,8 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
* Represents a call to a delegating or base class constructor from within a constructor.
*/
abstract class TranslatedConstructorCallFromConstructor extends TranslatedStructorCallFromStructor,
TTranslatedConstructorBaseInit {
TTranslatedConstructorBaseInit
{
TranslatedConstructorCallFromConstructor() { this = TTranslatedConstructorBaseInit(call) }
}
@@ -917,7 +923,8 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
* derived class constructor
*/
class TranslatedConstructorBaseInit extends TranslatedConstructorCallFromConstructor,
TranslatedBaseStructorCall {
TranslatedBaseStructorCall
{
TranslatedConstructorBaseInit() { not call instanceof ConstructorDelegationInit }
final override string toString() { result = "construct base: " + call.toString() }
@@ -934,7 +941,8 @@ TranslatedDestructorBaseDestruction getTranslatedDestructorBaseDestruction(
* derived class destructor.
*/
class TranslatedDestructorBaseDestruction extends TranslatedBaseStructorCall,
TTranslatedDestructorBaseDestruction {
TTranslatedDestructorBaseDestruction
{
TranslatedDestructorBaseDestruction() { this = TTranslatedDestructorBaseDestruction(call) }
final override string toString() { result = "destroy base: " + call.toString() }

View File

@@ -20,7 +20,8 @@ TranslatedMicrosoftTryExceptHandler getTranslatedMicrosoftTryExceptHandler(
}
class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
TTranslatedMicrosoftTryExceptHandler {
TTranslatedMicrosoftTryExceptHandler
{
MicrosoftTryExceptStmt tryExcept;
TranslatedMicrosoftTryExceptHandler() { this = TTranslatedMicrosoftTryExceptHandler(tryExcept) }

View File

@@ -389,7 +389,8 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
private module HeuristicAllocation {
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr
{
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
@@ -406,7 +407,8 @@ private module HeuristicAllocation {
}
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction
{
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
@@ -430,7 +432,8 @@ private module HeuristicAllocation {
* 2. The function must return a pointer type
* 3. There must be a unique parameter of unsigned integral type.
*/
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function
{
int sizeArg;
HeuristicAllocationFunctionByName() {

View File

@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
* The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`.
*/
private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction,
RemoteFlowSourceFunction {
RemoteFlowSourceFunction
{
GetDelimFunction() { this.hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) }
override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) {

View File

@@ -14,7 +14,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
* The standard functions `fgets` and `fgetws`.
*/
private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
SideEffectFunction, RemoteFlowSourceFunction {
SideEffectFunction, RemoteFlowSourceFunction
{
FgetsFunction() {
// fgets(str, num, stream)
// fgetws(wstr, num, stream)
@@ -69,7 +70,8 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
* The standard functions `gets`.
*/
private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunction,
SideEffectFunction, LocalFlowSourceFunction {
SideEffectFunction, LocalFlowSourceFunction
{
GetsFunction() {
// gets(str)
this.hasGlobalOrStdOrBslName("gets")

View File

@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
* The standard function templates `std::move` and `std::forward`.
*/
private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction,
FunctionTemplateInstantiation {
FunctionTemplateInstantiation
{
IdentityFunction() { this.hasQualifiedName("std", ["move", "forward"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }

View File

@@ -121,7 +121,8 @@ class IteratorCrementNonMemberOperator extends Operator {
}
private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMemberOperator,
DataFlowFunction {
DataFlowFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
output.isReturnValue()
@@ -143,7 +144,8 @@ class IteratorCrementMemberOperator extends MemberFunction {
}
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
DataFlowFunction, TaintFunction {
DataFlowFunction, TaintFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierAddress() and
output.isReturnValue()
@@ -204,7 +206,8 @@ class IteratorBinaryArithmeticMemberOperator extends MemberFunction {
}
private class IteratorBinaryArithmeticMemberOperatorModel extends IteratorBinaryArithmeticMemberOperator,
TaintFunction {
TaintFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isReturnValue()
@@ -258,7 +261,8 @@ class IteratorAssignArithmeticNonMemberOperator extends Operator {
}
private class IteratorAssignArithmeticNonMemberOperatorModel extends IteratorAssignArithmeticNonMemberOperator,
DataFlowFunction, TaintFunction {
DataFlowFunction, TaintFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isParameter(0) and
output.isReturnValue()
@@ -289,7 +293,8 @@ class IteratorAssignArithmeticMemberOperator extends MemberFunction {
}
private class IteratorAssignArithmeticMemberOperatorModel extends IteratorAssignArithmeticMemberOperator,
DataFlowFunction, TaintFunction {
DataFlowFunction, TaintFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierAddress() and
output.isReturnValue()
@@ -325,7 +330,8 @@ class IteratorAssignArithmeticOperator extends Function {
* non-member and member versions, use `IteratorPointerDereferenceOperator`.
*/
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction,
IteratorReferenceFunction {
IteratorReferenceFunction
{
IteratorPointerDereferenceMemberOperator() {
this.getClassAndName("operator*") instanceof Iterator
}
@@ -353,7 +359,8 @@ class IteratorPointerDereferenceNonMemberOperator extends Operator, IteratorRefe
}
private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorPointerDereferenceNonMemberOperator,
TaintFunction {
TaintFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
output.isReturnValue()
@@ -389,7 +396,8 @@ private class IteratorFieldMemberOperator extends Operator, TaintFunction {
* An `operator[]` member function of an iterator class.
*/
private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction,
IteratorReferenceFunction {
IteratorReferenceFunction
{
IteratorArrayMemberOperator() { this.getClassAndName("operator[]") instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -418,7 +426,8 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
* `operator*` and use their own `operator=` to assign to the container.
*/
private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMemberOperator,
TaintFunction {
TaintFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(0) and
output.isQualifierObject()

View File

@@ -15,7 +15,8 @@ import semmle.code.cpp.models.interfaces.Taint
* `__builtin___memcpy_chk`.
*/
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
AliasFunction {
AliasFunction
{
MemcpyFunction() {
// memcpy(dest, src, num)
// memmove(dest, src, num)

View File

@@ -13,7 +13,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
* The standard function `memset` and its assorted variants
*/
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
SideEffectFunction {
SideEffectFunction
{
MemsetFunction() {
this.hasGlobalOrStdOrBslName("memset")
or

View File

@@ -8,7 +8,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
* guaranteed to be side-effect free.
*/
private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction,
SideEffectFunction {
SideEffectFunction
{
PureStrFunction() {
this.hasGlobalOrStdOrBslName([
atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr",
@@ -153,7 +154,8 @@ private class PureFunction extends TaintFunction, SideEffectFunction {
* evaluation is guaranteed to be side-effect free.
*/
private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction,
SideEffectFunction {
SideEffectFunction
{
PureMemFunction() {
this.hasGlobalOrStdOrBslName([
"memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem"

View File

@@ -11,7 +11,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
/** The function `recv` and its assorted variants */
private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction,
RemoteFlowSourceFunction {
RemoteFlowSourceFunction
{
Recv() {
this.hasGlobalName([
"recv", // recv(socket, dest, len, flags)

View File

@@ -15,7 +15,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
* The `scanf` family of functions.
*/
abstract private class ScanfFunctionModel extends ArrayFunction, TaintFunction, AliasFunction,
SideEffectFunction {
SideEffectFunction
{
override predicate hasArrayWithNullTerminator(int bufParam) {
bufParam = this.(ScanfFunction).getFormatParameterIndex()
}

View File

@@ -29,7 +29,8 @@ private class SmartPtr extends Class, PointerWrapper {
* - `std::weak_ptr<T>::operator*()`
*/
private class PointerUnwrapperFunction extends MemberFunction, TaintFunction, DataFlowFunction,
SideEffectFunction, AliasFunction {
SideEffectFunction, AliasFunction
{
PointerUnwrapperFunction() {
exists(PointerWrapper wrapper | wrapper.getAnUnwrapperFunction() = this)
}

View File

@@ -13,7 +13,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
* The standard function `strset` and its assorted variants
*/
private class StrsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
SideEffectFunction {
SideEffectFunction
{
StrsetFunction() {
hasGlobalName([
"strset", "_strset", "_strset_l", "_wcsset", "_wcsset_l", "_mbsset", "_mbsset_l",

View File

@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.CommandExecution
* A function for running a command using a command interpreter.
*/
private class SystemFunction extends CommandExecutionFunction, ArrayFunction, AliasFunction,
SideEffectFunction {
SideEffectFunction
{
SystemFunction() {
hasGlobalOrStdName("system") or // system(command)
hasGlobalName("popen") or // popen(command, mode)

View File

@@ -591,7 +591,8 @@ deprecated library class DataSensitiveExprCall extends DataSensitiveCallExpr, Ex
/** Call to a virtual function. */
deprecated library class DataSensitiveOverriddenFunctionCall extends DataSensitiveCallExpr,
FunctionCall {
FunctionCall
{
DataSensitiveOverriddenFunctionCall() {
exists(getTarget().(VirtualFunction).getAnOverridingFunction())
}

View File

@@ -1,3 +1,7 @@
## 0.5.4
No user-facing changes.
## 0.5.3
No user-facing changes.

View File

@@ -1,11 +1,11 @@
int write_default_config_bad() {
void write_default_config_bad() {
// BAD - this is world-writable so any user can overwrite the config
FILE* out = creat(OUTFILE, 0666);
fprintf(out, DEFAULT_CONFIG);
int out = creat(OUTFILE, 0666);
dprintf(out, DEFAULT_CONFIG);
}
int write_default_config_good() {
void write_default_config_good() {
// GOOD - this allows only the current user to modify the file
FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR);
fprintf(out, DEFAULT_CONFIG);
int out = creat(OUTFILE, S_IWUSR | S_IRUSR);
dprintf(out, DEFAULT_CONFIG);
}

View File

@@ -0,0 +1,3 @@
## 0.5.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.5.3
lastReleaseVersion: 0.5.4

View File

@@ -14,8 +14,8 @@ import cpp
from FunctionCall fc, FunctionCall fc2, LocalScopeVariable v
where
freeCall(fc, v.getAnAccess()) and
freeCall(fc2, v.getAnAccess()) and
fc.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
fc2.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
fc != fc2 and
fc.getASuccessor*() = fc2 and
not exists(Expr exptmp |

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.5.4-dev
version: 0.5.5-dev
groups:
- cpp
- queries

View File

@@ -1,14 +1,14 @@
| CPP-205.cpp:0:0:0:0 | CPP-205.cpp | |
| CPP-205.cpp:1:20:1:20 | T | |
| CPP-205.cpp:1:20:1:20 | definition of T | |
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:5 | fn | function fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for fn<T>(T) -> int |
| CPP-205.cpp:2:5:2:6 | fn | function fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<int>(int) -> int |
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for int fn<int>(int) |
| CPP-205.cpp:2:5:2:5 | fn | function int fn<int>(int) |
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for int fn<T>(T) |
| CPP-205.cpp:2:5:2:6 | fn | function int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<int>(int) |
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<int>(int) |
| CPP-205.cpp:2:15:5:1 | { ... } | |
| CPP-205.cpp:2:15:5:1 | { ... } | |
| CPP-205.cpp:3:3:3:33 | declaration | |
@@ -20,16 +20,16 @@
| CPP-205.cpp:4:3:4:11 | return ... | |
| CPP-205.cpp:4:10:4:10 | 0 | |
| CPP-205.cpp:4:10:4:10 | 0 | |
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for main() -> int |
| CPP-205.cpp:7:5:7:8 | main | function main() -> int |
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for int main() |
| CPP-205.cpp:7:5:7:8 | main | function int main() |
| CPP-205.cpp:7:12:9:1 | { ... } | |
| CPP-205.cpp:8:3:8:15 | return ... | |
| CPP-205.cpp:8:10:8:11 | call to fn | |
| CPP-205.cpp:8:13:8:13 | 0 | |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
| file://:0:0:0:0 | __super | |
| file://:0:0:0:0 | __va_list_tag | |
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
| file://:0:0:0:0 | y | |

View File

@@ -1,17 +1,19 @@
import cpp
import semmle.code.cpp.Print
string describe(Element e) {
result = "function " + e.(Function).getFullSignature()
e instanceof Function and
result = "function " + getIdentityString(e)
or
result =
"function declaration entry for " +
e.(FunctionDeclarationEntry).getFunction().getFullSignature()
getIdentityString(e.(FunctionDeclarationEntry).getFunction())
or
result = "parameter for " + e.(Parameter).getFunction().getFullSignature()
result = "parameter for " + getIdentityString(e.(Parameter).getFunction())
or
result =
"parameter declaration entry for " +
e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction().getFullSignature()
getIdentityString(e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction())
}
from Element e

View File

@@ -1,51 +1,51 @@
newExprs
| allocators.cpp:49:3:49:9 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
| allocators.cpp:50:3:50:15 | new | int | operator new(size_t, float) -> void * | 4 | 4 | | |
| allocators.cpp:51:3:51:11 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
| allocators.cpp:52:3:52:14 | new | String | operator new(unsigned long) -> void * | 8 | 8 | | |
| allocators.cpp:53:3:53:27 | new | String | operator new(size_t, float) -> void * | 8 | 8 | | |
| allocators.cpp:54:3:54:17 | new | Overaligned | operator new(unsigned long, align_val_t) -> void * | 256 | 128 | aligned | |
| allocators.cpp:55:3:55:25 | new | Overaligned | operator new(size_t, align_val_t, float) -> void * | 256 | 128 | aligned | |
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator new(size_t) -> void * | 1 | 1 | | |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator new(size_t, align_val_t, float) -> void * | 128 | 128 | aligned | |
| allocators.cpp:129:3:129:21 | new | int | operator new(size_t, void *) -> void * | 4 | 4 | | & ... |
| allocators.cpp:135:3:135:26 | new | int | operator new(size_t, const nothrow_t &) -> void * | 4 | 4 | | |
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
newArrayExprs
| allocators.cpp:68:3:68:12 | new[] | int[] | int | operator new[](unsigned long) -> void * | 4 | 4 | | n | |
| allocators.cpp:69:3:69:18 | new[] | int[] | int | operator new[](size_t, float) -> void * | 4 | 4 | | n | |
| allocators.cpp:70:3:70:15 | new[] | String[] | String | operator new[](unsigned long) -> void * | 8 | 8 | | n | |
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | operator new[](unsigned long, align_val_t) -> void * | 256 | 128 | aligned | n | |
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | operator new[](unsigned long) -> void * | 8 | 8 | | | |
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | FailedInit::operator new[](size_t) -> void * | 1 | 1 | | n | |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | FailedInitOveraligned::operator new[](size_t, align_val_t, float) -> void * | 128 | 128 | aligned | | |
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | operator new[](size_t, void *) -> void * | 4 | 4 | | | buf |
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | operator new[](size_t, const nothrow_t &) -> void * | 4 | 4 | | | |
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | operator new[](unsigned long) -> void * | 10 | 1 | | x | |
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | operator new[](unsigned long) -> void * | 20 | 1 | | | |
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | operator new[](unsigned long) -> void * | 900 | 1 | | x | |
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
newExprDeallocators
| allocators.cpp:52:3:52:14 | new | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:53:3:53:27 | new | String | operator delete(void *, float) -> void | 8 | 8 | |
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator delete(void *, size_t) -> void | 1 | 1 | sized |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator delete(void *, align_val_t, float) -> void | 128 | 128 | aligned |
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
newArrayExprDeallocators
| allocators.cpp:70:3:70:15 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:72:3:72:16 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:108:3:108:19 | new[] | FailedInit | FailedInit::operator delete[](void *, size_t) -> void | 1 | 1 | sized |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | FailedInitOveraligned::operator delete[](void *, align_val_t, float) -> void | 128 | 128 | aligned |
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
deleteExprs
| allocators.cpp:59:3:59:35 | delete | int | operator delete(void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:60:3:60:38 | delete | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | SizedDealloc::operator delete(void *, size_t) -> void | 32 | 1 | sized |
| allocators.cpp:62:3:62:43 | delete | Overaligned | operator delete(void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
| allocators.cpp:64:3:64:44 | delete | const String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized |
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
deleteArrayExprs
| allocators.cpp:78:3:78:37 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:79:3:79:40 | delete[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | SizedDealloc::operator delete[](void *, size_t) -> void | 32 | 1 | sized |
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | operator delete[](void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:83:3:83:23 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
allocationFunctions
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |

View File

@@ -1,12 +1,13 @@
import cpp
import semmle.code.cpp.models.implementations.Allocation
import semmle.code.cpp.Print
query predicate newExprs(
NewExpr expr, string type, string sig, int size, int alignment, string form, string placement
) {
exists(Function allocator, Type allocatedType |
expr.getAllocator() = allocator and
sig = allocator.getFullSignature() and
sig = getIdentityString(allocator) and
allocatedType = expr.getAllocatedType() and
type = allocatedType.toString() and
size = allocatedType.getSize() and
@@ -24,7 +25,7 @@ query predicate newArrayExprs(
) {
exists(Function allocator, Type arrayType, Type elementType |
expr.getAllocator() = allocator and
sig = allocator.getFullSignature() and
sig = getIdentityString(allocator) and
arrayType = expr.getAllocatedType() and
t1 = arrayType.toString() and
elementType = expr.getAllocatedElementType() and
@@ -44,7 +45,7 @@ query predicate newExprDeallocators(
) {
exists(Function deallocator, Type allocatedType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
allocatedType = expr.getAllocatedType() and
type = allocatedType.toString() and
size = allocatedType.getSize() and
@@ -62,7 +63,7 @@ query predicate newArrayExprDeallocators(
) {
exists(Function deallocator, Type elementType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
elementType = expr.getAllocatedElementType() and
type = elementType.toString() and
size = elementType.getSize() and
@@ -80,7 +81,7 @@ query predicate deleteExprs(
) {
exists(Function deallocator, Type deletedType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
deletedType = expr.getDeletedObjectType() and
type = deletedType.toString() and
size = deletedType.getSize() and
@@ -98,7 +99,7 @@ query predicate deleteArrayExprs(
) {
exists(Function deallocator, Type elementType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
elementType = expr.getDeletedElementType() and
type = elementType.toString() and
size = elementType.getSize() and

View File

@@ -1,30 +1,30 @@
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(a<int> &&) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(const a<int> &) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(a<int> &&) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(const a<int> &) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:4:26:4:26 | a | a<<unnamed>>::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
| copy_from_prototype.cpp:4:26:4:26 | a | a<int>::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b() -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(b &&) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(const b &) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(b &&) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(const b &) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(c<int> &&) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(const c<int> &) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(c<int> &&) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(const c<int> &) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<T> | X |
| copy_from_prototype.cpp:14:26:14:26 | c | c<int>::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(d &&) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(const d &) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(d &&) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(const e<int> &) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(e<int> &&) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(const e<int> &) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(e<int> &&) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:23:26:23:26 | e | e<T>::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
| copy_from_prototype.cpp:26:35:26:43 | e | e<int>::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
| copy_from_prototype.cpp:3:7:3:7 | a | void a<int>::a(a<int> const&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | a | void a<int>::a(a<int>&&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>& a<int>::operator=(a<int> const&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>& a<int>::operator=(a<int>&&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:4:26:4:26 | a | void a<(unnamed template parameter)>::a<(unnamed template parameter)>() | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
| copy_from_prototype.cpp:4:26:4:26 | a | void a<int>::a<(unnamed template parameter)>() | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b() | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b(b const&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b(b&&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b& b::operator=(b const&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b& b::operator=(b&&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | void c<int>::c(c<int> const&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | void c<int>::c(c<int>&&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>& c<int>::operator=(c<int> const&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>& c<int>::operator=(c<int>&&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:14:26:14:26 | c | void c<T>::c<(unnamed template parameter)>() | copy_from_prototype.cpp:13:7:13:7 | c<T> | X |
| copy_from_prototype.cpp:14:26:14:26 | c | void c<int>::c<(unnamed template parameter)>() | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d() | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d(d const&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d(d&&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d& d::operator=(d const&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d& d::operator=(d&&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | void e<int>::e(e<int> const&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | void e<int>::e(e<int>&&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>& e<int>::operator=(e<int> const&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>& e<int>::operator=(e<int>&&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:23:26:23:26 | e | void e<T>::e<(unnamed template parameter)>() | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
| copy_from_prototype.cpp:26:35:26:43 | e | void e<int>::e<(unnamed template parameter)>() | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
| file://:0:0:0:0 | operator= | __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) | file://:0:0:0:0 | __va_list_tag | <none> |
| file://:0:0:0:0 | operator= | __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) | file://:0:0:0:0 | __va_list_tag | <none> |

View File

@@ -1,4 +1,5 @@
import cpp
import semmle.code.cpp.Print
from Function f, string e
where
@@ -8,4 +9,4 @@ where
then e = f.getADeclarationEntry().getNoExceptExpr().toString()
else e = "<no expr>"
else e = "<none>"
select f, f.getFullSignature(), f.getDeclaringType(), e
select f, getIdentityString(f), f.getDeclaringType(), e

View File

@@ -19,3 +19,6 @@
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
| test.cpp:430:6:430:6 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:429:2:429:6 | call to scanf | call to scanf |

View File

@@ -406,3 +406,26 @@ char *my_string_copy() {
*ptr++ = 0;
return DST_STRING;
}
void scan_and_write() {
{
int i;
if (scanf("%d", &i) < 1) {
i = 0;
}
use(i); // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
}
{
int i;
if (scanf("%d", &i) != 1) {
i = 0;
}
use(i); // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
}
}
void scan_and_static_variable() {
static int i;
scanf("%d", &i);
use(i); // GOOD [FALSE POSITIVE]: static variables are always 0-initialized
}

View File

@@ -1,5 +1,6 @@
using Xunit;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Collections.Generic;
using System;
using System.Linq;
@@ -85,6 +86,15 @@ namespace Semmle.Autobuild.CSharp.Tests
return ret;
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var ret = (this as IBuildActions).RunProcess(cmd, args, workingDirectory, env, out var stdout);
stdout.ForEach(line => onOutput(line));
return ret;
}
public IList<string> DirectoryDeleteIn { get; } = new List<string>();
void IBuildActions.DirectoryDelete(string dir, bool recursive)
@@ -200,6 +210,16 @@ namespace Semmle.Autobuild.CSharp.Tests
if (!DownloadFiles.Contains((address, fileName)))
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
}
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new TestDiagnosticWriter();
}
internal class TestDiagnosticWriter : IDiagnosticsWriter
{
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
}
/// <summary>
@@ -391,6 +411,7 @@ namespace Semmle.Autobuild.CSharp.Tests
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_DIAGNOSTIC_DIR"] = "";
actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = isWindows ? "win64" : "linux64";
actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;

View File

@@ -0,0 +1,69 @@
using Semmle.Autobuild.Shared;
using Semmle.Extraction.CSharp;
namespace Semmle.Autobuild.CSharp
{
internal class AutoBuildRule : IBuildRule<CSharpAutobuildOptions>
{
private readonly CSharpAutobuilder autobuilder;
public DotNetRule DotNetRule { get; }
public MsBuildRule MsBuildRule { get; }
public BuildCommandAutoRule BuildCommandAutoRule { get; }
public AutoBuildRule(CSharpAutobuilder autobuilder)
{
this.autobuilder = autobuilder;
this.DotNetRule = new DotNetRule();
this.MsBuildRule = new MsBuildRule();
this.BuildCommandAutoRule = new BuildCommandAutoRule(DotNetRule.WithDotNet);
}
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
var cleanTrapFolder =
BuildScript.DeleteDirectory(this.autobuilder.TrapDir);
var cleanSourceArchive =
BuildScript.DeleteDirectory(this.autobuilder.SourceArchiveDir);
var tryCleanExtractorArgsLogs =
BuildScript.Create(actions =>
{
foreach (var file in Extractor.GetCSharpArgsLogs())
{
try
{
actions.FileDelete(file);
}
catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block]
{ }
}
return 0;
});
var attemptExtractorCleanup =
BuildScript.Try(cleanTrapFolder) &
BuildScript.Try(cleanSourceArchive) &
tryCleanExtractorArgsLogs &
BuildScript.DeleteFile(Extractor.GetCSharpLogPath());
/// <summary>
/// Execute script `s` and check that the C# extractor has been executed.
/// If either fails, attempt to cleanup any artifacts produced by the extractor,
/// and exit with code 1, in order to proceed to the next attempt.
/// </summary>
BuildScript IntermediateAttempt(BuildScript s) =>
(s & this.autobuilder.CheckExtractorRun(false)) |
(attemptExtractorCleanup & BuildScript.Failure);
return
// First try .NET Core
IntermediateAttempt(this.DotNetRule.Analyse(this.autobuilder, true)) |
// Then MSBuild
(() => IntermediateAttempt(this.MsBuildRule.Analyse(this.autobuilder, true))) |
// And finally look for a script that might be a build script
(() => this.BuildCommandAutoRule.Analyse(this.autobuilder, true) & this.autobuilder.CheckExtractorRun(true));
}
}
}

View File

@@ -1,6 +1,8 @@
using Semmle.Extraction.CSharp;
using Semmle.Util.Logging;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Linq;
namespace Semmle.Autobuild.CSharp
{
@@ -29,25 +31,16 @@ namespace Semmle.Autobuild.CSharp
public class CSharpAutobuilder : Autobuilder<CSharpAutobuildOptions>
{
public CSharpAutobuilder(IBuildActions actions, CSharpAutobuildOptions options) : base(actions, options) { }
private const string buildCommandDocsUrl =
"https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages";
private readonly AutoBuildRule autoBuildRule;
public CSharpAutobuilder(IBuildActions actions, CSharpAutobuildOptions options) : base(actions, options, new CSharpDiagnosticClassifier()) =>
this.autoBuildRule = new AutoBuildRule(this);
public override BuildScript GetBuildScript()
{
/// <summary>
/// A script that checks that the C# extractor has been executed.
/// </summary>
BuildScript CheckExtractorRun(bool warnOnFailure) =>
BuildScript.Create(actions =>
{
if (actions.FileExists(Extractor.GetCSharpLogPath()))
return 0;
if (warnOnFailure)
Log(Severity.Error, "No C# code detected during build.");
return 1;
});
var attempt = BuildScript.Failure;
switch (GetCSharpBuildStrategy())
{
@@ -65,47 +58,9 @@ namespace Semmle.Autobuild.CSharp
attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true);
break;
case CSharpBuildStrategy.Auto:
var cleanTrapFolder =
BuildScript.DeleteDirectory(TrapDir);
var cleanSourceArchive =
BuildScript.DeleteDirectory(SourceArchiveDir);
var tryCleanExtractorArgsLogs =
BuildScript.Create(actions =>
{
foreach (var file in Extractor.GetCSharpArgsLogs())
{
try
{
actions.FileDelete(file);
}
catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block]
{ }
}
return 0;
});
var attemptExtractorCleanup =
BuildScript.Try(cleanTrapFolder) &
BuildScript.Try(cleanSourceArchive) &
tryCleanExtractorArgsLogs &
BuildScript.DeleteFile(Extractor.GetCSharpLogPath());
/// <summary>
/// Execute script `s` and check that the C# extractor has been executed.
/// If either fails, attempt to cleanup any artifacts produced by the extractor,
/// and exit with code 1, in order to proceed to the next attempt.
/// </summary>
BuildScript IntermediateAttempt(BuildScript s) =>
(s & CheckExtractorRun(false)) |
(attemptExtractorCleanup & BuildScript.Failure);
attempt =
// First try .NET Core
IntermediateAttempt(new DotNetRule().Analyse(this, true)) |
// Then MSBuild
(() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) |
// And finally look for a script that might be a build script
(() => new BuildCommandAutoRule(DotNetRule.WithDotNet).Analyse(this, true) & CheckExtractorRun(true)) |
// Attempt a few different build strategies to see if one works
this.autoBuildRule.Analyse(this, true) |
// All attempts failed: print message
AutobuildFailure();
break;
@@ -114,6 +69,127 @@ namespace Semmle.Autobuild.CSharp
return attempt;
}
/// <summary>
/// A script that checks that the C# extractor has been executed.
/// </summary>
public BuildScript CheckExtractorRun(bool warnOnFailure) =>
BuildScript.Create(actions =>
{
if (actions.FileExists(Extractor.GetCSharpLogPath()))
return 0;
if (warnOnFailure)
Log(Severity.Error, "No C# code detected during build.");
return 1;
});
protected override void AutobuildFailureDiagnostic()
{
// if `ScriptPath` is not null here, the `BuildCommandAuto` rule was
// run and found at least one script to execute
if (this.autoBuildRule.BuildCommandAutoRule.ScriptPath is not null)
{
var relScriptPath = this.MakeRelative(autoBuildRule.BuildCommandAutoRule.ScriptPath);
// if we found multiple build scripts in the project directory, then we can say
// as much to indicate that we may have picked the wrong one;
// otherwise, we just report that the one script we found didn't work
DiagnosticMessage message =
this.autoBuildRule.BuildCommandAutoRule.CandidatePaths.Count() > 1 ?
new(
this.Options.Language,
"multiple-build-scripts",
"There are multiple potential build scripts",
markdownMessage:
"CodeQL found multiple potential build scripts for your project and " +
$"attempted to run `{relScriptPath}`, which failed. " +
"This may not be the right build script for your project. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
) :
new(
this.Options.Language,
"script-failure",
"Unable to build project using build script",
markdownMessage:
"CodeQL attempted to build your project using a script located at " +
$"`{relScriptPath}`, which failed. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
);
AddDiagnostic(message);
}
// project files which don't exist get marked as not .NET core projects, but we don't want
// to show an error for this if the files don't exist
var foundNotDotNetProjects = autoBuildRule.DotNetRule.NotDotNetProjects.Where(
proj => this.Actions.FileExists(proj.FullPath)
);
// both dotnet and msbuild builds require project or solution files; if we haven't found any
// then neither of those rules would've worked
if (this.ProjectsOrSolutionsToBuild.Count == 0)
{
this.AddDiagnostic(new(
this.Options.Language,
"no-projects-or-solutions",
"No project or solutions files found",
markdownMessage:
"CodeQL could not find any project or solution files in your repository. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
));
}
// show a warning if there are projects which are not compatible with .NET Core, in case that is unintentional
else if (foundNotDotNetProjects.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"dotnet-incompatible-projects",
"Some projects are incompatible with .NET Core",
severity: DiagnosticMessage.TspSeverity.Warning,
markdownMessage: $"""
CodeQL found some projects which cannot be built with .NET Core:
{autoBuildRule.DotNetRule.NotDotNetProjects.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 5)}
"""
));
}
// report any projects that failed to build with .NET Core
if (autoBuildRule.DotNetRule.FailedProjectsOrSolutions.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"dotnet-build-failure",
"Some projects or solutions failed to build using .NET Core",
markdownMessage: $"""
CodeQL was unable to build the following projects using .NET Core:
{autoBuildRule.DotNetRule.FailedProjectsOrSolutions.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 10)}
Set up a [manual build command]({buildCommandDocsUrl}).
"""
));
}
// report any projects that failed to build with MSBuild
if (autoBuildRule.MsBuildRule.FailedProjectsOrSolutions.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"msbuild-build-failure",
"Some projects or solutions failed to build using MSBuild",
markdownMessage: $"""
CodeQL was unable to build the following projects using MSBuild:
{autoBuildRule.MsBuildRule.FailedProjectsOrSolutions.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 10)}
Set up a [manual build command]({buildCommandDocsUrl}).
"""
));
}
}
/// <summary>
/// Gets the build strategy that the autobuilder should apply, based on the
/// options in the `lgtm.yml` file.

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Autobuild.Shared;
using Semmle.Util;
namespace Semmle.Autobuild.CSharp
{
/// <summary>
/// A diagnostic rule which tries to identify missing Xamarin SDKs.
/// </summary>
public class MissingXamarinSdkRule : DiagnosticRule
{
private const string docsUrl = "https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-xamarin-applications";
public class Result : IDiagnosticsResult
{
/// <summary>
/// The name of the SDK that is missing.
/// </summary>
public string SDKName { get; }
public Result(string sdkName)
{
this.SDKName = sdkName;
}
public DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared => new(
builder.Options.Language,
$"missing-xamarin-{this.SDKName.ToLower()}-sdk",
$"Missing Xamarin SDK for {this.SDKName}",
severity: severity ?? DiagnosticMessage.TspSeverity.Error,
markdownMessage: $"[Configure your workflow]({docsUrl}) for this SDK before running CodeQL."
);
}
public MissingXamarinSdkRule() :
base("MSB4019:[^\"]*\"[^\"]*Xamarin\\.(?<sdkName>[^\\.]*)\\.CSharp\\.targets\"")
{
}
public override void Fire(DiagnosticClassifier classifier, Match match)
{
if (!match.Groups.TryGetValue("sdkName", out var sdkName))
throw new ArgumentException("Expected regular expression match to contain sdkName");
var xamarinResults = classifier.Results.OfType<Result>().Where(result =>
result.SDKName.Equals(sdkName.Value)
);
if (!xamarinResults.Any())
classifier.Results.Add(new Result(sdkName.Value));
}
}
public class MissingProjectFileRule : DiagnosticRule
{
private const string runsOnDocsUrl = "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on";
private const string checkoutDocsUrl = "https://github.com/actions/checkout#usage";
public class Result : IDiagnosticsResult
{
/// <summary>
/// A set of missing project files.
/// </summary>
public HashSet<string> MissingProjectFiles { get; }
public Result()
{
this.MissingProjectFiles = new HashSet<string>();
}
public DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared => new(
builder.Options.Language,
"missing-project-files",
"Missing project files",
severity: severity ?? DiagnosticMessage.TspSeverity.Warning,
markdownMessage: $"""
Some project files were not found when CodeQL built your project:
{this.MissingProjectFiles.AsEnumerable().Select(p => builder.MakeRelative(p)).ToMarkdownList(MarkdownUtil.CodeFormatter, 5)}
This may lead to subsequent failures. You can check for common causes for missing project files:
- Ensure that the project is built using the {runsOnDocsUrl.ToMarkdownLink("intended operating system")} and that filenames on case-sensitive platforms are correctly specified.
- If your repository uses Git submodules, ensure that those are {checkoutDocsUrl.ToMarkdownLink("checked out")} before the CodeQL action is run.
- If you auto-generate some project files as part of your build process, ensure that these are generated before the CodeQL action is run.
"""
);
}
public MissingProjectFileRule() :
base("MSB3202: The project file \"(?<projectFile>[^\"]+)\" was not found. \\[(?<location>[^\\]]+)\\]")
{
}
public override void Fire(DiagnosticClassifier classifier, Match match)
{
if (!match.Groups.TryGetValue("projectFile", out var projectFile))
throw new ArgumentException("Expected regular expression match to contain projectFile");
if (!match.Groups.TryGetValue("location", out var location))
throw new ArgumentException("Expected regular expression match to contain location");
var result = classifier.Results.OfType<Result>().FirstOrDefault();
// if we do not yet have a result for this rule, create one and add it to the list
// of results the classifier knows about
if (result is null)
{
result = new Result();
classifier.Results.Add(result);
}
// then add the missing project file
result.MissingProjectFiles.Add(projectFile.Value);
}
}
/// <summary>
/// Implements a <see cref="DiagnosticClassifier" /> which applies C#-specific rules to
/// the build output.
/// </summary>
public class CSharpDiagnosticClassifier : DiagnosticClassifier
{
public CSharpDiagnosticClassifier()
{
// add C#-specific rules to this classifier
this.AddRule(new MissingXamarinSdkRule());
this.AddRule(new MissingProjectFileRule());
}
}
}

View File

@@ -15,6 +15,15 @@ namespace Semmle.Autobuild.CSharp
/// </summary>
internal class DotNetRule : IBuildRule<CSharpAutobuildOptions>
{
public readonly List<IProjectOrSolution> FailedProjectsOrSolutions = new();
/// <summary>
/// A list of projects which are incompatible with DotNet.
/// </summary>
public IEnumerable<Project<CSharpAutobuildOptions>> NotDotNetProjects { get; private set; }
public DotNetRule() => NotDotNetProjects = new List<Project<CSharpAutobuildOptions>>();
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
if (!builder.ProjectsOrSolutionsToBuild.Any())
@@ -22,10 +31,12 @@ namespace Semmle.Autobuild.CSharp
if (auto)
{
var notDotNetProject = builder.ProjectsOrSolutionsToBuild
NotDotNetProjects = builder.ProjectsOrSolutionsToBuild
.SelectMany(p => Enumerators.Singleton(p).Concat(p.IncludedProjects))
.OfType<Project<CSharpAutobuildOptions>>()
.FirstOrDefault(p => !p.DotNetProject);
.Where(p => !p.DotNetProject);
var notDotNetProject = NotDotNetProjects.FirstOrDefault();
if (notDotNetProject is not null)
{
builder.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject);
@@ -50,7 +61,10 @@ namespace Semmle.Autobuild.CSharp
var build = GetBuildScript(builder, dotNetPath, environment, projectOrSolution.FullPath);
ret &= BuildScript.Try(clean) & BuildScript.Try(restore) & build;
ret &= BuildScript.Try(clean) & BuildScript.Try(restore) & BuildScript.OnFailure(build, ret =>
{
FailedProjectsOrSolutions.Add(projectOrSolution);
});
}
return ret;
});

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{

View File

@@ -1,3 +1,4 @@
using Semmle.Util;
using Semmle.Util.Logging;
using System;
using System.Collections.Generic;
@@ -189,10 +190,11 @@ namespace Semmle.Autobuild.Shared
/// solution file and tools.
/// </summary>
/// <param name="options">The command line options.</param>
protected Autobuilder(IBuildActions actions, TAutobuildOptions options)
protected Autobuilder(IBuildActions actions, TAutobuildOptions options, DiagnosticClassifier diagnosticClassifier)
{
Actions = actions;
Options = options;
DiagnosticClassifier = diagnosticClassifier;
pathsLazy = new Lazy<IEnumerable<(string, int)>>(() =>
{
@@ -232,24 +234,53 @@ namespace Semmle.Autobuild.Shared
return ret ?? new List<IProjectOrSolution>();
});
CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT");
CodeQlPlatform = Actions.GetEnvironmentVariable("CODEQL_PLATFORM");
CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable(EnvVars.Root(this.Options.Language));
CodeQlPlatform = Actions.GetEnvironmentVariable(EnvVars.Platform);
TrapDir =
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ??
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR has not been set.");
TrapDir = RequireEnvironmentVariable(EnvVars.TrapDir(this.Options.Language));
SourceArchiveDir = RequireEnvironmentVariable(EnvVars.SourceArchiveDir(this.Options.Language));
DiagnosticsDir = RequireEnvironmentVariable(EnvVars.DiagnosticDir(this.Options.Language));
SourceArchiveDir =
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ??
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR has not been set.");
this.diagnostics = actions.CreateDiagnosticsWriter(Path.Combine(DiagnosticsDir, $"autobuilder-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc"));
}
protected string TrapDir { get; }
/// <summary>
/// Retrieves the value of an environment variable named <paramref name="name"> or throws
/// an exception if no such environment variable has been set.
/// </summary>
/// <param name="name">The name of the environment variable.</param>
/// <returns>The value of the environment variable.</returns>
/// <exception cref="InvalidEnvironmentException">
/// Thrown if the environment variable is not set.
/// </exception>
protected string RequireEnvironmentVariable(string name)
{
return Actions.GetEnvironmentVariable(name) ??
throw new InvalidEnvironmentException($"The environment variable {name} has not been set.");
}
protected string SourceArchiveDir { get; }
public string TrapDir { get; }
public string SourceArchiveDir { get; }
public string DiagnosticsDir { get; }
protected DiagnosticClassifier DiagnosticClassifier { get; }
private readonly ILogger logger = new ConsoleLogger(Verbosity.Info);
private readonly IDiagnosticsWriter diagnostics;
/// <summary>
/// Makes <see cref="path" /> relative to the root source directory.
/// </summary>
/// <param name="path">The path which to make relative.</param>
/// <returns>The relative path.</returns>
public string MakeRelative(string path)
{
return Path.GetRelativePath(this.RootDirectory, path);
}
/// <summary>
/// Log a given build event to the console.
/// </summary>
@@ -260,6 +291,15 @@ namespace Semmle.Autobuild.Shared
logger.Log(severity, format, args);
}
/// <summary>
/// Write <paramref name="diagnostic"/> to the diagnostics file.
/// </summary>
/// <param name="diagnostic">The diagnostics entry to write.</param>
public void AddDiagnostic(DiagnosticMessage diagnostic)
{
diagnostics.AddEntry(diagnostic);
}
/// <summary>
/// Attempt to build this project.
/// </summary>
@@ -283,7 +323,19 @@ namespace Semmle.Autobuild.Shared
Log(silent ? Severity.Debug : Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}");
}
return script.Run(Actions, startCallback, exitCallback);
var onOutput = BuildOutputHandler(Console.Out);
var onError = BuildOutputHandler(Console.Error);
var buildResult = script.Run(Actions, startCallback, exitCallback, onOutput, onError);
// if the build succeeded, all diagnostics we captured from the build output should be warnings;
// otherwise they should all be errors
var diagSeverity = buildResult == 0 ? DiagnosticMessage.TspSeverity.Warning : DiagnosticMessage.TspSeverity.Error;
this.DiagnosticClassifier.Results
.Select(result => result.ToDiagnosticMessage(this, diagSeverity))
.ForEach(AddDiagnostic);
return buildResult;
}
/// <summary>
@@ -291,13 +343,58 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public abstract BuildScript GetBuildScript();
/// <summary>
/// Produces a diagnostic for the tool status page that we were unable to automatically
/// build the user's project and that they can manually specify a build command. This
/// can be overriden to implement more specific messages depending on the origin of
/// the failure.
/// </summary>
protected virtual void AutobuildFailureDiagnostic() => AddDiagnostic(new DiagnosticMessage(
this.Options.Language,
"autobuild-failure",
"Unable to build project",
visibility: new DiagnosticMessage.TspVisibility(statusPage: true),
plaintextMessage: """
We were unable to automatically build your project.
Set up a manual build command.
"""
));
/// <summary>
/// Returns a build script that can be run upon autobuild failure.
/// </summary>
/// <returns>
/// A build script that reports that we could not automatically detect a suitable build method.
/// </returns>
protected BuildScript AutobuildFailure() =>
BuildScript.Create(actions =>
{
Log(Severity.Error, "Could not auto-detect a suitable build method");
AutobuildFailureDiagnostic();
return 1;
});
/// <summary>
/// Constructs a <see cref="BuildOutputHandler" /> which uses the <see cref="DiagnosticClassifier" />
/// to classify build output. All data also gets written to <paramref name="writer" />.
/// </summary>
/// <param name="writer">
/// The <see cref="TextWriter" /> to which the build output would have normally been written to.
/// This is normally <see cref="Console.Out" /> or <see cref="Console.Error" />.
/// </param>
/// <returns>The constructed <see cref="BuildOutputHandler" />.</returns>
protected BuildOutputHandler BuildOutputHandler(TextWriter writer) => new(data =>
{
if (data is not null)
{
writer.WriteLine(data);
DiagnosticClassifier.ClassifyLine(data);
}
});
/// <summary>
/// Value of CODEQL_EXTRACTOR_<LANG>_ROOT environment variable.
/// </summary>

View File

@@ -11,11 +11,26 @@ using System.Runtime.InteropServices;
namespace Semmle.Autobuild.Shared
{
public delegate void BuildOutputHandler(string? data);
/// <summary>
/// Wrapper around system calls so that the build scripts can be unit-tested.
/// </summary>
public interface IBuildActions
{
/// <summary>
/// Runs a process, captures its output, and provides it asynchronously.
/// </summary>
/// <param name="exe">The exe to run.</param>
/// <param name="args">The other command line arguments.</param>
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
/// <param name="env">Additional environment variables.</param>
/// <param name="onOutput">A handler for stdout output.</param>
/// <param name="onError">A handler for stderr output.</param>
/// <returns>The process exit code.</returns>
int RunProcess(string exe, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError);
/// <summary>
/// Runs a process and captures its output.
/// </summary>
@@ -152,6 +167,17 @@ namespace Semmle.Autobuild.Shared
/// Downloads the resource with the specified URI to a local file.
/// </summary>
void DownloadFile(string address, string fileName);
/// <summary>
/// Creates an <see cref="IDiagnosticsWriter" /> for the given <paramref name="filename" />.
/// </summary>
/// <param name="filename">
/// The path suggesting where the diagnostics should be written to.
/// </param>
/// <returns>
/// A <see cref="IDiagnosticsWriter" /> to which diagnostic entries can be added.
/// </returns>
IDiagnosticsWriter CreateDiagnosticsWriter(string filename);
}
/// <summary>
@@ -173,15 +199,31 @@ namespace Semmle.Autobuild.Shared
if (workingDirectory is not null)
pi.WorkingDirectory = workingDirectory;
// Environment variables can only be used when not redirecting stdout
if (!redirectStandardOutput)
{
if (environment is not null)
environment.ForEach(kvp => pi.Environment[kvp.Key] = kvp.Value);
}
environment?.ForEach(kvp => pi.Environment[kvp.Key] = kvp.Value);
return pi;
}
int IBuildActions.RunProcess(string exe, string args, string? workingDirectory, System.Collections.Generic.IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var pi = GetProcessStartInfo(exe, args, workingDirectory, env, true);
using var p = new Process
{
StartInfo = pi
};
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) => onOutput(e.Data));
p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => onError(e.Data));
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
return p.ExitCode;
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment)
{
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false);
@@ -253,6 +295,8 @@ namespace Semmle.Autobuild.Shared
public void DownloadFile(string address, string fileName) =>
DownloadFileAsync(address, fileName).Wait();
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new DiagnosticsStream(filename);
public static IBuildActions Instance { get; } = new SystemBuildActions();
}
}

View File

@@ -11,22 +11,42 @@ namespace Semmle.Autobuild.Shared
{
private readonly WithDotNet<AutobuildOptionsShared> withDotNet;
/// <summary>
/// A list of paths to files in the project directory which we classified as scripts.
/// </summary>
public IEnumerable<string> CandidatePaths { get; private set; }
/// <summary>
/// The path of the script we decided to run, if any.
/// </summary>
public string? ScriptPath { get; private set; }
public BuildCommandAutoRule(WithDotNet<AutobuildOptionsShared> withDotNet)
{
this.withDotNet = withDotNet;
this.CandidatePaths = new List<string>();
}
/// <summary>
/// A list of extensions that we consider to be for scripts on Windows.
/// </summary>
private readonly IEnumerable<string> winExtensions = new List<string> {
".bat",
".cmd",
".exe"
};
/// <summary>
/// A list of extensions that we consider to be for scripts on Linux.
/// </summary>
private readonly IEnumerable<string> linuxExtensions = new List<string> {
"",
".sh"
};
/// <summary>
/// A list of filenames without extensions that we think might be build scripts.
/// </summary>
private readonly IEnumerable<string> buildScripts = new List<string> {
"build"
};
@@ -35,18 +55,25 @@ namespace Semmle.Autobuild.Shared
{
builder.Log(Severity.Info, "Attempting to locate build script");
// a list of extensions for files that we consider to be scripts on the current platform
var extensions = builder.Actions.IsWindows() ? winExtensions : linuxExtensions;
// a list of combined base script names with the current platform's script extensions
// e.g. for Linux: build, build.sh
var scripts = buildScripts.SelectMany(s => extensions.Select(e => s + e));
var scriptPath = builder.Paths.Where(p => scripts.Any(p.Item1.ToLower().EndsWith)).OrderBy(p => p.Item2).Select(p => p.Item1).FirstOrDefault();
// search through the files in the project directory for paths which end in one of
// the names given by `scripts`, then order them by their distance from the root
this.CandidatePaths = builder.Paths.Where(p => scripts.Any(p.Item1.ToLower().EndsWith)).OrderBy(p => p.Item2).Select(p => p.Item1);
// pick the first matching path, if there is one
this.ScriptPath = this.CandidatePaths.FirstOrDefault();
if (scriptPath is null)
if (this.ScriptPath is null)
return BuildScript.Failure;
var chmod = new CommandBuilder(builder.Actions);
chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}");
chmod.RunCommand("/bin/chmod", $"u+x {this.ScriptPath}");
var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script);
var dir = builder.Actions.GetDirectoryName(scriptPath);
var dir = builder.Actions.GetDirectoryName(this.ScriptPath);
// A specific .NET Core version may be required
return chmodScript & withDotNet(builder, environment =>
@@ -58,7 +85,7 @@ namespace Semmle.Autobuild.Shared
if (vsTools is not null)
command.CallBatFile(vsTools.Path);
command.RunCommand(scriptPath);
command.RunCommand(this.ScriptPath);
return command.Script;
});
}

View File

@@ -46,6 +46,33 @@ namespace Semmle.Autobuild.Shared
/// <returns>The exit code from this build script.</returns>
public abstract int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, out IList<string> stdout);
/// <summary>
/// Runs this build command.
/// </summary>
/// <param name="actions">
/// The interface used to implement the build actions.
/// </param>
/// <param name="startCallback">
/// A call back that is called every time a new process is started. The
/// argument to the call back is a textual representation of the process.
/// </param>
/// <param name="exitCallBack">
/// A call back that is called every time a new process exits. The first
/// argument to the call back is the exit code, and the second argument is
/// an exit message.
/// </param>
/// <param name="onOutput">
/// A handler for data read from stdout.
/// </param>
/// <param name="onError">
/// A handler for data read from stderr.
/// </param>
/// <returns>The exit code from this build script.</returns>
public abstract int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError);
/// <summary>
/// A build script which executes an external program or script.
/// </summary>
private class BuildCommand : BuildScript
{
private readonly string exe, arguments;
@@ -110,8 +137,29 @@ namespace Semmle.Autobuild.Shared
return ret;
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
startCallback(this.ToString(), silent);
var ret = 1;
var retMessage = "";
try
{
ret = actions.RunProcess(exe, arguments, workingDirectory, environment, onOutput, onError);
}
catch (Exception ex)
when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException)
{
retMessage = ex.Message;
}
exitCallBack(ret, retMessage, silent);
return ret;
}
}
/// <summary>
/// A build script which runs a C# function.
/// </summary>
private class ReturnBuildCommand : BuildScript
{
private readonly Func<IBuildActions, int> func;
@@ -127,8 +175,13 @@ namespace Semmle.Autobuild.Shared
stdout = Array.Empty<string>();
return func(actions);
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError) => func(actions);
}
/// <summary>
/// Allows two build scripts to be composed sequentially.
/// </summary>
private class BindBuildScript : BuildScript
{
private readonly BuildScript s1;
@@ -175,6 +228,32 @@ namespace Semmle.Autobuild.Shared
stdout = @out;
return ret2;
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
int ret1;
if (s2a is not null)
{
var stdout1 = new List<string>();
var onOutputWrapper = new BuildOutputHandler(data =>
{
if (data is not null)
stdout1.Add(data);
onOutput(data);
});
ret1 = s1.Run(actions, startCallback, exitCallBack, onOutputWrapper, onError);
return s2a(stdout1, ret1).Run(actions, startCallback, exitCallBack, onOutput, onError);
}
if (s2b is not null)
{
ret1 = s1.Run(actions, startCallback, exitCallBack, onOutput, onError);
return s2b(ret1).Run(actions, startCallback, exitCallBack, onOutput, onError);
}
throw new InvalidOperationException("Unexpected error");
}
}
/// <summary>
@@ -260,6 +339,23 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public static BuildScript Try(BuildScript s) => s | Success;
/// <summary>
/// Creates a build script that runs the build script <paramref name="s" />. If
/// running <paramref name="s" /> fails, <paramref name="k" /> is invoked with
/// the exit code.
/// </summary>
/// <param name="s">The build script to run.</param>
/// <param name="k">
/// The callback that is invoked if <paramref name="s" /> failed.
/// </param>
/// <returns>The build script which implements this.</returns>
public static BuildScript OnFailure(BuildScript s, Action<int> k) =>
new BindBuildScript(s, ret => Create(actions =>
{
if (!Succeeded(ret)) k(ret);
return ret;
}));
/// <summary>
/// Creates a build script that deletes the given directory.
/// </summary>

View File

@@ -0,0 +1,96 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{
/// <summary>
/// Direct results result from the successful application of a <see cref="DiagnosticRule" />,
/// which can later be converted to a corresponding <see cref="DiagnosticMessage" />.
/// </summary>
public interface IDiagnosticsResult
{
/// <summary>
/// Produces a <see cref="DiagnosticMessage" /> corresponding to this result.
/// </summary>
/// <param name="builder">
/// The autobuilder to use for constructing the base <see cref="DiagnosticMessage" />.
/// </param>
/// <param name="severity">
/// An optional severity value which overrides the default severity of the diagnostic.
/// </param>
/// <returns>The <see cref="DiagnosticMessage" /> corresponding to this result.</returns>
DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared;
}
public class DiagnosticRule
{
/// <summary>
/// The pattern against which this rule matches build output.
/// </summary>
public Regex Pattern { get; }
/// <summary>
/// Constructs a diagnostic rule for the given <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(Regex pattern)
{
this.Pattern = pattern;
}
/// <summary>
/// Constructs a diagnostic rule for the given regular expression <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(string pattern)
{
this.Pattern = new Regex(pattern, RegexOptions.Compiled);
}
/// <summary>
/// Used by a <see cref="DiagnosticClassifier" /> <paramref name="classifier" /> to
/// signal that the rule has matched some build output with <paramref name="match" />.
/// </summary>
/// <param name="classifier">The classifier which is firing the rule.</param>
/// <param name="match">The <see cref="Match" /> that resulted from applying the rule.</param>
public virtual void Fire(DiagnosticClassifier classifier, Match match) { }
}
public class DiagnosticClassifier
{
private readonly List<DiagnosticRule> rules;
public readonly List<IDiagnosticsResult> Results;
public DiagnosticClassifier()
{
this.rules = new List<DiagnosticRule>();
this.Results = new List<IDiagnosticsResult>();
}
/// <summary>
/// Adds <paramref name="rule" /> to this classifier.
/// </summary>
/// <param name="rule">The rule to add.</param>
protected void AddRule(DiagnosticRule rule)
{
this.rules.Add(rule);
}
/// <summary>
/// Applies all of this classifier's rules to <paramref name="line" /> to see which match.
/// </summary>
/// <param name="line">The line to which the rules should be applied to.</param>
public void ClassifyLine(string line)
{
this.rules.ForEach(rule =>
{
var match = rule.Pattern.Match(line);
if (match.Success)
{
rule.Fire(this, match);
}
});
}
}
}

View File

@@ -0,0 +1,13 @@
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{
public static class EnvVars
{
public const string Platform = "CODEQL_PLATFORM";
public static string Root(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_ROOT";
public static string TrapDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_TRAP_DIR";
public static string SourceArchiveDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_SOURCE_ARCHIVE_DIR";
public static string DiagnosticDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_DIAGNOSTIC_DIR";
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Semmle.Autobuild.Shared
{
public static class MarkdownUtil
{
/// <summary>
/// Formats items as markdown inline code.
/// </summary>
/// <returns>A function which formats items as markdown inline code.</returns>
public static readonly Func<string, string> CodeFormatter = item => $"`{item}`";
/// <summary>
/// Formats the string as a markdown link.
/// </summary>
/// <param name="link">The URL for the link.</param>
/// <param name="title">The text that is displayed.</param>
/// <returns>A string containing a markdown-formatted link.</returns>
public static string ToMarkdownLink(this string link, string title) => $"[{title}]({link})";
/// <summary>
/// Renders <see cref="projects" /> as a markdown list of the project paths.
/// </summary>
/// <param name="projects">
/// The list of projects whose paths should be rendered as a markdown list.
/// </param>
/// <param name="limit">The maximum number of items to include in the list.</param>
/// <returns>Returns the markdown list as a string.</returns>
public static string ToMarkdownList(this IEnumerable<IProjectOrSolution> projects, int? limit = null)
{
return projects.ToMarkdownList(p => $"`{p.FullPath}`", limit);
}
/// <summary>
/// Renders <see cref="items" /> as a markdown list.
/// </summary>
/// <typeparam name="T">The item type.</typeparam>
/// <param name="items">The list that should be formatted as a markdown list.</param>
/// <param name="formatter">A function which converts individual items into a string representation.</param>
/// <param name="limit">The maximum number of items to include in the list.</param>
/// <returns>Returns the markdown list as a string.</returns>
public static string ToMarkdownList<T>(this IEnumerable<T> items, Func<T, string> formatter, int? limit = null)
{
var sb = new StringBuilder();
// if there is a limit, take at most that many items from the start of the list
var list = limit is not null ? items.Take(limit.Value) : items;
sb.Append(string.Join('\n', list.Select(item => $"- {formatter(item)}")));
// if there were more items than allowed in the list, add an extra item indicating
// how many more items there were
var length = items.Count();
if (limit is not null && length > limit)
{
sb.Append($"\n- and {length - limit} more. View the CodeQL logs for a full list.");
}
return sb.ToString();
}
}
}

View File

@@ -1,7 +1,6 @@
using Semmle.Util.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace Semmle.Autobuild.Shared
{
@@ -31,6 +30,11 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public class MsBuildRule : IBuildRule<AutobuildOptionsShared>
{
/// <summary>
/// A list of solutions or projects which failed to build.
/// </summary>
public readonly List<IProjectOrSolution> FailedProjectsOrSolutions = new();
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
{
if (!builder.ProjectsOrSolutionsToBuild.Any())
@@ -128,7 +132,13 @@ namespace Semmle.Autobuild.Shared
command.Argument(builder.Options.MsBuildArguments);
ret &= command.Script;
// append the build script which invokes msbuild to the overall build script `ret`;
// we insert a check that building the current project or solution was successful:
// if it was not successful, we add it to `FailedProjectsOrSolutions`
ret &= BuildScript.OnFailure(command.Script, ret =>
{
FailedProjectsOrSolutions.Add(projectOrSolution);
});
}
return ret;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{

View File

@@ -1,4 +1,4 @@
namespace Semmle.Autobuild.Shared
namespace Semmle.Util
{
public sealed class Language
{

View File

@@ -15,6 +15,7 @@
<ItemGroup>
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Semmle.Util
{
/// <summary>
/// Represents diagnostic messages for the tool status page.
/// </summary>
public class DiagnosticMessage
{
/// <summary>
/// Represents sources of diagnostic messages.
/// </summary>
public class TspSource
{
/// <summary>
/// An identifier under which it makes sense to group this diagnostic message.
/// This is used to build the SARIF reporting descriptor object.
/// </summary>
public string Id { get; }
/// <summary>
/// Display name for the ID. This is used to build the SARIF reporting descriptor object.
/// </summary>
public string Name { get; }
/// <summary>
/// Name of the CodeQL extractor. This is used to identify which tool component the reporting descriptor object should be nested under in SARIF.
/// </summary>
public string? ExtractorName { get; }
public TspSource(string id, string name, string? extractorName = null)
{
Id = id;
Name = name;
ExtractorName = extractorName;
}
}
/// <summary>
/// Enumerates severity levels for diagnostics.
/// </summary>
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))]
public enum TspSeverity
{
Note,
Warning,
Error
}
/// <summary>
/// Stores flags indicating where the diagnostic should be displayed.
/// </summary>
public class TspVisibility
{
/// <summary>
/// A read-only instance of <see cref="TspVisibility" /> which indicates that the
/// diagnostic should be used in all supported locations.
/// </summary>
public static readonly TspVisibility All = new(true, true, true);
/// <summary>
/// True if the message should be displayed on the status page (defaults to false).
/// </summary>
public bool? StatusPage { get; }
/// <summary>
/// True if the message should be counted in the diagnostics summary table printed by
/// <c>codeql database analyze</c> (defaults to false).
/// </summary>
public bool? CLISummaryTable { get; }
/// <summary>
/// True if the message should be sent to telemetry (defaults to false).
/// </summary>
public bool? Telemetry { get; }
public TspVisibility(bool? statusPage = null, bool? cliSummaryTable = null, bool? telemetry = null)
{
this.StatusPage = statusPage;
this.CLISummaryTable = cliSummaryTable;
this.Telemetry = telemetry;
}
}
/// <summary>
/// Represents source code locations for diagnostic messages.
/// </summary>
public class TspLocation
{
/// <summary>
/// Path to the affected file if appropriate, relative to the source root.
/// </summary>
public string? File { get; }
/// <summary>
/// The line where the range to which the diagnostic relates to starts.
/// </summary>
public int? StartLine { get; }
/// <summary>
/// The column where the range to which the diagnostic relates to starts.
/// </summary>
public int? StartColumn { get; }
/// <summary>
/// The line where the range to which the diagnostic relates to ends.
/// </summary>
public int? EndLine { get; }
/// <summary>
/// The column where the range to which the diagnostic relates to ends.
/// </summary>
public int? EndColumn { get; }
public TspLocation(string? file = null, int? startLine = null, int? startColumn = null, int? endLine = null, int? endColumn = null)
{
this.File = file;
this.StartLine = startLine;
this.StartColumn = startColumn;
this.EndLine = endLine;
this.EndColumn = endColumn;
}
}
/// <summary>
/// ISO 8601 timestamp.
/// </summary>
public string Timestamp { get; }
/// <summary>
/// The source of the diagnostic message.
/// </summary>
public TspSource Source { get; }
/// <summary>
/// GitHub flavored Markdown formatted message. Should include inline links to any help pages.
/// </summary>
public string? MarkdownMessage { get; }
/// <summary>
/// Plain text message. Used by components where the string processing needed to support
/// Markdown is cumbersome.
/// </summary>
public string? PlaintextMessage { get; }
/// <summary>
/// List of help links intended to supplement <see cref="PlaintextMessage" />.
/// </summary>
public List<string> HelpLinks { get; }
/// <summary>
/// SARIF severity.
/// </summary>
public TspSeverity? Severity { get; }
/// <summary>
/// If true, then this message won't be presented to users.
/// </summary>
public bool Internal { get; }
public TspVisibility Visibility { get; }
public TspLocation Location { get; }
/// <summary>
/// Structured metadata about the diagnostic message.
/// </summary>
public Dictionary<string, object> Attributes { get; }
public DiagnosticMessage(
Language language, string id, string name, string? markdownMessage = null, string? plaintextMessage = null,
TspVisibility? visibility = null, TspLocation? location = null, TspSeverity? severity = TspSeverity.Error,
DateTime? timestamp = null, bool? intrnl = null
)
{
this.Source = new TspSource(
id: $"{language.UpperCaseName.ToLower()}/autobuilder/{id}",
name: name,
extractorName: language.UpperCaseName.ToLower()
);
this.Timestamp = (timestamp ?? DateTime.UtcNow).ToString("o", CultureInfo.InvariantCulture);
this.HelpLinks = new List<string>();
this.Attributes = new Dictionary<string, object>();
this.Severity = severity;
this.Visibility = visibility ?? TspVisibility.All;
this.Location = location ?? new TspLocation();
this.Internal = intrnl ?? false;
this.MarkdownMessage = markdownMessage;
this.PlaintextMessage = plaintextMessage;
}
}
/// <summary>
/// Provides the ability to write diagnostic messages to some output.
/// </summary>
public interface IDiagnosticsWriter
{
/// <summary>
/// Adds <paramref name="message" /> as a new diagnostics entry.
/// </summary>
/// <param name="message">The diagnostics entry to add.</param>
void AddEntry(DiagnosticMessage message);
}
/// <summary>
/// A wrapper around an underlying <see cref="StreamWriter" /> which allows
/// <see cref="DiagnosticMessage" /> objects to be serialized to it.
/// </summary>
public sealed class DiagnosticsStream : IDiagnosticsWriter, IDisposable
{
private readonly JsonSerializer serializer;
private readonly StreamWriter writer;
/// <summary>
/// Initialises a new <see cref="DiagnosticsStream" /> for a file at <paramref name="path" />.
/// </summary>
/// <param name="path">The path to the file that should be created.</param>
public DiagnosticsStream(string path)
{
this.writer = File.CreateText(path);
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
serializer = new JsonSerializer
{
ContractResolver = contractResolver,
NullValueHandling = NullValueHandling.Ignore
};
}
/// <summary>
/// Adds <paramref name="message" /> as a new diagnostics entry.
/// </summary>
/// <param name="message">The diagnostics entry to add.</param>
public void AddEntry(DiagnosticMessage message)
{
serializer.Serialize(writer, message);
writer.Flush();
}
/// <summary>
/// Releases all resources used by the <see cref="DiagnosticsStream" /> object.
/// </summary>
public void Dispose()
{
writer.Dispose();
}
}
}

View File

@@ -1,3 +1,7 @@
## 1.4.4
No user-facing changes.
## 1.4.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.4.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.4.3
lastReleaseVersion: 1.4.4

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.4.4-dev
version: 1.4.5-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 1.4.4
No user-facing changes.
## 1.4.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.4.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.4.3
lastReleaseVersion: 1.4.4

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.4.4-dev
version: 1.4.5-dev
groups:
- csharp
- solorigate

View File

@@ -0,0 +1,36 @@
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL found some projects which cannot be built with .NET Core:\n\n- `test.csproj`",
"severity": "warning",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/dotnet-incompatible-projects",
"name": "Some projects are incompatible with .NET Core"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/msbuild-build-failure",
"name": "Some projects or solutions failed to build using MSBuild"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Example</RootNamespace>
<AssemblyName>Example</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,5 @@
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], db=None, lang="csharp", runFunction=runUnsuccessfully)
check_diagnostics()

View File

@@ -0,0 +1,36 @@
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.sln`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/msbuild-build-failure",
"name": "Some projects or solutions failed to build using MSBuild"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "Some project files were not found when CodeQL built your project:\n\n- `Example.csproj`\n- `Example.Test.csproj`\n\nThis may lead to subsequent failures. You can check for common causes for missing project files:\n\n- Ensure that the project is built using the [intended operating system](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on) and that filenames on case-sensitive platforms are correctly specified.\n- If your repository uses Git submodules, ensure that those are [checked out](https://github.com/actions/checkout#usage) before the CodeQL action is run.\n- If you auto-generate some project files as part of your build process, ensure that these are generated before the CodeQL action is run.",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/missing-project-files",
"name": "Missing project files"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,5 @@
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], db=None, lang="csharp", runFunction=runUnsuccessfully)
check_diagnostics()

View File

@@ -0,0 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example.csproj", "{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Test", "Example.Test.csproj", "{F4587B5F-9918-4079-9291-5A08CD9761FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}.Debug|x86.ActiveCfg = Debug|x86
{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}.Debug|x86.Build.0 = Debug|x86
{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}.Release|x86.ActiveCfg = Release|x86
{F70CE6B6-1735-4AD2-B1EB-B91FCD1012D1}.Release|x86.Build.0 = Release|x86
{F4587B5F-9918-4079-9291-5A08CD9761FB}.Debug|x86.ActiveCfg = Debug|x86
{F4587B5F-9918-4079-9291-5A08CD9761FB}.Debug|x86.Build.0 = Debug|x86
{F4587B5F-9918-4079-9291-5A08CD9761FB}.Release|x86.ActiveCfg = Release|x86
{F4587B5F-9918-4079-9291-5A08CD9761FB}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,54 @@
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL was unable to build the following projects using .NET Core:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/dotnet-build-failure",
"name": "Some projects or solutions failed to build using .NET Core"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/msbuild-build-failure",
"name": "Some projects or solutions failed to build using MSBuild"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "[Configure your workflow](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-xamarin-applications) for this SDK before running CodeQL.",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/missing-xamarin-ios-sdk",
"name": "Missing Xamarin SDK for iOS"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LanguageTargets>$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets</LanguageTargets>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,5 @@
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], db=None, lang="csharp", runFunction=runUnsuccessfully)
check_diagnostics()

View File

@@ -1,3 +1,5 @@
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create(['dotnet build'], test_db="default-db", db=None, lang="csharp")
run_codeql_database_create(['dotnet build'], db=None, lang="csharp")
check_diagnostics()

View File

@@ -1,8 +1,11 @@
import os
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create(['dotnet pack'], test_db="default-db", db=None, lang="csharp")
run_codeql_database_create(['dotnet pack'], db=None, lang="csharp")
## Check that the NuGet package is created.
if not os.path.isfile("bin/Debug/dotnet_pack.1.0.0.nupkg"):
raise Exception("The NuGet package was not created.")
raise Exception("The NuGet package was not created.")
check_diagnostics()

View File

@@ -1,9 +1,12 @@
import os
from create_database_utils import *
from diagnostics_test_utils import *
artifacts = 'bin/Temp'
run_codeql_database_create([f"dotnet publish -o {artifacts}"], test_db="default-db", db=None, lang="csharp")
run_codeql_database_create([f"dotnet publish -o {artifacts}"], db=None, lang="csharp")
## Check that the publish folder is created.
if not os.path.isdir(artifacts):
raise Exception("The publish artifact folder was not created.")
raise Exception("The publish artifact folder was not created.")
check_diagnostics()

View File

@@ -1,5 +1,6 @@
import os
from create_database_utils import *
from diagnostics_test_utils import *
def run_codeql_database_create_stdout(args, dbname):
stdout = open(dbname + "file.txt", 'w+')
@@ -16,32 +17,40 @@ def check_build_out(msg, s):
# no arguments
s = run_codeql_database_create_stdout(['dotnet run'], "test-db")
check_build_out("Default reply", s)
check_diagnostics()
# no arguments, but `--`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test-db', 'dotnet run --'], "test2-db")
check_build_out("Default reply", s)
check_diagnostics(diagnostics_dir="test2-db/diagnostic")
# one argument, no `--`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test2-db', 'dotnet run hello'], "test3-db")
check_build_out("Default reply", s)
check_diagnostics(diagnostics_dir="test3-db/diagnostic")
# one argument, but `--`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test3-db', 'dotnet run -- hello'], "test4-db")
check_build_out("Default reply", s)
check_diagnostics(diagnostics_dir="test4-db/diagnostic")
# two arguments, no `--`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test4-db', 'dotnet run hello world'], "test5-db")
check_build_out("hello, world", s)
check_diagnostics(diagnostics_dir="test5-db/diagnostic")
# two arguments, and `--`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test5-db', 'dotnet run -- hello world'], "test6-db")
check_build_out("hello, world", s)
check_diagnostics(diagnostics_dir="test6-db/diagnostic")
# shared compilation enabled; tracer should override by changing the command
# to `dotnet run -p:UseSharedCompilation=true -p:UseSharedCompilation=false -- hello world`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test6-db', 'dotnet run -p:UseSharedCompilation=true -- hello world'], "test7-db")
check_build_out("hello, world", s)
check_diagnostics(diagnostics_dir="test7-db/diagnostic")
# option passed into `dotnet run`
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test7-db', 'dotnet build', 'dotnet run --no-build hello world'], "test8-db")
check_build_out("hello, world", s)
check_diagnostics(diagnostics_dir="test8-db/diagnostic")

View File

@@ -1,4 +1,6 @@
from create_database_utils import *
from diagnostics_test_utils import *
# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET`
run_codeql_database_create([], test_db="default-db", db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
run_codeql_database_create([], db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
check_diagnostics()

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exit 1

View File

@@ -0,0 +1,36 @@
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL attempted to build your project using a script located at `build.sh`, which failed. Set up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/script-failure",
"name": "Unable to build project using build script"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL could not find any project or solution files in your repository. Set up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/no-projects-or-solutions",
"name": "No project or solutions files found"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,5 @@
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], db=None, lang="csharp", runFunction=runUnsuccessfully)
check_diagnostics()

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exit 1

View File

@@ -0,0 +1,36 @@
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL could not find any project or solution files in your repository. Set up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/no-projects-or-solutions",
"name": "No project or solutions files found"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"attributes": {},
"helpLinks": [],
"internal": false,
"location": {},
"markdownMessage": "CodeQL found multiple potential build scripts for your project and attempted to run `build.sh`, which failed. This may not be the right build script for your project. Set up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
"severity": "error",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/multiple-build-scripts",
"name": "There are multiple potential build scripts"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

Some files were not shown because too many files have changed in this diff Show More