r279374 - [Sema] Don't crash on scanf on forward-declared enums.

Vitaly Buka via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 20 10:27:30 PDT 2016


msan is not happy about this change
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/15681/steps/check-llvm%20msan/logs/stdio

On Sat, Aug 20, 2016 at 9:59 AM Benjamin Kramer via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: d0k
> Date: Sat Aug 20 11:51:33 2016
> New Revision: 279374
>
> URL: http://llvm.org/viewvc/llvm-project?rev=279374&view=rev
> Log:
> [Sema] Don't crash on scanf on forward-declared enums.
>
> This is valid in GNU C, which allows pointers to incomplete enums. GCC
> just pretends that the underlying type is 'int' in those cases, follow
> that behavior.
>
> Modified:
>     cfe/trunk/lib/Analysis/FormatString.cpp
>     cfe/trunk/lib/Analysis/ScanfFormatString.cpp
>     cfe/trunk/test/Sema/format-strings-enum.c
>
> Modified: cfe/trunk/lib/Analysis/FormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=279374&r1=279373&r2=279374&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/FormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/FormatString.cpp Sat Aug 20 11:51:33 2016
> @@ -310,8 +310,13 @@ ArgType::matchesType(ASTContext &C, Qual
>        return Match;
>
>      case AnyCharTy: {
> -      if (const EnumType *ETy = argTy->getAs<EnumType>())
> +      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> +        // If the enum is incomplete we know nothing about the underlying
> type.
> +        // Assume that it's 'int'.
> +        if (!ETy->getDecl()->isComplete())
> +          return NoMatch;
>          argTy = ETy->getDecl()->getIntegerType();
> +      }
>
>        if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
>          switch (BT->getKind()) {
> @@ -327,8 +332,14 @@ ArgType::matchesType(ASTContext &C, Qual
>      }
>
>      case SpecificTy: {
> -      if (const EnumType *ETy = argTy->getAs<EnumType>())
> -        argTy = ETy->getDecl()->getIntegerType();
> +      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> +        // If the enum is incomplete we know nothing about the underlying
> type.
> +        // Assume that it's 'int'.
> +        if (!ETy->getDecl()->isComplete())
> +          argTy = C.IntTy;
> +        else
> +          argTy = ETy->getDecl()->getIntegerType();
> +      }
>        argTy = C.getCanonicalType(argTy).getUnqualifiedType();
>
>        if (T == argTy)
>
> Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=279374&r1=279373&r2=279374&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Sat Aug 20 11:51:33 2016
> @@ -418,8 +418,12 @@ bool ScanfSpecifier::fixType(QualType QT
>    QualType PT = QT->getPointeeType();
>
>    // If it's an enum, get its underlying type.
> -  if (const EnumType *ETy = PT->getAs<EnumType>())
> +  if (const EnumType *ETy = PT->getAs<EnumType>()) {
> +    // Don't try to fix incomplete enums.
> +    if (!ETy->getDecl()->isComplete())
> +      return false;
>      PT = ETy->getDecl()->getIntegerType();
> +  }
>
>    const BuiltinType *BT = PT->getAs<BuiltinType>();
>    if (!BT)
>
> Modified: cfe/trunk/test/Sema/format-strings-enum.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-enum.c?rev=279374&r1=279373&r2=279374&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Sema/format-strings-enum.c (original)
> +++ cfe/trunk/test/Sema/format-strings-enum.c Sat Aug 20 11:51:33 2016
> @@ -11,6 +11,7 @@
>  #endif
>
>  EXTERN_C int printf(const char *,...);
> +EXTERN_C int scanf(const char *, ...);
>
>  typedef enum { Constant = 0 } TestEnum;
>  // Note that in C, the type of 'Constant' is 'int'. In C++ it is
> 'TestEnum'.
> @@ -34,3 +35,18 @@ void testLong(LongEnum input) {
>    printf("%lu", input);
>    printf("%lu", LongConstant);
>  }
> +
> +#ifndef __cplusplus
> +// GNU C allows forward declaring enums.
> +extern enum forward_declared *fwd;
> +
> +void forward_enum() {
> +  printf("%u", fwd); // expected-warning{{format specifies type 'unsigned
> int' but the argument has type 'enum forward_declared *}}
> +  printf("%p", fwd);
> +
> +  scanf("%c", fwd); // expected-warning{{format specifies type 'char *'
> but the argument has type 'enum forward_declared *}}
> +  scanf("%u", fwd);
> +  scanf("%lu", fwd); // expected-warning{{format specifies type 'unsigned
> long *' but the argument has type 'enum forward_declared *}}
> +  scanf("%p", fwd); // expected-warning{{format specifies type 'void **'
> but the argument has type 'enum forward_declared *}}
> +}
> +#endif
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160820/6a32f6a6/attachment.html>


More information about the cfe-commits mailing list