diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -140,6 +140,25 @@ *p; // Now diagnosed as a warning-as-error. } +- Clang now diagnoses use of a bit-field as an instruction operand in Microsoft + style inline asm blocks as an error. Previously, a bit-field operand yielded + the address of the allocation unit the bit-field was stored within; reads or + writes therefore had the potential to read or write nearby bit-fields. This + change fixes `issue 57791 `_. + + .. code-block:: c++ + + typedef struct S { + unsigned bf:1; + } S; + void f(S s) { + __asm { + mov eax, s.bf // Now diagnosed as an error. + mov s.bf, eax // Now diagnosed as an error. + } + } + + What's New in Clang |release|? ============================== Some of the major new features and improvements to Clang are listed diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -279,6 +279,9 @@ def err_asm_invalid_type : Error< "invalid type %0 in asm %select{input|output}1">; + def err_ms_asm_bitfield_unsupported : Error< + "an inline asm block cannot have an operand which is a bit-field">; + def warn_stack_clash_protection_inline_asm : Warning< "Unable to protect inline asm that clobbers stack pointer against stack clash">, InGroup>; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -932,13 +932,24 @@ bool IsSimple = (NumOutputs != 0 || NumInputs != 0); setFunctionHasBranchProtectedScope(); + bool InvalidOperand = false; for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) { - if (Exprs[I]->getType()->isBitIntType()) - return StmtError( - Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type) - << Exprs[I]->getType() << (I < NumOutputs) - << Exprs[I]->getSourceRange()); + Expr *E = Exprs[I]; + if (E->getType()->isBitIntType()) { + InvalidOperand = true; + Diag(E->getBeginLoc(), diag::err_asm_invalid_type) + << E->getType() << (I < NumOutputs) + << E->getSourceRange(); + } else if (E->refersToBitField()) { + InvalidOperand = true; + FieldDecl *BitField = E->getSourceBitField(); + Diag(E->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported) + << E->getSourceRange(); + Diag(BitField->getLocation(), diag::note_bitfield_decl); + } } + if (InvalidOperand) + return StmtError(); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, diff --git a/clang/test/Parser/ms-inline-asm.c b/clang/test/Parser/ms-inline-asm.c --- a/clang/test/Parser/ms-inline-asm.c +++ b/clang/test/Parser/ms-inline-asm.c @@ -62,6 +62,18 @@ __asm mov eax, offset A // expected-error {{offset operator cannot yet handle constants}} } +// GH57791 +typedef struct S { + unsigned bf1:1; // expected-note {{bit-field is declared here}} + unsigned bf2:1; // expected-note {{bit-field is declared here}} +} S; +void t15(S s) { + __asm { + mov eax, s.bf1 // expected-error {{an inline asm block cannot have an operand which is a bit-field}} + mov s.bf2, eax // expected-error {{an inline asm block cannot have an operand which is a bit-field}} + } +} + int t_fail(void) { // expected-note {{to match this}} __asm __asm { // expected-error 3 {{expected}} expected-note {{to match this}}