Skip to content

Avoid lambdas as default member initializers in feature options (MSVC ODR violation) - #4900

Merged
ahojnnes merged 1 commit into
colmap:mainfrom
Tobias-Fischer:fix-msvc-lambda-member-initializers
Oct 27, 2026
Merged

ahojnnes merged 1 commit into
colmap:mainfrom
Tobias-Fischer:fix-msvc-lambda-member-initializers

Conversation

@Tobias-Fischer

Copy link
Copy Markdown
Contributor

AlikedMatchingOptions, LomaMatchingOptions and SiftMatchingOptions initialize members with immediately invoked lambdas (brute_force = []() { ... }();). MSVC numbers such lambdas with a counter per translation unit, while their mangled name is only scoped to the enclosing class (e.g. colmap::AlikedMatchingOptions::<lambda_2_>). Translation units that include these headers in a different order (e.g. sift.h before aliked.h) therefore define identically named lambdas with different bodies, and the linker keeps only one of them — an ODR violation.

We hit this in the conda-forge pycolmap build on Windows, where import pycolmap crashed with heap corruption (0xc0000374). With symbols and full page heap, the faulting frame is colmap::AlikedMatchingOptions::<lambda_2_>::operator() at aliked.h:65, i.e. the name of the LightGlue initializer but the body of the brute-force one: it writes a BruteForceONNXMatchingOptions (0x38 bytes, model_path at 0x18) into the LightGlueONNXMatchingOptions member (0x28 bytes), past the end of the allocation. Whether it triggers depends on link order and include context, which is why it appeared after an unrelated dependency change (Qt5 → Qt6).

This replaces the four lambda initializers with named inline functions, which have the same name in every translation unit. No behavior change otherwise. Verified that with this change applied, pycolmap imports cleanly on Windows (including under full page heap); see conda-forge/pycolmap-feedstock#100.

🤖 Generated with Claude Code

https://claude.ai/code/session_016pNQyKU5AZiqQWpsjhHPVk

MSVC numbers lambdas in default member initializers with a counter per
translation unit, while their mangled names are only scoped to the
enclosing class. Translation units that include these headers in a
different order thus define identically named lambdas with different
bodies, which the linker merges (an ODR violation).

In pycolmap this made AlikedMatchingOptions::<lambda_2_> resolve to the
brute-force initializer, which then wrote a BruteForceONNXMatchingOptions
into the smaller LightGlueONNXMatchingOptions member, corrupting the heap
during `import pycolmap` on Windows.

Use named inline functions instead, which have the same name everywhere.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016pNQyKU5AZiqQWpsjhHPVk
Tobias-Fischer added a commit to Tobias-Fischer/pycolmap-feedstock that referenced this pull request Oct 26, 2026
Backport of colmap/colmap#4900: lambdas used as
default member initializers in colmap's feature headers got identical
names with different bodies across translation units on MSVC, and the
linker merged them, corrupting the heap during `import pycolmap`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016pNQyKU5AZiqQWpsjhHPVk

@sarlinpe sarlinpe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

conda-forge-admin pushed a commit to conda-forge/colmap-feedstock that referenced this pull request Oct 26, 2026
Backport of colmap/colmap#4900. On MSVC,
identically named lambdas from different translation units were merged
by the linker, corrupting the heap in pycolmap on Windows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016pNQyKU5AZiqQWpsjhHPVk
@ahojnnes
ahojnnes merged commit 5ff7e73 into colmap:main Oct 27, 2026
16 checks passed
fringehush-gif added a commit to fringehush-gif/colmap that referenced this pull request Nov 3, 2026
## Summary

Merge upstream 9371f7b and PR4895
maintainer revision db7586c into
d297c1e, retaining independent stream,
blocking-sync, LoMa resize/transfer and ONNX stream changes.

Retain upstream option initialization, CUDA diagnostics and RootSIFT zero-row
safety. Use the maintainer's generic fail-closed BF16 helper and thin LoMa
wrapper. Register CUDA tests once, keep their CUDA dependency explicit, and
fix the sparse-matrix test's mixed CMake link signature.

## Validation

Incremental over d297c1e; retained the imported merge parents.

22 affected CPU objects compiled and CLI linked incrementally;
63 focused CPU tests and 7 RTX3080Ti CUDA tests pass, zero skips/failures.
Actual separate CUDA-enabled CMake configure/generation passes. The initial
ONNX test-link and Poisson CMake failures were corrected; only outstanding
test links were completed, with no repeated CLI or object build.

The one-line Poisson test CMake fix was configured after native tests and
changes no compiled production code. Public formatting changes whitespace
and include ordering only. CUDA objects are reused for declaration/comment
header deltas. Nine inherited archive identities match qualified controls;
the remaining inputs inherit the frozen native-build link closure.

No performance, memory, whole-scene quality, HIP, Python-binding or
unsupported-device end-to-end LoMa claim. PR4895 remains unmerged upstream.

AI disclosure: Totally vibe coded.

## Upstream commits

- `5ff7e73c4efa1fcad0a7766f0242ed8cec700831` Avoid lambdas as default member initializers in feature options (MSVC ODR violation) (colmap#4900)
- `3dd12895f96ae88f43eb7cfee8b26c467c6954e1` Fix CLI option names in the feature and FAQ docs (colmap#4901)
- `15526bb9a7bca6d1843b8b849169d7f6ce4f900b` Improve CUDA driver failure diagnostics (colmap#4903)
- `9371f7b47ebe660dfa8a8d968ff8def199ef0456` Preserve zero descriptors in RootSIFT normalization (colmap#4891)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants