Skip to content

WatermarkTask: NullReferenceException when a user license entry is null #75

Description

@gfraiteur

Summary

WatermarkTask.Execute enumerates the user licenses and dereferences each entry without testing it for null. When one entry is null, the whole compilation dies with an unhandled NullReferenceException reported as PS0099.

Symptom

error PS0099: Unhandled exception (postsharp-x64-srv.exe 2024.0.24 debug | .NET Framework 4.8.1 (X64)):
              System.NullReferenceException: Object reference not set to an instance of an object.
error PS0099:   at PostSharp.Sdk.Extensibility.Tasks.WatermarkTask.<>c.<Execute>b__0_1(LicenseConfiguration l)
error PS0099:   at System.Linq.Enumerable.All[TSource](IEnumerable`1 source, Func`2 predicate)
error PS0099:   at PostSharp.Sdk.Extensibility.Tasks.WatermarkTask.Execute()
error PS0099:   at PostSharp.Sdk.Extensibility.Project.ExecutePhase(TaskPhase phase)
error PS0099:   at PostSharp.Sdk.Extensibility.Project.Execute()
error PS0099:   at PostSharp.Compiler.Hosting.PostSharpObject.InvokeProject(ProjectInvocation projectInvocation)

Diagnosis

if ( LocalUserLicenseManager.Instance.UserLicenses.All( l => l.License != null && l.License.RequiresWatermark() ) )

The lambda guards l.License, so the exception can only come from l itself being null: LocalUserLicenseManager.Instance.UserLicenses contained a null element.

What produces the null element has not been established. Worth noting that the affected process is postsharp-x64-srv.exe, the persistent pipe server, which serves many compilations in sequence, so a collection being enumerated while it is populated is one candidate — but that is a hypothesis, not a finding.

Whatever the origin, the task should not turn it into an unhandled exception. RequiresWatermark decides whether the assembly is watermarked as built with an evaluation licence, so a null entry should be treated as "does not require a watermark" and skipped, exactly like an entry whose License is null.

Frequency

Observed once, in a CI run of PostSharp 2024.0 / Test .NET Framework: Build Tests (Core), on the test Aspects.StateMachine.Iterator_OnException_OptimizeOff. That job runs WatermarkTask for each of its 371 tests, and only that one failed; the OptimizeOn variant of the same test passed seconds later, which is consistent with the null being transient rather than determined by the code under test.

Over the last 60 recorded runs of that test, it failed twice. The other failure, on an unrelated branch of the 2026.0 line, was a different licensing error (PS0242: No valid license key has been installed) and shows no WatermarkTask exception, so the two are not the same defect. What they have in common is that this test is sensitive to the licensing state of the agent.

Affected source

  • Core/PostSharp.Compiler.Engine/Sdk/Extensibility/Tasks/WatermarkTask.csExecute

Proposed fix

Drop the whole WatermarkTask as obsolete.

Environment

  • PostSharp 2024.0.24, debug build, postsharp-x64-srv.exe, .NET Framework 4.8.1 (X64)

-- Claude for Gael Fraiteur

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions