From 920a06ca7416a13e13789de363462abc5866d840 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:52:52 +0000 Subject: [PATCH 1/8] Fix UB: initialize SpirvCodeGenOptions members All bool, uint32_t, and enum members in SpirvCodeGenOptions were left uninitialized by the implicit default constructor. Reading these indeterminate values is undefined behavior. Add in-class member initializers for all scalar fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- include/dxc/Support/SPIRVOptions.h | 80 +++++++++++++++--------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/include/dxc/Support/SPIRVOptions.h b/include/dxc/Support/SPIRVOptions.h index 352cf6c2ec..ede9fc0fd6 100644 --- a/include/dxc/Support/SPIRVOptions.h +++ b/include/dxc/Support/SPIRVOptions.h @@ -39,40 +39,40 @@ enum class SpirvLayoutRule { struct SpirvCodeGenOptions { /// Disable legalization and optimization and emit raw SPIR-V - bool codeGenHighLevel; - bool debugInfoFile; - bool debugInfoLine; - bool debugInfoSource; - bool debugInfoTool; - bool debugInfoRich; + bool codeGenHighLevel = false; + bool debugInfoFile = false; + bool debugInfoLine = false; + bool debugInfoSource = false; + bool debugInfoTool = false; + bool debugInfoRich = false; /// Use NonSemantic.Vulkan.DebugInfo.100 debug info instead of /// OpenCL.DebugInfo.100 - bool debugInfoVulkan; - bool defaultRowMajor; - bool disableValidation; - bool enable16BitTypes; - bool finiteMathOnly; - bool enableReflect; - bool invertY; // Additive inverse - bool invertW; // Multiplicative inverse - bool noWarnEmulatedFeatures; - bool noWarnIgnoredFeatures; - bool preserveBindings; - bool preserveInterface; - bool useDxLayout; - bool useGlLayout; - bool useLegacyBufferMatrixOrder; - bool useScalarLayout; - bool flattenResourceArrays; - bool reduceLoadSize; - bool autoShiftBindings; - bool supportNonzeroBaseInstance; - bool supportNonzeroBaseVertex; - bool fixFuncCallArguments; - bool enableMaximalReconvergence; - bool useVulkanMemoryModel; - bool useUnknownImageFormat; - bool IEEEStrict; + bool debugInfoVulkan = false; + bool defaultRowMajor = false; + bool disableValidation = false; + bool enable16BitTypes = false; + bool finiteMathOnly = false; + bool enableReflect = false; + bool invertY = false; // Additive inverse + bool invertW = false; // Multiplicative inverse + bool noWarnEmulatedFeatures = false; + bool noWarnIgnoredFeatures = false; + bool preserveBindings = false; + bool preserveInterface = false; + bool useDxLayout = false; + bool useGlLayout = false; + bool useLegacyBufferMatrixOrder = false; + bool useScalarLayout = false; + bool flattenResourceArrays = false; + bool reduceLoadSize = false; + bool autoShiftBindings = false; + bool supportNonzeroBaseInstance = false; + bool supportNonzeroBaseVertex = false; + bool fixFuncCallArguments = false; + bool enableMaximalReconvergence = false; + bool useVulkanMemoryModel = false; + bool useUnknownImageFormat = false; + bool IEEEStrict = false; /// Maximum length in words for the OpString literal containing the shader /// source for DebugSource and DebugSourceContinued. If the source code length /// is larger than this number, we will use DebugSourceContinued instructions @@ -81,14 +81,14 @@ struct SpirvCodeGenOptions { /// limitation of a single SPIR-V instruction size (0xFFFF) - 2 operand words /// for OpString. Currently a smaller value is only used to test /// DebugSourceContinued generation. - uint32_t debugSourceLen; - SpirvLayoutRule cBufferLayoutRule; - SpirvLayoutRule sBufferLayoutRule; - SpirvLayoutRule tBufferLayoutRule; - SpirvLayoutRule ampPayloadLayoutRule; + uint32_t debugSourceLen = 0; + SpirvLayoutRule cBufferLayoutRule = SpirvLayoutRule::Void; + SpirvLayoutRule sBufferLayoutRule = SpirvLayoutRule::Void; + SpirvLayoutRule tBufferLayoutRule = SpirvLayoutRule::Void; + SpirvLayoutRule ampPayloadLayoutRule = SpirvLayoutRule::Void; llvm::StringRef stageIoOrder; llvm::StringRef targetEnv; - uint32_t maxId; + uint32_t maxId = 0; llvm::SmallVector bShift; llvm::SmallVector sShift; llvm::SmallVector tShift; @@ -109,9 +109,9 @@ struct SpirvCodeGenOptions { std::optional samplerHeapBinding; std::optional counterHeapBinding; - bool signaturePacking; ///< Whether signature packing is enabled or not + bool signaturePacking = false; ///< Whether signature packing is enabled or not - bool printAll; // Dump SPIR-V module before each pass and after the last one. + bool printAll = false; // Dump SPIR-V module before each pass and after the last one. // String representation of all command line options and input file. std::string clOptions; From c746af20bdd8b72049c811357aa5a857fc520dc3 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:52:57 +0000 Subject: [PATCH 2/8] Fix UB: initialize FrontendInputFile::IsSystem in default ctor The default constructor omitted IsSystem from its initializer list, leaving it indeterminate. Reading it is undefined behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tools/clang/include/clang/Frontend/FrontendOptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/include/clang/Frontend/FrontendOptions.h b/tools/clang/include/clang/Frontend/FrontendOptions.h index 3e31fa4b05..ae83c23124 100644 --- a/tools/clang/include/clang/Frontend/FrontendOptions.h +++ b/tools/clang/include/clang/Frontend/FrontendOptions.h @@ -92,7 +92,7 @@ class FrontendInputFile { bool IsSystem; public: - FrontendInputFile() : Buffer(nullptr), Kind(IK_None) { } + FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, From 67309830822b88b261557c63cdb00aa8273982b0 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:53:02 +0000 Subject: [PATCH 3/8] Fix UB: avoid left shift of negative value in APInt::slt Left-shifting a negative signed integer is UB before C++20. Cast to uint64_t for the left shift, then back to int64_t for the arithmetic right shift that performs sign extension. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/Support/APInt.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index d01238a552..8b80b7eff4 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -552,8 +552,8 @@ bool APInt::ult(const APInt& RHS) const { bool APInt::slt(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); if (isSingleWord()) { - int64_t lhsSext = (int64_t(VAL) << (64-BitWidth)) >> (64-BitWidth); - int64_t rhsSext = (int64_t(RHS.VAL) << (64-BitWidth)) >> (64-BitWidth); + int64_t lhsSext = int64_t(uint64_t(VAL) << (64-BitWidth)) >> (64-BitWidth); + int64_t rhsSext = int64_t(uint64_t(RHS.VAL) << (64-BitWidth)) >> (64-BitWidth); return lhsSext < rhsSext; } @@ -1062,7 +1062,7 @@ APInt APInt::ashr(unsigned shiftAmt) const { else { unsigned SignBit = APINT_BITS_PER_WORD - BitWidth; return APInt(BitWidth, - (((int64_t(VAL) << SignBit) >> SignBit) >> shiftAmt)); + (((int64_t(uint64_t(VAL) << SignBit) >> SignBit) >> shiftAmt))); } } From b60208839f13a17588c7d4e767afe2a67d24ebc1 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:53:07 +0000 Subject: [PATCH 4/8] Fix UB: initialize vfs::Status members in default ctor The default constructor only initialized Type, leaving Perms, IsVFSMapped, User, Group, and Size indeterminate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tools/clang/include/clang/Basic/VirtualFileSystem.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/clang/include/clang/Basic/VirtualFileSystem.h b/tools/clang/include/clang/Basic/VirtualFileSystem.h index 1c65fb5eac..6b486b83e5 100644 --- a/tools/clang/include/clang/Basic/VirtualFileSystem.h +++ b/tools/clang/include/clang/Basic/VirtualFileSystem.h @@ -40,10 +40,13 @@ class Status { llvm::sys::fs::perms Perms; public: - bool IsVFSMapped; // FIXME: remove when files support multiple names + bool IsVFSMapped = false; // FIXME: remove when files support multiple names public: - Status() : Type(llvm::sys::fs::file_type::status_error) {} + Status() + : User(0), Group(0), Size(0), + Type(llvm::sys::fs::file_type::status_error), + Perms(llvm::sys::fs::perms_not_known) {} Status(const llvm::sys::fs::file_status &Status); Status(StringRef Name, StringRef RealName, llvm::sys::fs::UniqueID UID, llvm::sys::TimeValue MTime, uint32_t User, uint32_t Group, From 146ecbdfd91b233f6e1901914c7e52e98b1a8d71 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:53:12 +0000 Subject: [PATCH 5/8] Fix UB: initialize LookupResult::Ambiguity member The copy constructor reads the Ambiguity field even when ResultKind is not Ambiguous, triggering a load of an indeterminate enum value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tools/clang/include/clang/Sema/Lookup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/include/clang/Sema/Lookup.h b/tools/clang/include/clang/Sema/Lookup.h index 5bfee8b0d0..1f880731eb 100644 --- a/tools/clang/include/clang/Sema/Lookup.h +++ b/tools/clang/include/clang/Sema/Lookup.h @@ -654,7 +654,7 @@ class LookupResult { // Results. LookupResultKind ResultKind; - AmbiguityKind Ambiguity; // ill-defined unless ambiguous + AmbiguityKind Ambiguity = {}; // ill-defined unless ambiguous UnresolvedSet<8> Decls; CXXBasePaths *Paths; CXXRecordDecl *NamingClass; From a3c493995d85727e6d99dc89536c1d5fbd9d37cf Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 03:53:16 +0000 Subject: [PATCH 6/8] Fix UB: initialize Triple::SubArch member SubArch was left uninitialized for architectures without a sub-architecture, causing loads of indeterminate enum values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- include/llvm/ADT/Triple.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 10a1e1a20b..cf2c096ce1 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -193,7 +193,7 @@ class Triple { ArchType Arch; /// The parsed subarchitecture type. - SubArchType SubArch; + SubArchType SubArch = NoSubArch; /// The parsed vendor type. VendorType Vendor; From 26389eb8e88b966d3d6be13851069ef9dd599ea2 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Fri, 20 Feb 2026 06:03:56 +0000 Subject: [PATCH 7/8] Fix UB: guard memcpy against null pointer in MemoryBuffer Passing a null pointer to memcpy is UB even when size is 0. Guard the call with a size check for empty StringRef inputs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/Support/MemoryBuffer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index bbdc85e6c3..e28144ff55 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -126,8 +126,9 @@ MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { getNewUninitMemBuffer(InputData.size(), BufferName); if (!Buf) return nullptr; - memcpy(const_cast(Buf->getBufferStart()), InputData.data(), - InputData.size()); + if (InputData.size()) + memcpy(const_cast(Buf->getBufferStart()), InputData.data(), + InputData.size()); return Buf; } From c6ad1fb1e1d60207d472414a06cb9f833c94e868 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Feb 2026 17:43:21 +0000 Subject: [PATCH 8/8] chore: autopublish 2026-02-20T17:43:20Z --- include/dxc/Support/SPIRVOptions.h | 6 ++++-- lib/Support/APInt.cpp | 10 ++++++---- lib/Support/MemoryBuffer.cpp | 2 +- tools/clang/include/clang/Frontend/FrontendOptions.h | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/dxc/Support/SPIRVOptions.h b/include/dxc/Support/SPIRVOptions.h index ede9fc0fd6..f39602e9d8 100644 --- a/include/dxc/Support/SPIRVOptions.h +++ b/include/dxc/Support/SPIRVOptions.h @@ -109,9 +109,11 @@ struct SpirvCodeGenOptions { std::optional samplerHeapBinding; std::optional counterHeapBinding; - bool signaturePacking = false; ///< Whether signature packing is enabled or not + bool signaturePacking = + false; ///< Whether signature packing is enabled or not - bool printAll = false; // Dump SPIR-V module before each pass and after the last one. + bool printAll = + false; // Dump SPIR-V module before each pass and after the last one. // String representation of all command line options and input file. std::string clOptions; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 8b80b7eff4..df41e00e3e 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -552,8 +552,10 @@ bool APInt::ult(const APInt& RHS) const { bool APInt::slt(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); if (isSingleWord()) { - int64_t lhsSext = int64_t(uint64_t(VAL) << (64-BitWidth)) >> (64-BitWidth); - int64_t rhsSext = int64_t(uint64_t(RHS.VAL) << (64-BitWidth)) >> (64-BitWidth); + int64_t lhsSext = + int64_t(uint64_t(VAL) << (64 - BitWidth)) >> (64 - BitWidth); + int64_t rhsSext = + int64_t(uint64_t(RHS.VAL) << (64 - BitWidth)) >> (64 - BitWidth); return lhsSext < rhsSext; } @@ -1061,8 +1063,8 @@ APInt APInt::ashr(unsigned shiftAmt) const { return APInt(BitWidth, 0); // undefined else { unsigned SignBit = APINT_BITS_PER_WORD - BitWidth; - return APInt(BitWidth, - (((int64_t(uint64_t(VAL) << SignBit) >> SignBit) >> shiftAmt))); + return APInt(BitWidth, (((int64_t(uint64_t(VAL) << SignBit) >> SignBit) >> + shiftAmt))); } } diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index e28144ff55..608bda7488 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -127,7 +127,7 @@ MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { if (!Buf) return nullptr; if (InputData.size()) - memcpy(const_cast(Buf->getBufferStart()), InputData.data(), + memcpy(const_cast(Buf->getBufferStart()), InputData.data(), InputData.size()); return Buf; } diff --git a/tools/clang/include/clang/Frontend/FrontendOptions.h b/tools/clang/include/clang/Frontend/FrontendOptions.h index ae83c23124..dabf1a4bb5 100644 --- a/tools/clang/include/clang/Frontend/FrontendOptions.h +++ b/tools/clang/include/clang/Frontend/FrontendOptions.h @@ -92,7 +92,7 @@ class FrontendInputFile { bool IsSystem; public: - FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } + FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) {} FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,