head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.3
	netbsd-11-0-RC3:1.1.1.3
	netbsd-11-0-RC2:1.1.1.3
	netbsd-11-0-RC1:1.1.1.3
	perseant-exfatfs-base-20250801:1.1.1.3
	netbsd-11:1.1.1.3.0.10
	netbsd-11-base:1.1.1.3
	netbsd-10-1-RELEASE:1.1.1.3
	perseant-exfatfs-base-20240630:1.1.1.3
	perseant-exfatfs:1.1.1.3.0.8
	perseant-exfatfs-base:1.1.1.3
	netbsd-8-3-RELEASE:1.1.1.1
	netbsd-9-4-RELEASE:1.1.1.2
	netbsd-10-0-RELEASE:1.1.1.3
	netbsd-10-0-RC6:1.1.1.3
	netbsd-10-0-RC5:1.1.1.3
	netbsd-10-0-RC4:1.1.1.3
	netbsd-10-0-RC3:1.1.1.3
	netbsd-10-0-RC2:1.1.1.3
	netbsd-10-0-RC1:1.1.1.3
	netbsd-10:1.1.1.3.0.6
	netbsd-10-base:1.1.1.3
	netbsd-9-3-RELEASE:1.1.1.2
	cjep_sun2x:1.1.1.3.0.4
	cjep_sun2x-base:1.1.1.3
	cjep_staticlib_x-base1:1.1.1.3
	netbsd-9-2-RELEASE:1.1.1.2
	cjep_staticlib_x:1.1.1.3.0.2
	cjep_staticlib_x-base:1.1.1.3
	netbsd-9-1-RELEASE:1.1.1.2
	phil-wifi-20200421:1.1.1.3
	phil-wifi-20200411:1.1.1.3
	phil-wifi-20200406:1.1.1.3
	netbsd-8-2-RELEASE:1.1.1.1
	netbsd-9-0-RELEASE:1.1.1.2
	netbsd-9-0-RC2:1.1.1.2
	netbsd-9-0-RC1:1.1.1.2
	netbsd-9:1.1.1.2.0.6
	netbsd-9-base:1.1.1.2
	phil-wifi-20190609:1.1.1.2
	netbsd-8-1-RELEASE:1.1.1.1
	netbsd-8-1-RC1:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.2
	pgoyette-compat-20190127:1.1.1.2
	pgoyette-compat-20190118:1.1.1.2
	pgoyette-compat-1226:1.1.1.2
	pgoyette-compat-1126:1.1.1.2
	pgoyette-compat-1020:1.1.1.2
	pgoyette-compat-0930:1.1.1.2
	pgoyette-compat-0906:1.1.1.2
	pgoyette-compat-0728:1.1.1.2
	clang-337282:1.1.1.2
	netbsd-8-0-RELEASE:1.1.1.1
	phil-wifi:1.1.1.2.0.4
	phil-wifi-base:1.1.1.2
	pgoyette-compat-0625:1.1.1.2
	netbsd-8-0-RC2:1.1.1.1
	pgoyette-compat-0521:1.1.1.2
	pgoyette-compat-0502:1.1.1.2
	pgoyette-compat-0422:1.1.1.2
	netbsd-8-0-RC1:1.1.1.1
	pgoyette-compat-0415:1.1.1.2
	pgoyette-compat-0407:1.1.1.2
	pgoyette-compat-0330:1.1.1.2
	pgoyette-compat-0322:1.1.1.2
	pgoyette-compat-0315:1.1.1.2
	pgoyette-compat:1.1.1.2.0.2
	pgoyette-compat-base:1.1.1.2
	clang-319952:1.1.1.2
	matt-nb8-mediatek:1.1.1.1.0.12
	matt-nb8-mediatek-base:1.1.1.1
	clang-309604:1.1.1.2
	perseant-stdc-iso10646:1.1.1.1.0.10
	perseant-stdc-iso10646-base:1.1.1.1
	netbsd-8:1.1.1.1.0.8
	netbsd-8-base:1.1.1.1
	prg-localcount2-base3:1.1.1.1
	prg-localcount2-base2:1.1.1.1
	prg-localcount2-base1:1.1.1.1
	prg-localcount2:1.1.1.1.0.6
	prg-localcount2-base:1.1.1.1
	pgoyette-localcount-20170426:1.1.1.1
	bouyer-socketcan-base1:1.1.1.1
	pgoyette-localcount:1.1.1.1.0.4
	pgoyette-localcount-20170320:1.1.1.1
	clang-294123:1.1.1.1
	bouyer-socketcan:1.1.1.1.0.2
	bouyer-socketcan-base:1.1.1.1
	clang-291444:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2017.01.11.10.34.45;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	CNnUNfII1jgNmxBz;

1.1.1.1
date	2017.01.11.10.34.45;	author joerg;	state Exp;
branches
	1.1.1.1.4.1;
next	1.1.1.2;
commitid	CNnUNfII1jgNmxBz;

1.1.1.2
date	2017.08.01.19.35.37;	author joerg;	state Exp;
branches
	1.1.1.2.4.1;
