[PATCH] Analysis: Add support for MS specific printf format specifiers

Aaron Ballman aaron at aaronballman.com
Wed Aug 21 05:42:14 PDT 2013


> Index: include/clang/Analysis/Analyses/FormatString.h
> ===================================================================
> --- include/clang/Analysis/Analyses/FormatString.h
> +++ include/clang/Analysis/Analyses/FormatString.h
> @@ -73,6 +73,9 @@
>      AsIntMax,     // 'j'
>      AsSizeT,      // 'z'
>      AsPtrDiff,    // 't'
> +    AsInt32,      // 'I32' (MSVCRT, like __int32)
> +    AsInt3264,    // 'I'   (MSVCRT, like size_t/ptrdiff_t)
> +    AsInt64,      // 'I64' (MSVCRT, like __int64)
>      AsLongDouble, // 'L'
>      AsAllocate,   // for '%as', GNU extension to C90 scanf
>      AsMAllocate,  // for '%ms', GNU extension to scanf
> Index: lib/Analysis/FormatString.cpp
> ===================================================================
> --- lib/Analysis/FormatString.cpp
> +++ lib/Analysis/FormatString.cpp
> @@ -223,6 +223,27 @@
>          break;
>        }
>        return false;
> +    // printf: AsInt64, AsInt32, AsInt3264
> +    // scanf:  AsInt64
> +    case 'I':
> +      if (I + 1 != E && I + 2 != E) {
> +        if (I[1] == '6' && I[2] == '4') {
> +          I += 3;
> +          lmKind = LengthModifier::AsInt64;
> +          break;
> +        }
> +        if (IsScanf)
> +          return false;
> +
> +        if (I[1] == '3' && I[2] == '2') {
> +          I += 3;
> +          lmKind = LengthModifier::AsInt64;

Shouldn't this be AsInt32?

> +          break;
> +        }
> +      }
> +      ++I;
> +      lmKind = LengthModifier::AsInt3264;
> +      break;
>    }
>    LengthModifier lm(lmPosition, lmKind);
>    FS.setLengthModifier(lm);
> @@ -471,6 +492,12 @@
>      return "z";
>    case AsPtrDiff:
>      return "t";
> +  case AsInt32:
> +    return "I32";
> +  case AsInt3264:
> +    return "I";
> +  case AsInt64:
> +    return "I64";
>    case AsLongDouble:
>      return "L";
>    case AsAllocate:
> @@ -514,7 +541,7 @@
>    case ScanListArg: return "[";
>    case InvalidSpecifier: return NULL;
>
> -  // MacOS X unicode extensions.
> +  // POSIX unicode extensions.
>    case CArg: return "C";
>    case SArg: return "S";
>
> @@ -678,6 +705,20 @@
>          default:
>            return false;
>        }
> +    case LengthModifier::AsInt32:
> +    case LengthModifier::AsInt3264:
> +    case LengthModifier::AsInt64:
> +      switch (CS.getKind()) {
> +        case ConversionSpecifier::dArg:
> +        case ConversionSpecifier::iArg:
> +        case ConversionSpecifier::oArg:
> +        case ConversionSpecifier::uArg:
> +        case ConversionSpecifier::xArg:
> +        case ConversionSpecifier::XArg:
> +          return Target.getTriple().isOSMSVCRT();
> +        default:
> +          return false;
> +      }
>    }
>    llvm_unreachable("Invalid LengthModifier Kind!");
>  }
> @@ -697,6 +738,9 @@
>      case LengthModifier::AsAllocate:
>      case LengthModifier::AsMAllocate:
>      case LengthModifier::AsQuad:
> +    case LengthModifier::AsInt32:
> +    case LengthModifier::AsInt3264:
> +    case LengthModifier::AsInt64:
>        return false;
>    }
>    llvm_unreachable("Invalid LengthModifier Kind!");
> Index: lib/Analysis/PrintfFormatString.cpp
> ===================================================================
> --- lib/Analysis/PrintfFormatString.cpp
> +++ lib/Analysis/PrintfFormatString.cpp
> @@ -187,8 +187,8 @@
>      case 'i': k = ConversionSpecifier::iArg; break;
>      case 'n': k = ConversionSpecifier::nArg; break;
>      case 'o': k = ConversionSpecifier::oArg; break;
> -    case 'p': k = ConversionSpecifier::pArg;   break;
> -    case 's': k = ConversionSpecifier::sArg;      break;
> +    case 'p': k = ConversionSpecifier::pArg; break;
> +    case 's': k = ConversionSpecifier::sArg; break;
>      case 'u': k = ConversionSpecifier::uArg; break;
>      case 'x': k = ConversionSpecifier::xArg; break;
>      // POSIX specific.
> @@ -278,18 +278,24 @@
>        case LengthModifier::AsLongDouble:
>          // GNU extension.
>          return Ctx.LongLongTy;
> -      case LengthModifier::None: return Ctx.IntTy;
> +      case LengthModifier::None:
> +      case LengthModifier::AsInt32:
> +        return Ctx.IntTy;
>        case LengthModifier::AsChar: return ArgType::AnyCharTy;
>        case LengthModifier::AsShort: return Ctx.ShortTy;
>        case LengthModifier::AsLong: return Ctx.LongTy;
>        case LengthModifier::AsLongLong:
>        case LengthModifier::AsQuad:
> +      case LengthModifier::AsInt64:
>          return Ctx.LongLongTy;
>        case LengthModifier::AsIntMax:
>          return ArgType(Ctx.getIntMaxType(), "intmax_t");
>        case LengthModifier::AsSizeT:
>          // FIXME: How to get the corresponding signed version of size_t?
>          return ArgType();
> +      case LengthModifier::AsInt3264:
> +        return Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.LongLongTy
> +                                                             : Ctx.IntTy;
>        case LengthModifier::AsPtrDiff:
>          return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
>        case LengthModifier::AsAllocate:
> @@ -302,17 +308,24 @@
>        case LengthModifier::AsLongDouble:
>          // GNU extension.
>          return Ctx.UnsignedLongLongTy;
> -      case LengthModifier::None: return Ctx.UnsignedIntTy;
> +      case LengthModifier::None:
> +      case LengthModifier::AsInt32:
> +        return Ctx.UnsignedIntTy;
>        case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
>        case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
>        case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
>        case LengthModifier::AsLongLong:
>        case LengthModifier::AsQuad:
> +      case LengthModifier::AsInt64:
>          return Ctx.UnsignedLongLongTy;
>        case LengthModifier::AsIntMax:
>          return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
>        case LengthModifier::AsSizeT:
>          return ArgType(Ctx.getSizeType(), "size_t");
> +      case LengthModifier::AsInt3264:
> +        return Ctx.getTargetInfo().getTriple().isArch64Bit()
> +                   ? Ctx.UnsignedLongLongTy
> +                   : Ctx.UnsignedIntTy;
>        case LengthModifier::AsPtrDiff:
>          // FIXME: How to get the corresponding unsigned
>          // version of ptrdiff_t?
> @@ -351,6 +364,9 @@
>          return ArgType(); // FIXME: Is this a known extension?
>        case LengthModifier::AsAllocate:
>        case LengthModifier::AsMAllocate:
> +      case LengthModifier::AsInt32:
> +      case LengthModifier::AsInt3264:
> +      case LengthModifier::AsInt64:
>          return ArgType::Invalid();
>      }
>    }
> Index: lib/Analysis/ScanfFormatString.cpp
> ===================================================================
> --- lib/Analysis/ScanfFormatString.cpp
> +++ lib/Analysis/ScanfFormatString.cpp
> @@ -231,6 +231,7 @@
>            return ArgType::PtrTo(Ctx.LongTy);
>          case LengthModifier::AsLongLong:
>          case LengthModifier::AsQuad:
> +        case LengthModifier::AsInt64:
>            return ArgType::PtrTo(Ctx.LongLongTy);
>          case LengthModifier::AsIntMax:
>            return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> @@ -243,8 +244,9 @@
>            // GNU extension.
>            return ArgType::PtrTo(Ctx.LongLongTy);
>          case LengthModifier::AsAllocate:
> -          return ArgType::Invalid();
>          case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
>            return ArgType::Invalid();
>        }
>
> @@ -266,6 +268,7 @@
>            return ArgType::PtrTo(Ctx.UnsignedLongTy);
>          case LengthModifier::AsLongLong:
>          case LengthModifier::AsQuad:
> +        case LengthModifier::AsInt64:
>            return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
>          case LengthModifier::AsIntMax:
>            return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
> @@ -278,8 +281,9 @@
>            // GNU extension.
>            return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
>          case LengthModifier::AsAllocate:
> -          return ArgType::Invalid();
>          case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
>            return ArgType::Invalid();
>        }
>
> @@ -359,6 +363,9 @@
>            return ArgType(); // FIXME: Is this a known extension?
>          case LengthModifier::AsAllocate:
>          case LengthModifier::AsMAllocate:
> +        case LengthModifier::AsInt32:
> +        case LengthModifier::AsInt3264:
> +        case LengthModifier::AsInt64:
>            return ArgType::Invalid();
>          }
>
> Index: test/Sema/format-strings-ms.c
> ===================================================================
> --- /dev/null
> +++ test/Sema/format-strings-ms.c
> @@ -0,0 +1,9 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -pedantic %s
> +
> +int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
> +
> +void test() {
> +  short val = 30;
> +  printf("val = %I64d\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \
> +                                // expected-warning{{format specifies type 'long long' but the argument has type 'short'}}
> +}
>

Should also have tests for I32 and I.

Otherwise, patch LGTM!

~Aaron

On Wed, Aug 21, 2013 at 5:01 AM, David Majnemer
<david.majnemer at gmail.com> wrote:
> Hi hans, jordan_rose, rnk,
>
> Adds support for %I, %I32 and %I64.
>
> http://llvm-reviews.chandlerc.com/D1456
>
> Files:
>   include/clang/Analysis/Analyses/FormatString.h
>   lib/Analysis/FormatString.cpp
>   lib/Analysis/PrintfFormatString.cpp
>   lib/Analysis/ScanfFormatString.cpp
>   test/Sema/format-strings-ms.c
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>



More information about the cfe-commits mailing list