Skip to content

Commit e0230d0

Browse files
CopilotNateD-MSFT
andauthored
Fix LNK1318 mspdbsrv race; wire --jobs into workflow
Agent-Logs-Url: https://github.com/microsoft/Windows-Driver-Developer-Supplemental-Tools/sessions/694e9d3d-f942-4564-8e96-8af21abeb87a Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com>
1 parent e49e5ca commit e0230d0

2 files changed

Lines changed: 43 additions & 4 deletions

File tree

.github/workflows/build-codeql.yaml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ jobs:
125125
- name: Run test script
126126
shell: pwsh
127127
run: |
128-
$pyArgs = @('src\drivers\test\build_create_analyze_test.py', '--codeql_path', '.\codeql-cli\codeql.exe', '--no_build', '-v')
128+
# Run per-test build/analyze in parallel inside the script. Default is
129+
# one worker per logical CPU (--jobs <N>); each worker is isolated to
130+
# its own working/, TestDB/, and AnalysisFiles/<name>.sarif paths.
131+
$pyArgs = @('src\drivers\test\build_create_analyze_test.py', '--codeql_path', '.\codeql-cli\codeql.exe', '--no_build', '-v', '--jobs', "$env:NUMBER_OF_PROCESSORS")
129132
if ("${{ github.event_name }}" -ne "pull_request") {
130133
$pyArgs += '--compare_results'
131134
}
@@ -219,7 +222,10 @@ jobs:
219222
- name: Run test script
220223
shell: pwsh
221224
run: |
222-
$pyArgs = @('src\drivers\test\build_create_analyze_test.py', '--codeql_path', '.\codeql-cli\codeql.exe', '--no_build', '-v')
225+
# Run per-test build/analyze in parallel inside the script. Default is
226+
# one worker per logical CPU (--jobs <N>); each worker is isolated to
227+
# its own working/, TestDB/, and AnalysisFiles/<name>.sarif paths.
228+
$pyArgs = @('src\drivers\test\build_create_analyze_test.py', '--codeql_path', '.\codeql-cli\codeql.exe', '--no_build', '-v', '--jobs', "$env:NUMBER_OF_PROCESSORS")
223229
if ("${{ github.event_name }}" -ne "pull_request") {
224230
$pyArgs += '--compare_results'
225231
}

src/drivers/test/build_create_analyze_test.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,37 @@
3333
db_create_failures = []
3434

3535

36+
def _build_subprocess_env():
37+
"""
38+
Build an environment dict for subprocess invocations of msbuild/link.exe so
39+
that each concurrent invocation talks to its own private ``mspdbsrv.exe``
40+
PDB server.
41+
42+
When the parallel test runner spawns multiple `codeql database create` ->
43+
`msbuild` -> `link.exe` chains concurrently, all link.exe processes
44+
inherit the same per-user `_MSPDBSRV_ENDPOINT_` and contend on a single
45+
`mspdbsrv.exe` for PDB RPC. Under load this races and the RPC server
46+
occasionally becomes unavailable, producing:
47+
48+
LINK : fatal error LNK1318: Unexpected PDB error; RPC (23) '(0x000006BA)'
49+
50+
Setting a unique `_MSPDBSRV_ENDPOINT_` per invocation makes link.exe
51+
spawn its own dedicated mspdbsrv with a unique RPC endpoint, eliminating
52+
cross-worker contention. This is the Microsoft-recommended fix for parallel
53+
MSVC builds. See https://learn.microsoft.com/cpp/error-messages/tool-errors/linker-tools-error-lnk1318.
54+
"""
55+
env = os.environ.copy()
56+
env["_MSPDBSRV_ENDPOINT_"] = "wddst_{pid}_{tid}_{n}".format(
57+
pid=os.getpid(),
58+
tid=threading.get_ident(),
59+
n=next(_endpoint_counter),
60+
)
61+
return env
62+
63+
64+
_endpoint_counter = itertools.count()
65+
66+
3667
def print_conditionally(*message):
3768
"""
3869
Prints the message if the verbose flag is set.
@@ -370,7 +401,7 @@ def db_create_for_external_driver(sln_file, config, platform):
370401
out2 = subprocess.run([codeql_path, "database", "create", db_loc, "--overwrite", "-l", "cpp", "--source-root="+workdir,
371402
"--command=msbuild "+ sln_file+ " -clp:Verbosity=m -t:clean,build -property:Configuration="+config+" -property:Platform="+platform + " -p:TargetVersion=Windows10 -p:SignToolWS=/fdws -p:DriverCFlagAddOn=/wd4996 -noLogo" ],
372403
cwd=workdir,
373-
shell=True, capture_output=True )
404+
shell=True, capture_output=True, env=_build_subprocess_env() )
374405
if out2.returncode != 0:
375406
print("Error in codeql database create: " + db_loc)
376407
print("Return code: " + str(out2.returncode))
@@ -419,8 +450,10 @@ def create_codeql_test_database(ql_test):
419450
print_conditionally(" - Command to run: " + str(codeql_command))
420451
# Always capture output so that on failure we can surface the underlying
421452
# msbuild / tracer diagnostics (which CodeQL writes mostly to stdout).
453+
# ``env=`` injects a unique ``_MSPDBSRV_ENDPOINT_`` so concurrent workers
454+
# do not race on a shared mspdbsrv.exe (LNK1318 RPC errors).
422455
out2 = subprocess.run(codeql_command,
423-
shell=True, capture_output=True )
456+
shell=True, capture_output=True, env=_build_subprocess_env() )
424457
if out2.returncode != 0:
425458
print("Error in codeql database create: " + ql_test.get_ql_name())
426459
print("Command: " + str(codeql_command))

0 commit comments

Comments
 (0)