next	1.1.1.3;
commitid	pMuDy65V0VicSx1A;

1.1.1.3
date	2019.11.13.22.19.20;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.1.4.1
date	2017.01.11.10.34.45;	author pgoyette;	state dead;
branches;
next	1.1.1.1.4.2;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.1.4.2
date	2017.03.20.06.52.36;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.2.4.1
date	2020.04.13.07.46.31;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@// TODO: header template

#include "clang/Analysis/Analyses/OSLog.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallBitVector.h"

using namespace clang;
using llvm::APInt;

using clang::analyze_os_log::OSLogBufferItem;
using clang::analyze_os_log::OSLogBufferLayout;

class OSLogFormatStringHandler
    : public analyze_format_string::FormatStringHandler {
private:
  struct ArgData {
    const Expr *E = nullptr;
    Optional<OSLogBufferItem::Kind> Kind;
    Optional<unsigned> Size;
    Optional<const Expr *> Count;
    Optional<const Expr *> Precision;
    Optional<const Expr *> FieldWidth;
    unsigned char Flags = 0;
  };
  SmallVector<ArgData, 4> ArgsData;
  ArrayRef<const Expr *> Args;

  OSLogBufferItem::Kind
  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
    switch (K) {
    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
      return OSLogBufferItem::StringKind;
    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
      return OSLogBufferItem::WideStringKind;
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
      return OSLogBufferItem::PointerKind;
    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@@"
      return OSLogBufferItem::ObjCObjKind;
    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
      return OSLogBufferItem::ErrnoKind;
    default:
      return OSLogBufferItem::ScalarKind;
    }
    }
  }

public:
  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
    ArgsData.reserve(Args.size());
  }

  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
                                     const char *StartSpecifier,
                                     unsigned SpecifierLen) {
    if (!FS.consumesDataArgument() &&
        FS.getConversionSpecifier().getKind() !=
            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
      return true;

    ArgsData.emplace_back();
    unsigned ArgIndex = FS.getArgIndex();
    if (ArgIndex < Args.size())
      ArgsData.back().E = Args[ArgIndex];

    // First get the Kind
    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
        !ArgsData.back().E) {
      // missing argument
      ArgsData.pop_back();
      return false;
    }

    switch (FS.getConversionSpecifier().getKind()) {
    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
      auto &precision = FS.getPrecision();
      switch (precision.getHowSpecified()) {
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
        break;
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
        ArgsData.back().Size = precision.getConstantAmount();
        break;
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
        ArgsData.back().Count = Args[precision.getArgIndex()];
        break;
      case clang::analyze_format_string::OptionalAmount::Invalid:
        return false;
      }
      break;
    }
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
      auto &precision = FS.getPrecision();
      switch (precision.getHowSpecified()) {
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
        return false; // length must be supplied with pointer format specifier
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
        ArgsData.back().Size = precision.getConstantAmount();
        break;
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
        ArgsData.back().Count = Args[precision.getArgIndex()];
        break;
      case clang::analyze_format_string::OptionalAmount::Invalid:
        return false;
      }
      break;
    }
    default:
      if (FS.getPrecision().hasDataArgument()) {
        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
      }
      break;
    }
    if (FS.getFieldWidth().hasDataArgument()) {
      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
    }

    if (FS.isPrivate()) {
      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
    }
    if (FS.isPublic()) {
      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
    }
    return true;
  }

  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
    Layout.Items.clear();
    for (auto &Data : ArgsData) {
      if (Data.FieldWidth) {
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
                                  Size, 0);
      }
      if (Data.Precision) {
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
                                  Size, 0);
      }
      if (Data.Count) {
        // "%.*P" has an extra "count" that we insert before the argument.
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
                                  0);
      }
      if (Data.Size)
        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
                                  Data.Flags);
      if (Data.Kind) {
        CharUnits Size;
        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
          Size = CharUnits::Zero();
        else
          Size = Ctx.getTypeSizeInChars(Data.E->getType());
        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
      } else {
        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
                                  Data.Flags);
      }
    }
  }
};

bool clang::analyze_os_log::computeOSLogBufferLayout(
    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());

  const Expr *StringArg;
  ArrayRef<const Expr *> VarArgs;
  switch (E->getBuiltinCallee()) {
  case Builtin::BI__builtin_os_log_format_buffer_size:
    assert(E->getNumArgs() >= 1 &&
           "__builtin_os_log_format_buffer_size takes at least 1 argument");
    StringArg = E->getArg(0);
    VarArgs = Args.slice(1);
    break;
  case Builtin::BI__builtin_os_log_format:
    assert(E->getNumArgs() >= 2 &&
           "__builtin_os_log_format takes at least 2 arguments");
    StringArg = E->getArg(1);
    VarArgs = Args.slice(2);
    break;
  default:
    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
  }

  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
  StringRef Data = Lit->getString();
  OSLogFormatStringHandler H(VarArgs);
  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);

  H.computeLayout(Ctx, Layout);
  return true;
}
@


1.1.1.1
log
@Import Clang pre-4.0.0 r291444.
@
text
@@


