|
33 | 33 | db_create_failures = [] |
34 | 34 |
|
35 | 35 |
|
| 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 | + |
36 | 67 | def print_conditionally(*message): |
37 | 68 | """ |
38 | 69 | Prints the message if the verbose flag is set. |
@@ -370,7 +401,7 @@ def db_create_for_external_driver(sln_file, config, platform): |
370 | 401 | out2 = subprocess.run([codeql_path, "database", "create", db_loc, "--overwrite", "-l", "cpp", "--source-root="+workdir, |
371 | 402 | "--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" ], |
372 | 403 | cwd=workdir, |
373 | | - shell=True, capture_output=True ) |
| 404 | + shell=True, capture_output=True, env=_build_subprocess_env() ) |
374 | 405 | if out2.returncode != 0: |
375 | 406 | print("Error in codeql database create: " + db_loc) |
376 | 407 | print("Return code: " + str(out2.returncode)) |
@@ -419,8 +450,10 @@ def create_codeql_test_database(ql_test): |
419 | 450 | print_conditionally(" - Command to run: " + str(codeql_command)) |
420 | 451 | # Always capture output so that on failure we can surface the underlying |
421 | 452 | # 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). |
422 | 455 | out2 = subprocess.run(codeql_command, |
423 | | - shell=True, capture_output=True ) |
| 456 | + shell=True, capture_output=True, env=_build_subprocess_env() ) |
424 | 457 | if out2.returncode != 0: |
425 | 458 | print("Error in codeql database create: " + ql_test.get_ql_name()) |
426 | 459 | print("Command: " + str(codeql_command)) |
|
0 commit comments