From 290aa8560bbff08e2c5ab362db3bb64052a8667f Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 25 Nov 2007 00:25:21 +0000 Subject: [PATCH] Check that the clobber registers are valid. llvm-svn: 44311 --- clang/Basic/TargetInfo.cpp | 45 ++++++++++++++++++- clang/Sema/SemaStmt.cpp | 21 +++++++++ clang/include/clang/Basic/DiagnosticKinds.def | 4 +- clang/include/clang/Basic/TargetInfo.h | 2 +- clang/test/Sema/asm.c | 15 ++++++- 5 files changed, 82 insertions(+), 5 deletions(-) diff --git a/clang/Basic/TargetInfo.cpp b/clang/Basic/TargetInfo.cpp index 57b01b7530ab..3b20d3aa554c 100644 --- a/clang/Basic/TargetInfo.cpp +++ b/clang/Basic/TargetInfo.cpp @@ -14,8 +14,9 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/AST/Builtins.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/STLExtras.h" #include using namespace clang; @@ -270,6 +271,46 @@ const char *TargetInfo::getVAListDeclaration() const { /// is a valid register name according to GCC. This is used by Sema for /// inline asm statements. bool TargetInfo::isValidGCCRegisterName(const char *Name) const { - // FIXME: Implement this. + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + if (Name[0] == '%' || Name[0] == '#') + Name++; + + if (strcmp(Name, "memory") == 0 || + strcmp(Name, "cc") == 0) + return true; + + PrimaryTarget->getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (strcmp(Name, Names[i]) == 0) + return true; + } + + // Now check aliases. + const TargetInfoImpl::GCCRegAlias *Aliases; + unsigned NumAliases; + + PrimaryTarget->getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return true; + } + } + return false; } diff --git a/clang/Sema/SemaStmt.cpp b/clang/Sema/SemaStmt.cpp index d99356edc192..7f5d038e71e7 100644 --- a/clang/Sema/SemaStmt.cpp +++ b/clang/Sema/SemaStmt.cpp @@ -16,8 +16,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/Stmt.h" #include "clang/Parse/Scope.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallString.h" using namespace clang; Sema::StmtResult Sema::ActOnExprStmt(ExprTy *expr) { @@ -691,6 +693,25 @@ Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, } } + // Check that the clobbers are valid. + for (unsigned i = 0; i < NumClobbers; i++) { + StringLiteral *Literal = cast((Expr *)Clobbers[i]); + assert(!Literal->isWide() && "Clobber strings should not be wide!"); + + llvm::SmallString<16> Clobber(Literal->getStrData(), + Literal->getStrData() + + Literal->getByteLength()); + + if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) { + Diag(Literal->getLocStart(), + diag::err_unknown_register_name_in_asm, + Clobber.c_str()); + + // FIXME: We currently leak memory here. + return true; + } + } + return new AsmStmt(AsmLoc, IsVolatile, NumOutputs, diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 31fdd27b670f..ffdf62699389 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -793,7 +793,9 @@ DIAG(err_invalid_lvalue_in_asm_output, ERROR, "invalid lvalue in asm output") DIAG(err_invalid_type_in_asm_input, ERROR, "invalid type '%0' in asm input") - +DIAG(err_unknown_register_name_in_asm, ERROR, + "unknown register name '%0' in asm") + // CHECK: printf format string errors DIAG(warn_printf_not_string_constant, WARNING, "format string is not a string literal (potentially insecure)") diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index c4c2631e4c0d..3a186a28beeb 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -278,7 +278,7 @@ public: } virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const = 0; + unsigned &NumNames) const = 0; struct GCCRegAlias { const char * const Aliases[5]; diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c index e01a0f2dc0de..360af015ce81 100644 --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -1,4 +1,4 @@ -// RUN: clang %s -verify -fsyntax-only +// RUN: clang %s -arch=i386 -verify -fsyntax-only void f() @@ -12,3 +12,16 @@ f() asm ("foo\n" : "=a" (i + 2)); // expected-error {{invalid lvalue in asm output}} } + +void +clobbers() +{ + asm ("nop" : : : "ax", "#ax", "%ax"); + asm ("nop" : : : "eax", "rax", "ah", "al"); + asm ("nop" : : : "0", "%0", "#0"); + asm ("nop" : : : "foo"); // expected-error {{unknown register name 'foo' in asm}} + asm ("nop" : : : "52"); + asm ("nop" : : : "53"); // expected-error {{unknown register name '53' in asm}} + asm ("nop" : : : "-1"); // expected-error {{unknown register name '-1' in asm}} + asm ("nop" : : : "+1"); // expected-error {{unknown register name '+1' in asm}} +} -- GitLab