CodeQL queries 1.25
Skip to end of metadata
Go to start of metadata

Name: Field is never assigned a non-default value

Description: Fields are automatically initialised with the default values for their type, which may not be the intent: prefer explicit initialisation.

ID: cs/unassigned-field

Kind: problem

Severity: recommendation

Precision: low

Query: NonAssignedFields.ql
/**
 * @name Field is never assigned a non-default value
 * @description Fields are automatically initialised with the default values for their type, which may not be the intent: prefer explicit initialisation.
 * @kind problem
 * @problem.severity recommendation
 * @precision low
 * @id cs/unassigned-field
 * @tags reliability
 *       maintainability
 *       useless-code
 *       external/cwe/cwe-457
 */

import csharp
import semmle.code.csharp.frameworks.System
import semmle.code.csharp.frameworks.system.runtime.InteropServices

// Any field transitively contained in t.
Field getANestedField(ValueOrRefType t) {
  result.getDeclaringType() = t
  or
  exists(Field mid |
    mid = getANestedField(t) and
    mid.getType() = result.getDeclaringType()
  )
}

// Any ValueOrRefType referenced by a Type, including TypeParameters.
ValueOrRefType getAReferencedType(Type t) {
  result = t
  or
  result = t.(TypeParameter).getASuppliedType()
}

predicate isTypeExternallyInitialized(ValueOrRefType t) {
  // The type got created via a call to PtrToStructure().
  exists(MethodCall mc, Type t0, Expr arg |
    mc.getTarget() = any(SystemRuntimeInteropServicesMarshalClass c).getPtrToStructureTypeMethod() and
    t = getAReferencedType(t0) and
    arg = mc.getArgument(1)
  |
    t0 = arg.(TypeofExpr).getTypeAccess().getTarget()
    or
    t0 = arg.getType()
  )
  or
  // An extern method exists which could initialize the type.
  exists(Method m, Parameter p |
    isExternMethod(m) and
    p = m.getAParameter() and
    t = p.getType()
  |
    p.isOut() or p.isRef()
  )
  or
  // The data structure has been cast to a pointer - all bets are off.
  exists(CastExpr c | t = getAReferencedType(c.getTargetType().(PointerType).getReferentType()))
}

// The type is potentially marshaled using an extern or interop.
predicate isFieldExternallyInitialized(Field f) {
  exists(ValueOrRefType t |
    f = getANestedField(t) and
    isTypeExternallyInitialized(t)
  )
}

predicate isExternMethod(Method externMethod) {
  externMethod.isExtern()
  or
  externMethod.getAnAttribute().getType() instanceof
    SystemRuntimeInteropServicesDllImportAttributeClass
  or
  externMethod.getDeclaringType().getAnAttribute().getType() instanceof
    SystemRuntimeInteropServicesComImportAttributeClass
}

from Field f, FieldRead fa
where
  f.fromSource() and
  not extractionIsStandalone() and
  not f.isReadOnly() and
  not f.isConst() and
  not f.getDeclaringType() instanceof Enum and
  not f.getType() instanceof Struct and
  not exists(Assignment ae, Field g |
    ae.getLValue().(FieldAccess).getTarget() = g and
    g.getSourceDeclaration() = f and
    not ae.getRValue() instanceof NullLiteral
  ) and
  not exists(MethodCall mc, int i, Field g |
    exists(Parameter p | mc.getTarget().getParameter(i) = p | p.isOut() or p.isRef()) and
    mc.getArgument(i) = g.getAnAccess() and
    g.getSourceDeclaration() = f
  ) and
  not isFieldExternallyInitialized(f) and
  not exists(f.getAnAttribute()) and
  not exists(Expr init, Field g |
    g.getSourceDeclaration() = f and
    g.getInitializer() = init and
    not init instanceof NullLiteral
  ) and
  not exists(AssignOperation ua, Field g |
    ua.getLValue().(FieldAccess).getTarget() = g and
    g.getSourceDeclaration() = f
  ) and
  not exists(MutatorOperation op |
    op.getAnOperand().(FieldAccess).getTarget().getSourceDeclaration() = f
  ) and
  exists(Field g |
    fa.getTarget() = g and
    g.getSourceDeclaration() = f
  )
select f,
  "The field '" + f.getName() + "' is never explicitly assigned a value, yet it is read $@.", fa,
  "here"

Fields are automatically given a default value when declared. If they are never assigned then they will always have their default value.

Recommendation

Check if an assignment to the field has been accidentally omitted. If it hasn't then consider removing the variable or explicitly initializing the field to its default value.

Example

In this example the programmer has forgotten to initialize the "name" field. This is the kind of mistake that this rule can detect.

class Person
{
    private string name;
    private int age;
    public Person(string name, int age)
    {
        this.age = age;
    }
}

References