1.1.1.2
log
@Import clang r309604 from branches/release_50
@
text
@d13 1
a17 1
namespace {
a168 1
} // end anonymous namespace
@


1.1.1.2.4.1
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.3
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.1.4.1
log
@file OSLog.cpp was added on branch pgoyette-localcount on 2017-03-20 06:52:36 +0000
@
text
@d1 202
@


1.1.1.1.4.2
log
@Sync with HEAD
@
text
@a0 202
// TODO: header template

#include "clang/Analysis/Analyses/OSLog.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallBitVector.h"

using namespace clang;
using llvm::APInt;

using clang::analyze_os_log::OSLogBufferItem;
using clang::analyze_os_log::OSLogBufferLayout;

class OSLogFormatStringHandler
    : public analyze_format_string::FormatStringHandler {
private:
  struct ArgData {
    const Expr *E = nullptr;
    Optional<OSLogBufferItem::Kind> Kind;
    Optional<unsigned> Size;
    Optional<const Expr *> Count;
    Optional<const Expr *> Precision;
    Optional<const Expr *> FieldWidth;
    unsigned char Flags = 0;
  };
  SmallVector<ArgData, 4> ArgsData;
  ArrayRef<const Expr *> Args;

  OSLogBufferItem::Kind
  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
    switch (K) {
    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
      return OSLogBufferItem::StringKind;
    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
      return OSLogBufferItem::WideStringKind;
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
      return OSLogBufferItem::PointerKind;
    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@@"
      return OSLogBufferItem::ObjCObjKind;
    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
      return OSLogBufferItem::ErrnoKind;
    default:
      return OSLogBufferItem::ScalarKind;
    }
    }
  }

public:
  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
    ArgsData.reserve(Args.size());
  }

  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
                                     const char *StartSpecifier,
                                     unsigned SpecifierLen) {
    if (!FS.consumesDataArgument() &&
        FS.getConversionSpecifier().getKind() !=
            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
      return true;

    ArgsData.emplace_back();
    unsigned ArgIndex = FS.getArgIndex();
    if (ArgIndex < Args.size())
      ArgsData.back().E = Args[ArgIndex];

    // First get the Kind
    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
        !ArgsData.back().E) {
      // missing argument
      ArgsData.pop_back();
      return false;
    }

    switch (FS.getConversionSpecifier().getKind()) {
    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
      auto &precision = FS.getPrecision();
      switch (precision.getHowSpecified()) {
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
        break;
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
        ArgsData.back().Size = precision.getConstantAmount();
        break;
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
        ArgsData.back().Count = Args[precision.getArgIndex()];
        break;
      case clang::analyze_format_string::OptionalAmount::Invalid:
        return false;
      }
      break;
    }
    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
      auto &precision = FS.getPrecision();
      switch (precision.getHowSpecified()) {
      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
        return false; // length must be supplied with pointer format specifier
      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
        ArgsData.back().Size = precision.getConstantAmount();
        break;
      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
        ArgsData.back().Count = Args[precision.getArgIndex()];
        break;
      case clang::analyze_format_string::OptionalAmount::Invalid:
        return false;
      }
      break;
    }
    default:
      if (FS.getPrecision().hasDataArgument()) {
        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
      }
      break;
    }
    if (FS.getFieldWidth().hasDataArgument()) {
      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
    }

    if (FS.isPrivate()) {
      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
    }
    if (FS.isPublic()) {
      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
    }
    return true;
  }

  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
    Layout.Items.clear();
    for (auto &Data : ArgsData) {
      if (Data.FieldWidth) {
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
                                  Size, 0);
      }
      if (Data.Precision) {
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
                                  Size, 0);
      }
      if (Data.Count) {
        // "%.*P" has an extra "count" that we insert before the argument.
        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
        Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
                                  0);
      }
      if (Data.Size)
        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
                                  Data.Flags);
      if (Data.Kind) {
        CharUnits Size;
        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
          Size = CharUnits::Zero();
        else
          Size = Ctx.getTypeSizeInChars(Data.E->getType());
        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
      } else {
        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
                                  Data.Flags);
      }
    }
  }
};

bool clang::analyze_os_log::computeOSLogBufferLayout(
    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());

  const Expr *StringArg;
  ArrayRef<const Expr *> VarArgs;
  switch (E->getBuiltinCallee()) {
  case Builtin::BI__builtin_os_log_format_buffer_size:
    assert(E->getNumArgs() >= 1 &&
           "__builtin_os_log_format_buffer_size takes at least 1 argument");
    StringArg = E->getArg(0);
    VarArgs = Args.slice(1);
    break;
  case Builtin::BI__builtin_os_log_format:
    assert(E->getNumArgs() >= 2 &&
           "__builtin_os_log_format takes at least 2 arguments");
    StringArg = E->getArg(1);
    VarArgs = Args.slice(2);
    break;
  default:
    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
  }

  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
  StringRef Data = Lit->getString();
  OSLogFormatStringHandler H(VarArgs);
  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);

  H.computeLayout(Ctx, Layout);
  return true;
}
@


