<commit_before>#pragma once

#include <iosfwd>
#include <initializer_list>

namespace RealRT
{
    class Vector3D
    {
        public:
            Vector3D(void) = default;

            Vector3D(float i, float j, float k);

            explicit Vector3D(const float *values);

            Vector3D(std::initializer_list<float> list);

            float I(void) const;

            float J(void) const;

            float K(void) const;

            Vector3D Add(const Vector3D &v) const;

            Vector3D Subtract(const Vector3D &v) const;

            Vector3D Normalize(void) const;

            float Distance(const Vector3D &rhs) const;

            float Magnitude(void) const;

            Vector3D Scale(float scalar) const;

            Vector3D Clip(float maxVal) const;

            Vector3D Weight(Vector3D dimWeights) const;

            float Dot(const Vector3D &rhs) const;

            Vector3D Cross(const Vector3D &rhs) const;

            float operator [](int i) const;

            bool operator ==(const Vector3D &rhs) const;

            bool operator !=(const Vector3D &rhs) const;

            bool operator <(const Vector3D &rhs) const;

            bool operator <=(const Vector3D &rhs) const;

            bool operator >(const Vector3D &rhs) const;

            bool operator >=(const Vector3D &rhs) const;

            Vector3D operator +(const Vector3D &rhs) const;

            Vector3D operator -(const Vector3D &rhs) const;

            Vector3D &operator +=(const Vector3D &rhs);

            Vector3D &operator -=(const Vector3D &rhs);

            friend Vector3D operator *(float scalar, const Vector3D &v);

            friend Vector3D operator *(const Vector3D &v, float scalar);

            float operator *(const Vector3D &rhs) const;

            Vector3D &operator *=(float scalar);

            Vector3D operator %(const Vector3D &rhs) const;

            Vector3D &operator %=(const Vector3D &rhs);

            friend std::ostream &operator<<(std::ostream &os, const Vector3D &obj);

            friend std::istream &operator>>(std::istream &is, Vector3D &obj);

        private:

            float _I = 0.f, _J = 0.f, _K = 0.f;
        };

}
<commit_msg>Fixed missing const reference on weight function declaration<commit_after>#pragma once

#include <iosfwd>
#include <initializer_list>

namespace RealRT
{
    class Vector3D
    {
        public:
            Vector3D(void) = default;

            Vector3D(float i, float j, float k);

            explicit Vector3D(const float *values);

            Vector3D(std::initializer_list<float> list);

            float I(void) const;

            float J(void) const;

            float K(void) const;

            Vector3D Add(const Vector3D &v) const;

            Vector3D Subtract(const Vector3D &v) const;

            Vector3D Normalize(void) const;

            float Distance(const Vector3D &rhs) const;

            float Magnitude(void) const;

            Vector3D Scale(float scalar) const;

            Vector3D Clip(float maxVal) const;

            Vector3D Weight(const Vector3D &dimWeights) const;

            float Dot(const Vector3D &rhs) const;

            Vector3D Cross(const Vector3D &rhs) const;

            float operator [](int i) const;

            bool operator ==(const Vector3D &rhs) const;

            bool operator !=(const Vector3D &rhs) const;

            bool operator <(const Vector3D &rhs) const;

            bool operator <=(const Vector3D &rhs) const;

            bool operator >(const Vector3D &rhs) const;

            bool operator >=(const Vector3D &rhs) const;

            Vector3D operator +(const Vector3D &rhs) const;

            Vector3D operator -(const Vector3D &rhs) const;

            Vector3D &operator +=(const Vector3D &rhs);

            Vector3D &operator -=(const Vector3D &rhs);

            friend Vector3D operator *(float scalar, const Vector3D &v);

            friend Vector3D operator *(const Vector3D &v, float scalar);

            float operator *(const Vector3D &rhs) const;

            Vector3D &operator *=(float scalar);

            Vector3D operator %(const Vector3D &rhs) const;

            Vector3D &operator %=(const Vector3D &rhs);

            friend std::ostream &operator<<(std::ostream &os, const Vector3D &obj);

            friend std::istream &operator>>(std::istream &is, Vector3D &obj);

        private:

            float _I = 0.f, _J = 0.f, _K = 0.f;
        };

}
<|endoftext|>


<commit_before>/**********************************************************************
**  Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
**  Author: Sérgio Martins <sergio.martins@kdab.com>
**
** This file may be distributed and/or modified under the terms of the
** GNU Lesser General Public License version 2.1 and version 3 as published by the
** Free Software Foundation and appearing in the file LICENSE.LGPL.txt included.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************/

#include "movablecontainers.h"
#include "Utils.h"

#include <clang/AST/AST.h>
#include <clang/AST/DeclTemplate.h>

#include <sstream>

using namespace std;
using namespace clang;

// Recomends usages of Q_PRIMITIVE_TYPE, don't advise for non-POD types that are movable

MovableContainers::MovableContainers(clang::CompilerInstance &ci)
    : CheckBase(ci)
{
}

void MovableContainers::VisitDecl(clang::Decl *decl)
{
    // Catches QTypeInfo<Foo> to know type classification
    auto templateDef = dyn_cast<ClassTemplateSpecializationDecl>(decl);
    if (templateDef) {
        registerQTypeInfo(templateDef);
    }

    // Catches QList<Foo>
    ClassTemplateSpecializationDecl *tstdecl = Utils::templateDecl(decl);
    if (tstdecl == nullptr || tstdecl->getName() != "QList")
        return;

    const TemplateArgumentList &tal = tstdecl->getTemplateArgs();

    if (tal.size() != 1) return;
    QualType qt2 = tal[0].getAsType();
    const int size_of_void = 32; // performance on arm is more important
    const int size_of_T = m_ci.getASTContext().getTypeSize(qt2); // QList<T>

    const bool isMovable = qt2.isTriviallyCopyableType(m_ci.getASTContext());

    if (size_of_T <= size_of_void && isMovable) {
        const Type *t = qt2.getTypePtrOrNull();
        if (t == nullptr || t->getAsCXXRecordDecl() == nullptr) return;

        std::string typeName = t->getAsCXXRecordDecl()->getName();
        if (m_typeInfos.count(t->getAsCXXRecordDecl()->getQualifiedNameAsString()) != 0)
            return;

        if (t->isRecordType() && !ignoreTypeInfo(typeName)) {
            std::string s;
            std::stringstream out;
            out << m_ci.getASTContext().getTypeSize(qt2)/8;
            s = "Make this class movable: " + typeName + " [-Wmore-warnings-movable]";
            emitWarning(decl->getLocStart(), s.c_str());
            emitWarning(t->getAsCXXRecordDecl()->getLocStart(), "Type declared here:");
        }
    }
}

void MovableContainers::registerQTypeInfo(ClassTemplateSpecializationDecl *decl)
{
    if (decl->getName() == "QTypeInfo") {
        auto &args = decl->getTemplateArgs();
        if (args.size() != 1)
            return;

        QualType qt = args[0].getAsType();
        const Type *t = qt.getTypePtrOrNull();
        CXXRecordDecl *recordDecl =  t ? t->getAsCXXRecordDecl() : nullptr;
        if (recordDecl != nullptr) {
            m_typeInfos.insert(recordDecl->getQualifiedNameAsString());
        }
    }
}

bool MovableContainers::ignoreTypeInfo(const std::string &className) const
{
    std::vector<std::string> primitives {"QPair"};
    return std::find(primitives.begin(), primitives.end(), className) != primitives.end();
}

std::string MovableContainers::name() const
{
    return "mark-it-primitive";
}
<commit_msg>Don't crash when we only have a fwd decl.<commit_after>/**********************************************************************
**  Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
**  Author: Sérgio Martins <sergio.martins@kdab.com>
**
** This file may be distributed and/or modified under the terms of the
** GNU Lesser General Public License version 2.1 and version 3 as published by the
** Free Software Foundation and appearing in the file LICENSE.LGPL.txt included.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************/

#include "movablecontainers.h"
#include "Utils.h"

#include <clang/AST/AST.h>
#include <clang/AST/DeclTemplate.h>

#include <sstream>

using namespace std;
using namespace clang;

// Recomends usages of Q_PRIMITIVE_TYPE, don't advise for non-POD types that are movable

MovableContainers::MovableContainers(clang::CompilerInstance &ci)
    : CheckBase(ci)
{
}

void MovableContainers::VisitDecl(clang::Decl *decl)
{
    // Catches QTypeInfo<Foo> to know type classification
    auto templateDef = dyn_cast<ClassTemplateSpecializationDecl>(decl);
    if (templateDef) {
        registerQTypeInfo(templateDef);
    }

    // Catches QList<Foo>
    ClassTemplateSpecializationDecl *tstdecl = Utils::templateDecl(decl);
    if (tstdecl == nullptr || tstdecl->getName() != "QList")
        return;

    const TemplateArgumentList &tal = tstdecl->getTemplateArgs();

    if (tal.size() != 1) return;
    QualType qt2 = tal[0].getAsType();

    const Type *t = qt2.getTypePtrOrNull();
    if (t == nullptr || t->getAsCXXRecordDecl() == nullptr || t->getAsCXXRecordDecl()->getDefinition() == nullptr) return; // Don't crash if we only have a fwd decl

    const int size_of_void = 32; // performance on arm is more important
    const int size_of_T = m_ci.getASTContext().getTypeSize(qt2); // QList<T>

    const bool isMovable = qt2.isTriviallyCopyableType(m_ci.getASTContext());

    if (size_of_T <= size_of_void && isMovable) {

        std::string typeName = t->getAsCXXRecordDecl()->getName();
        if (m_typeInfos.count(t->getAsCXXRecordDecl()->getQualifiedNameAsString()) != 0)
            return;

        if (t->isRecordType() && !ignoreTypeInfo(typeName)) {
            std::string s;
            std::stringstream out;
            out << m_ci.getASTContext().getTypeSize(qt2)/8;
            s = "Make this class movable: " + typeName + " [-Wmore-warnings-movable]";
            emitWarning(decl->getLocStart(), s.c_str());
            emitWarning(t->getAsCXXRecordDecl()->getLocStart(), "Type declared here:");
        }
    }
}

void MovableContainers::registerQTypeInfo(ClassTemplateSpecializationDecl *decl)
{
    if (decl->getName() == "QTypeInfo") {
        auto &args = decl->getTemplateArgs();
        if (args.size() != 1)
            return;

        QualType qt = args[0].getAsType();
        const Type *t = qt.getTypePtrOrNull();
        CXXRecordDecl *recordDecl =  t ? t->getAsCXXRecordDecl() : nullptr;
        if (recordDecl != nullptr) {
            m_typeInfos.insert(recordDecl->getQualifiedNameAsString());
        }
    }
}

bool MovableContainers::ignoreTypeInfo(const std::string &className) const
{
    std::vector<std::string> primitives {"QPair"};
    return std::find(primitives.begin(), primitives.end(), className) != primitives.end();
}

std::string MovableContainers::name() const
{
    return "mark-it-primitive";
}
<|endoftext|>


<commit_before>#include <QApplication>
#include "MotionCapture.h"
#include <ros/ros.h>

int main(int argc, char *argv[])
{
	ros::init(argc, argv, "MotionCapture");
	ros::NodeHandle node;
    QApplication a(argc, argv);
	MotionCapture w(node);
    w.show();

    return a.exec();
}

<commit_msg>Update main.cpp<commit_after>#include <QApplication>
#include "MotionCapture.h"
#include <ros/ros.h>

int main(int argc, char *argv[])
{
    ros::init(argc, argv, "MotionCapture");
    ros::NodeHandle node;
    QApplication a(argc, argv);
    MotionCapture w(node);
    w.show();

    return a.exec();
}

<|endoftext|>


<commit_before>#ifndef WIN32

//===--- TerminalDisplayUnix.cpp - Output To UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a UNIX terminal. It tries to
//  support all "common" terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#include "textinput/TerminalDisplayUnix.h"

#include "textinput/TerminalConfigUnix.h"
#include "textinput/Color.h"

#include <stdio.h>
// putenv not in cstdlib on Solaris
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <csignal>
#include <cstring>
#include <sstream>

using std::signal;
using std::strstr;

namespace {
  textinput::TerminalDisplayUnix*& gTerminalDisplayUnix() {
    static textinput::TerminalDisplayUnix* S = 0;
    return S;
  }

  void InitRGB256(unsigned char rgb256[][3]) {
    // initialize the array with the expected standard colors:
    // (from http://frexx.de/xterm-256-notes)

    // this is not what I see, though it's supposedly the default:
    //   rgb[0][0] =   0; rgb[0][1] =   0; rgb[0][1] =   0;
    // use this instead, just to be on the safe side:
    rgb256[0][0] =  46; rgb256[0][1] =  52; rgb256[0][1] =  64;
    rgb256[1][0] = 205; rgb256[1][1] =   0; rgb256[1][1] =   0;
    rgb256[2][0] =   0; rgb256[2][1] = 205; rgb256[2][1] =   0;
    rgb256[3][0] = 205; rgb256[3][1] = 205; rgb256[3][1] =   0;
    rgb256[4][0] =   0; rgb256[4][1] =   0; rgb256[4][1] = 238;
    rgb256[5][0] = 205; rgb256[5][1] =   0; rgb256[5][1] = 205;
    rgb256[6][0] =   0; rgb256[6][1] = 205; rgb256[6][1] = 205;
    rgb256[7][0] = 229; rgb256[7][1] = 229; rgb256[7][1] = 229;

    // this is not what I see, though it's supposedly the default:
    //   rgb256[ 8][0] = 127; rgb256[ 8][1] = 127; rgb256[ 8][1] = 127;
    // use this instead, just to be on the safe side:
    rgb256[ 8][0] =   0; rgb256[ 8][1] =   0; rgb256[ 8][1] =   0;
    rgb256[ 9][0] = 255; rgb256[ 9][1] =   0; rgb256[ 9][1] =   0;
    rgb256[10][0] =   0; rgb256[10][1] = 255; rgb256[10][1] =   0;
    rgb256[11][0] = 255; rgb256[11][1] = 255; rgb256[11][1] =   0;
    rgb256[12][0] =  92; rgb256[12][1] =  92; rgb256[12][1] = 255;
    rgb256[13][0] = 255; rgb256[13][1] =   0; rgb256[13][1] = 255;
    rgb256[14][0] =   0; rgb256[14][1] = 255; rgb256[14][1] = 255;
    rgb256[15][0] = 255; rgb256[15][1] = 255; rgb256[15][1] = 255;

    // 6 intensity RGB
    static const int intensities[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
    int idx = 16;
    for (int r = 0; r < 6; ++r) {
      for (int g = 0; g < 6; ++g) {
        for (int b = 0; b < 6; ++b) {
          rgb256[idx][0] = intensities[r];
          rgb256[idx][1] = intensities[g];
          rgb256[idx][2] = intensities[b];
          ++idx;
        }
      }
    }

    // colors 232-255 are a grayscale ramp, intentionally leaving out
    // black and white
    for (unsigned char gray = 0; gray < 24; ++gray) {
      unsigned char level = (gray * 10) + 8;
      rgb256[232 + gray][0] = level;
      rgb256[232 + gray][1] = level;
      rgb256[232 + gray][2] = level;
    }
  }
} // unnamed namespace

extern "C" void TerminalDisplayUnix__handleResizeSignal(int) {
  gTerminalDisplayUnix()->HandleResizeSignal();
}

namespace textinput {
  // If input is not a tty don't write in tty-mode either.
  TerminalDisplayUnix::TerminalDisplayUnix():
    TerminalDisplay(isatty(fileno(stdin)) && isatty(fileno(stdout))),
    fIsAttached(false), fNColors(16) {
    HandleResizeSignal();
    gTerminalDisplayUnix() = this;
    signal(SIGWINCH, TerminalDisplayUnix__handleResizeSignal);
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ECHO);
    TerminalConfigUnix::Get().TIOS()->c_lflag |= ECHOCTL|ECHOKE|ECHOE;
#endif
    const char* TERM = getenv("TERM");
    if (TERM &&  strstr(TERM, "256")) {
      fNColors = 256;
    }
  }

  TerminalDisplayUnix::~TerminalDisplayUnix() {
    Detach();
  }

  void
  TerminalDisplayUnix::HandleResizeSignal() {
#ifdef TIOCGWINSZ
    struct winsize sz;
    int ret = ioctl(fileno(stdout), TIOCGWINSZ, (char*)&sz);
    if (!ret && sz.ws_col) {
      SetWidth(sz.ws_col);

      // Export what we found.
      std::stringstream s;
      s << sz.ws_col;
      setenv("COLUMS", s.str().c_str(), 1 /*overwrite*/);
      s.clear();
      s << sz.ws_row;
      setenv("LINES", s.str().c_str(), 1 /*overwrite*/);
    }
#else
    // try $COLUMNS
    const char* COLUMNS = getenv("COLUMNS");
    if (COLUMNS) {
      long width = atol(COLUMNS);
      if (width > 4 && width < 1024*16) {
        SetWidth(width);
      }
    }
#endif
  }

  void
  TerminalDisplayUnix::SetColor(char CIdx, const Color& C) {
    if (!IsTTY()) return;

    // Default color, reset previous bold etc.
    static const char text[] = {(char)0x1b, '[', '0', 'm', 0};
    WriteRawString(text, 4);

    if (CIdx == 0) return;

    if (fNColors == 256) {
      int ANSIIdx = GetClosestColorIdx256(C);
      static const char preamble[] = {'\x1b', '[', '3', '8', ';', '5', ';', 0};
      std::string buf(preamble);
      if (ANSIIdx > 100) {
        buf += '0' + (ANSIIdx / 100);
      }
      if (ANSIIdx > 10) {
        buf += '0' + ((ANSIIdx / 10) % 10);
      }
      buf += '0' + (ANSIIdx % 10);
      buf +=  "m";
      WriteRawString(buf.c_str(), buf.length());
    } else {
      int ANSIIdx = GetClosestColorIdx16(C);
      char buf[] = {'\x1b', '[', '3', '0' + (ANSIIdx % 8), 'm', 0};
      if (ANSIIdx > 7) buf[2] += 6;
      WriteRawString(buf, 5);
    }

    if (C.fModifiers & Color::kModUnderline) {
      WriteRawString("\033[4m", 4);
    }
    if (C.fModifiers & Color::kModBold) {
      WriteRawString("\033[1m", 4);
    }
    if (C.fModifiers & Color::kModInverse) {
      WriteRawString("\033[7m", 4);
    }

  }

  void
  TerminalDisplayUnix::MoveFront() {
    static const char text[] = {(char)0x1b, '[', '1', 'G', 0};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::MoveInternal(char What, size_t n) {
    static const char cmd[] = "\x1b[";
    if (!IsTTY()) return;
    std::string text;
    for (size_t i = 0; i < n; ++i) {
      text += cmd;
      text += What;
    }
    WriteRawString(text.c_str(), text.length());
  }

  void
  TerminalDisplayUnix::MoveUp(size_t nLines /* = 1 */) {
    MoveInternal('A', nLines);
  }

  void
  TerminalDisplayUnix::MoveDown(size_t nLines /* = 1 */) {
    if (!IsTTY()) return;
    std::string moves(nLines, 0x0a);
    WriteRawString(moves.c_str(), nLines);
  }

  void
  TerminalDisplayUnix::MoveRight(size_t nCols /* = 1 */) {
    MoveInternal('C', nCols);
  }

  void
  TerminalDisplayUnix::MoveLeft(size_t nCols /* = 1 */) {
    MoveInternal('D', nCols);
  }

  void
  TerminalDisplayUnix::EraseToRight() {
    static const char text[] = {(char)0x1b, '[', 'K', 0};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::WriteRawString(const char *text, size_t len) {
    if (write(fileno(stdout), text, len) == -1) {
      // Silence Ubuntu's "unused result". We don't care if it fails.
    }
  }

  void
  TerminalDisplayUnix::ActOnEOL() {
    if (!IsTTY()) return;
    WriteRawString(" \b", 2);
    //MoveUp();
  }

  void
  TerminalDisplayUnix::Attach() {
    // set to noecho
    if (fIsAttached) return;
    fflush(stdout);
    TerminalConfigUnix::Get().Attach();
    fIsAttached = true;
    NotifyTextChange(Range::AllWithPrompt());
  }

  void
  TerminalDisplayUnix::Detach() {
    if (!fIsAttached) return;
    fflush(stdout);
    TerminalConfigUnix::Get().Detach();
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx16(const Color& C) {
    int r = C.fR;
    int g = C.fG;
    int b = C.fB;
    int sum = r + g + b;
    r = r > sum / 4;
    g = g > sum / 4;
    b = b > sum / 4;

    // ANSI:
    return r + (g * 2) + (b * 4);
    // ! ANSI:
    // return (r * 4) + (g * 2) + b;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx256(const Color& C) {
    static unsigned char rgb256[256][3] = {{0}};
    if (rgb256[0][0] == 0) {
      InitRGB256(rgb256);
    }

    // Find the closest index.
    // A: the closest color match (square of geometric distance in RGB)
    // B: the closest brightness match
    // Treat them equally, which suppresses differences
    // in color due to squared distance.

    // start with black:
    int idx = 0;
    unsigned int r = C.fR;
    unsigned int g = C.fG;
    unsigned int b = C.fB;
    unsigned int graylvl = (r + g + b)/3;
    long mindelta = (r*r + g*g + b*b) + graylvl;
    if (mindelta) {
      for (unsigned int i = 0; i < 256; ++i) {
        long delta = (rgb256[i][0] + rgb256[i][1] + rgb256[i][2])/3 - graylvl;
        if (delta < 0) delta = -delta;
        delta += (r-rgb256[i][0])*(r-rgb256[i][0]) +
        (g-rgb256[i][1])*(g-rgb256[i][1]) +
        (b-rgb256[i][2])*(b-rgb256[i][2]);

        if (delta < mindelta) {
          mindelta = delta;
          idx = i;
          if (mindelta == 0) break;
        }
      }
    }
    return idx;
  }

}

#endif // #ifndef WIN32
<commit_msg>Reset fWritePos+Len when Attach()ing: we don't know where the application has sent us, cursor-wise.<commit_after>#ifndef WIN32

//===--- TerminalDisplayUnix.cpp - Output To UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a UNIX terminal. It tries to
//  support all "common" terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#include "textinput/TerminalDisplayUnix.h"

#include "textinput/TerminalConfigUnix.h"
#include "textinput/Color.h"

#include <stdio.h>
// putenv not in cstdlib on Solaris
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <csignal>
#include <cstring>
#include <sstream>

using std::signal;
using std::strstr;

namespace {
  textinput::TerminalDisplayUnix*& gTerminalDisplayUnix() {
    static textinput::TerminalDisplayUnix* S = 0;
    return S;
  }

  void InitRGB256(unsigned char rgb256[][3]) {
    // initialize the array with the expected standard colors:
    // (from http://frexx.de/xterm-256-notes)

    // this is not what I see, though it's supposedly the default:
    //   rgb[0][0] =   0; rgb[0][1] =   0; rgb[0][1] =   0;
    // use this instead, just to be on the safe side:
    rgb256[0][0] =  46; rgb256[0][1] =  52; rgb256[0][1] =  64;
    rgb256[1][0] = 205; rgb256[1][1] =   0; rgb256[1][1] =   0;
    rgb256[2][0] =   0; rgb256[2][1] = 205; rgb256[2][1] =   0;
    rgb256[3][0] = 205; rgb256[3][1] = 205; rgb256[3][1] =   0;
    rgb256[4][0] =   0; rgb256[4][1] =   0; rgb256[4][1] = 238;
    rgb256[5][0] = 205; rgb256[5][1] =   0; rgb256[5][1] = 205;
    rgb256[6][0] =   0; rgb256[6][1] = 205; rgb256[6][1] = 205;
    rgb256[7][0] = 229; rgb256[7][1] = 229; rgb256[7][1] = 229;

    // this is not what I see, though it's supposedly the default:
    //   rgb256[ 8][0] = 127; rgb256[ 8][1] = 127; rgb256[ 8][1] = 127;
    // use this instead, just to be on the safe side:
    rgb256[ 8][0] =   0; rgb256[ 8][1] =   0; rgb256[ 8][1] =   0;
    rgb256[ 9][0] = 255; rgb256[ 9][1] =   0; rgb256[ 9][1] =   0;
    rgb256[10][0] =   0; rgb256[10][1] = 255; rgb256[10][1] =   0;
    rgb256[11][0] = 255; rgb256[11][1] = 255; rgb256[11][1] =   0;
    rgb256[12][0] =  92; rgb256[12][1] =  92; rgb256[12][1] = 255;
    rgb256[13][0] = 255; rgb256[13][1] =   0; rgb256[13][1] = 255;
    rgb256[14][0] =   0; rgb256[14][1] = 255; rgb256[14][1] = 255;
    rgb256[15][0] = 255; rgb256[15][1] = 255; rgb256[15][1] = 255;

    // 6 intensity RGB
    static const int intensities[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
    int idx = 16;
    for (int r = 0; r < 6; ++r) {
      for (int g = 0; g < 6; ++g) {
        for (int b = 0; b < 6; ++b) {
          rgb256[idx][0] = intensities[r];
          rgb256[idx][1] = intensities[g];
          rgb256[idx][2] = intensities[b];
          ++idx;
        }
      }
    }

    // colors 232-255 are a grayscale ramp, intentionally leaving out
    // black and white
    for (unsigned char gray = 0; gray < 24; ++gray) {
      unsigned char level = (gray * 10) + 8;
      rgb256[232 + gray][0] = level;
      rgb256[232 + gray][1] = level;
      rgb256[232 + gray][2] = level;
    }
  }
} // unnamed namespace

extern "C" void TerminalDisplayUnix__handleResizeSignal(int) {
  gTerminalDisplayUnix()->HandleResizeSignal();
}

namespace textinput {
  // If input is not a tty don't write in tty-mode either.
  TerminalDisplayUnix::TerminalDisplayUnix():
    TerminalDisplay(isatty(fileno(stdin)) && isatty(fileno(stdout))),
    fIsAttached(false), fNColors(16) {
    HandleResizeSignal();
    gTerminalDisplayUnix() = this;
    signal(SIGWINCH, TerminalDisplayUnix__handleResizeSignal);
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ECHO);
    TerminalConfigUnix::Get().TIOS()->c_lflag |= ECHOCTL|ECHOKE|ECHOE;
#endif
    const char* TERM = getenv("TERM");
    if (TERM &&  strstr(TERM, "256")) {
      fNColors = 256;
    }
  }

  TerminalDisplayUnix::~TerminalDisplayUnix() {
    Detach();
  }

  void
  TerminalDisplayUnix::HandleResizeSignal() {
#ifdef TIOCGWINSZ
    struct winsize sz;
    int ret = ioctl(fileno(stdout), TIOCGWINSZ, (char*)&sz);
    if (!ret && sz.ws_col) {
      SetWidth(sz.ws_col);

      // Export what we found.
      std::stringstream s;
      s << sz.ws_col;
      setenv("COLUMS", s.str().c_str(), 1 /*overwrite*/);
      s.clear();
      s << sz.ws_row;
      setenv("LINES", s.str().c_str(), 1 /*overwrite*/);
    }
#else
    // try $COLUMNS
    const char* COLUMNS = getenv("COLUMNS");
    if (COLUMNS) {
      long width = atol(COLUMNS);
      if (width > 4 && width < 1024*16) {
        SetWidth(width);
      }
    }
#endif
  }

  void
  TerminalDisplayUnix::SetColor(char CIdx, const Color& C) {
    if (!IsTTY()) return;

    // Default color, reset previous bold etc.
    static const char text[] = {(char)0x1b, '[', '0', 'm', 0};
    WriteRawString(text, 4);

    if (CIdx == 0) return;

    if (fNColors == 256) {
      int ANSIIdx = GetClosestColorIdx256(C);
      static const char preamble[] = {'\x1b', '[', '3', '8', ';', '5', ';', 0};
      std::string buf(preamble);
      if (ANSIIdx > 100) {
        buf += '0' + (ANSIIdx / 100);
      }
      if (ANSIIdx > 10) {
        buf += '0' + ((ANSIIdx / 10) % 10);
      }
      buf += '0' + (ANSIIdx % 10);
      buf +=  "m";
      WriteRawString(buf.c_str(), buf.length());
    } else {
      int ANSIIdx = GetClosestColorIdx16(C);
      char buf[] = {'\x1b', '[', '3', '0' + (ANSIIdx % 8), 'm', 0};
      if (ANSIIdx > 7) buf[2] += 6;
      WriteRawString(buf, 5);
    }

    if (C.fModifiers & Color::kModUnderline) {
      WriteRawString("\033[4m", 4);
    }
    if (C.fModifiers & Color::kModBold) {
      WriteRawString("\033[1m", 4);
    }
    if (C.fModifiers & Color::kModInverse) {
      WriteRawString("\033[7m", 4);
    }

  }

  void
  TerminalDisplayUnix::MoveFront() {
    static const char text[] = {(char)0x1b, '[', '1', 'G', 0};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::MoveInternal(char What, size_t n) {
    static const char cmd[] = "\x1b[";
    if (!IsTTY()) return;
    std::string text;
    for (size_t i = 0; i < n; ++i) {
      text += cmd;
      text += What;
    }
    WriteRawString(text.c_str(), text.length());
  }

  void
  TerminalDisplayUnix::MoveUp(size_t nLines /* = 1 */) {
    MoveInternal('A', nLines);
  }

  void
  TerminalDisplayUnix::MoveDown(size_t nLines /* = 1 */) {
    if (!IsTTY()) return;
    std::string moves(nLines, 0x0a);
    WriteRawString(moves.c_str(), nLines);
  }

  void
  TerminalDisplayUnix::MoveRight(size_t nCols /* = 1 */) {
    MoveInternal('C', nCols);
  }

  void
  TerminalDisplayUnix::MoveLeft(size_t nCols /* = 1 */) {
    MoveInternal('D', nCols);
  }

  void
  TerminalDisplayUnix::EraseToRight() {
    static const char text[] = {(char)0x1b, '[', 'K', 0};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::WriteRawString(const char *text, size_t len) {
    if (write(fileno(stdout), text, len) == -1) {
      // Silence Ubuntu's "unused result". We don't care if it fails.
    }
  }

  void
  TerminalDisplayUnix::ActOnEOL() {
    if (!IsTTY()) return;
    WriteRawString(" \b", 2);
    //MoveUp();
  }

  void
  TerminalDisplayUnix::Attach() {
    // set to noecho
    if (fIsAttached) return;
    fflush(stdout);
    TerminalConfigUnix::Get().Attach();
    fWritePos = Pos();
    fWriteLen = 0;
    fIsAttached = true;
    NotifyTextChange(Range::AllWithPrompt());
  }

  void
  TerminalDisplayUnix::Detach() {
    if (!fIsAttached) return;
    fflush(stdout);
    TerminalConfigUnix::Get().Detach();
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx16(const Color& C) {
    int r = C.fR;
    int g = C.fG;
    int b = C.fB;
    int sum = r + g + b;
    r = r > sum / 4;
    g = g > sum / 4;
    b = b > sum / 4;

    // ANSI:
    return r + (g * 2) + (b * 4);
    // ! ANSI:
    // return (r * 4) + (g * 2) + b;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx256(const Color& C) {
    static unsigned char rgb256[256][3] = {{0}};
    if (rgb256[0][0] == 0) {
      InitRGB256(rgb256);
    }

    // Find the closest index.
    // A: the closest color match (square of geometric distance in RGB)
    // B: the closest brightness match
    // Treat them equally, which suppresses differences
    // in color due to squared distance.

    // start with black:
    int idx = 0;
    unsigned int r = C.fR;
    unsigned int g = C.fG;
    unsigned int b = C.fB;
    unsigned int graylvl = (r + g + b)/3;
    long mindelta = (r*r + g*g + b*b) + graylvl;
    if (mindelta) {
      for (unsigned int i = 0; i < 256; ++i) {
        long delta = (rgb256[i][0] + rgb256[i][1] + rgb256[i][2])/3 - graylvl;
        if (delta < 0) delta = -delta;
        delta += (r-rgb256[i][0])*(r-rgb256[i][0]) +
        (g-rgb256[i][1])*(g-rgb256[i][1]) +
        (b-rgb256[i][2])*(b-rgb256[i][2]);

        if (delta < mindelta) {
          mindelta = delta;
          idx = i;
          if (mindelta == 0) break;
        }
      }
    }
    return idx;
  }

}

#endif // #ifndef WIN32
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/nacl/nacl_listener.h"

#include <errno.h>
#include <stdlib.h>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/common/nacl_messages.h"
#include "chrome/nacl/nacl_validation_db.h"
#include "chrome/nacl/nacl_validation_query.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
#include "ipc/ipc_switches.h"
#include "native_client/src/trusted/service_runtime/sel_main_chrome.h"

#if defined(OS_LINUX)
#include "content/public/common/child_process_sandbox_support_linux.h"
#endif

#if defined(OS_WIN)
#include <fcntl.h>
#include <io.h>

#include "content/public/common/sandbox_init.h"
#endif

namespace {
#if defined(OS_MACOSX)

// On Mac OS X, shm_open() works in the sandbox but does not give us
// an FD that we can map as PROT_EXEC.  Rather than doing an IPC to
// get an executable SHM region when CreateMemoryObject() is called,
// we preallocate one on startup, since NaCl's sel_ldr only needs one
// of them.  This saves a round trip.

base::subtle::Atomic32 g_shm_fd = -1;

int CreateMemoryObject(size_t size, int executable) {
  if (executable && size > 0) {
    int result_fd = base::subtle::NoBarrier_AtomicExchange(&g_shm_fd, -1);
    if (result_fd != -1) {
      // ftruncate() is disallowed by the Mac OS X sandbox and
      // returns EPERM.  Luckily, we can get the same effect with
      // lseek() + write().
      if (lseek(result_fd, size - 1, SEEK_SET) == -1) {
        LOG(ERROR) << "lseek() failed: " << errno;
        return -1;
      }
      if (write(result_fd, "", 1) != 1) {
        LOG(ERROR) << "write() failed: " << errno;
        return -1;
      }
      return result_fd;
    }
  }
  // Fall back to NaCl's default implementation.
  return -1;
}

#elif defined(OS_LINUX)

int CreateMemoryObject(size_t size, int executable) {
  return content::MakeSharedMemorySegmentViaIPC(size, executable);
}

#elif defined(OS_WIN)

// We wrap the function to convert the bool return value to an int.
int BrokerDuplicateHandle(NaClHandle source_handle,
                          uint32_t process_id,
                          NaClHandle* target_handle,
                          uint32_t desired_access,
                          uint32_t options) {
  return content::BrokerDuplicateHandle(source_handle, process_id,
                                        target_handle, desired_access,
                                        options);
}

#endif

// Use an env var because command line args are eaten by nacl_helper.
bool CheckEnvVar(const char* name, bool default_value) {
  bool result = default_value;
  const char* var = getenv(name);
  if (var && strlen(var) > 0) {
    result = var[0] != '0';
  }
  return result;
}

}  // namespace

class BrowserValidationDBProxy : public NaClValidationDB {
 public:
  explicit BrowserValidationDBProxy(NaClListener* listener)
      : listener_(listener) {
  }

  bool QueryKnownToValidate(const std::string& signature) {
    // Initialize to false so that if the Send fails to write to the return
    // value we're safe.  For example if the message is (for some reason)
    // dispatched as an async message the return parameter will not be written.
    bool result = false;
    if (!listener_->Send(new NaClProcessMsg_QueryKnownToValidate(signature,
                                                                 &result))) {
      LOG(ERROR) << "Failed to query NaCl validation cache.";
      result = false;
    }
    return result;
  }

  void SetKnownToValidate(const std::string& signature) {
    // Caching is optional: NaCl will still work correctly if the IPC fails.
    if (!listener_->Send(new NaClProcessMsg_SetKnownToValidate(signature))) {
      LOG(ERROR) << "Failed to update NaCl validation cache.";
    }
  }

 private:
  // The listener never dies, otherwise this might be a dangling reference.
  NaClListener* listener_;
};

NaClListener::NaClListener() : shutdown_event_(true, false),
                               io_thread_("NaCl_IOThread"),
                               main_loop_(NULL),
                               debug_enabled_(false) {
  io_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
}

NaClListener::~NaClListener() {
  NOTREACHED();
  shutdown_event_.Signal();
}

bool NaClListener::Send(IPC::Message* msg) {
  DCHECK(main_loop_ != NULL);
  if (MessageLoop::current() == main_loop_) {
    // This thread owns the channel.
    return channel_->Send(msg);
  } else {
    // This thread does not own the channel.
    return filter_->Send(msg);
  }
}

void NaClListener::Listen() {
  std::string channel_name =
      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kProcessChannelID);
  channel_.reset(new IPC::SyncChannel(this, io_thread_.message_loop_proxy(),
                                      &shutdown_event_));
  filter_ = new IPC::SyncMessageFilter(&shutdown_event_);
  channel_->AddFilter(filter_.get());
  channel_->Init(channel_name, IPC::Channel::MODE_CLIENT, true);
  main_loop_ = MessageLoop::current();
  main_loop_->Run();
}

bool NaClListener::OnMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(NaClListener, msg)
      IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnMsgStart)
      IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void NaClListener::OnMsgStart(const nacl::NaClStartParams& params) {
  struct NaClChromeMainArgs *args = NaClChromeMainArgsCreate();
  if (args == NULL) {
    LOG(ERROR) << "NaClChromeMainArgsCreate() failed";
    return;
  }

  std::vector<nacl::FileDescriptor> handles = params.handles;

#if defined(OS_LINUX) || defined(OS_MACOSX)
  args->create_memory_object_func = CreateMemoryObject;
# if defined(OS_MACOSX)
  CHECK(handles.size() >= 1);
  g_shm_fd = nacl::ToNativeHandle(handles[handles.size() - 1]);
  handles.pop_back();
# endif
#endif

  CHECK(handles.size() >= 1);
  NaClHandle irt_handle = nacl::ToNativeHandle(handles[handles.size() - 1]);
  handles.pop_back();

#if defined(OS_WIN)
  args->irt_fd = _open_osfhandle(reinterpret_cast<intptr_t>(irt_handle),
                                 _O_RDONLY | _O_BINARY);
  if (args->irt_fd < 0) {
    LOG(ERROR) << "_open_osfhandle() failed";
    return;
  }
#else
  args->irt_fd = irt_handle;
#endif

  if (CheckEnvVar("NACL_VALIDATION_CACHE", true)) {
    // The cache structure is not freed and exists until the NaCl process exits.
    args->validation_cache = CreateValidationCache(
        new BrowserValidationDBProxy(this), params.validation_cache_key,
        params.version);
  }

  CHECK(handles.size() == 1);
  args->imc_bootstrap_handle = nacl::ToNativeHandle(handles[0]);
  args->enable_exception_handling = params.enable_exception_handling;
  args->enable_debug_stub = debug_enabled_;
#if defined(OS_WIN)
  args->broker_duplicate_handle_func = BrokerDuplicateHandle;
#endif
  NaClChromeMainStart(args);
  NOTREACHED();
}
<commit_msg>Revert 134369 "Enable NaCl's validation cache."<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/nacl/nacl_listener.h"

#include <errno.h>
#include <stdlib.h>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/common/nacl_messages.h"
#include "chrome/nacl/nacl_validation_db.h"
#include "chrome/nacl/nacl_validation_query.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
#include "ipc/ipc_switches.h"
#include "native_client/src/trusted/service_runtime/sel_main_chrome.h"

#if defined(OS_LINUX)
#include "content/public/common/child_process_sandbox_support_linux.h"
#endif

#if defined(OS_WIN)
#include <fcntl.h>
#include <io.h>

#include "content/public/common/sandbox_init.h"
#endif

namespace {
#if defined(OS_MACOSX)

// On Mac OS X, shm_open() works in the sandbox but does not give us
// an FD that we can map as PROT_EXEC.  Rather than doing an IPC to
// get an executable SHM region when CreateMemoryObject() is called,
// we preallocate one on startup, since NaCl's sel_ldr only needs one
// of them.  This saves a round trip.

base::subtle::Atomic32 g_shm_fd = -1;

int CreateMemoryObject(size_t size, int executable) {
  if (executable && size > 0) {
    int result_fd = base::subtle::NoBarrier_AtomicExchange(&g_shm_fd, -1);
    if (result_fd != -1) {
      // ftruncate() is disallowed by the Mac OS X sandbox and
      // returns EPERM.  Luckily, we can get the same effect with
      // lseek() + write().
      if (lseek(result_fd, size - 1, SEEK_SET) == -1) {
        LOG(ERROR) << "lseek() failed: " << errno;
        return -1;
      }
      if (write(result_fd, "", 1) != 1) {
        LOG(ERROR) << "write() failed: " << errno;
        return -1;
      }
      return result_fd;
    }
  }
  // Fall back to NaCl's default implementation.
  return -1;
}

#elif defined(OS_LINUX)

int CreateMemoryObject(size_t size, int executable) {
  return content::MakeSharedMemorySegmentViaIPC(size, executable);
}

#elif defined(OS_WIN)

// We wrap the function to convert the bool return value to an int.
int BrokerDuplicateHandle(NaClHandle source_handle,
                          uint32_t process_id,
                          NaClHandle* target_handle,
                          uint32_t desired_access,
                          uint32_t options) {
  return content::BrokerDuplicateHandle(source_handle, process_id,
                                        target_handle, desired_access,
                                        options);
}

#endif

// Use an env var because command line args are eaten by nacl_helper.
bool CheckEnvVar(const char* name, bool default_value) {
  bool result = default_value;
  const char* var = getenv(name);
  if (var && strlen(var) > 0) {
    result = var[0] != '0';
  }
  return result;
}

}  // namespace

class BrowserValidationDBProxy : public NaClValidationDB {
 public:
  explicit BrowserValidationDBProxy(NaClListener* listener)
      : listener_(listener) {
  }

  bool QueryKnownToValidate(const std::string& signature) {
    // Initialize to false so that if the Send fails to write to the return
    // value we're safe.  For example if the message is (for some reason)
    // dispatched as an async message the return parameter will not be written.
    bool result = false;
    if (!listener_->Send(new NaClProcessMsg_QueryKnownToValidate(signature,
                                                                 &result))) {
      LOG(ERROR) << "Failed to query NaCl validation cache.";
      result = false;
    }
    return result;
  }

  void SetKnownToValidate(const std::string& signature) {
    // Caching is optional: NaCl will still work correctly if the IPC fails.
    if (!listener_->Send(new NaClProcessMsg_SetKnownToValidate(signature))) {
      LOG(ERROR) << "Failed to update NaCl validation cache.";
    }
  }

 private:
  // The listener never dies, otherwise this might be a dangling reference.
  NaClListener* listener_;
};

NaClListener::NaClListener() : shutdown_event_(true, false),
                               io_thread_("NaCl_IOThread"),
                               main_loop_(NULL),
                               debug_enabled_(false) {
  io_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
}

NaClListener::~NaClListener() {
  NOTREACHED();
  shutdown_event_.Signal();
}

bool NaClListener::Send(IPC::Message* msg) {
  DCHECK(main_loop_ != NULL);
  if (MessageLoop::current() == main_loop_) {
    // This thread owns the channel.
    return channel_->Send(msg);
  } else {
    // This thread does not own the channel.
    return filter_->Send(msg);
  }
}

void NaClListener::Listen() {
  std::string channel_name =
      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kProcessChannelID);
  channel_.reset(new IPC::SyncChannel(this, io_thread_.message_loop_proxy(),
                                      &shutdown_event_));
  filter_ = new IPC::SyncMessageFilter(&shutdown_event_);
  channel_->AddFilter(filter_.get());
  channel_->Init(channel_name, IPC::Channel::MODE_CLIENT, true);
  main_loop_ = MessageLoop::current();
  main_loop_->Run();
}

bool NaClListener::OnMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(NaClListener, msg)
      IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnMsgStart)
      IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void NaClListener::OnMsgStart(const nacl::NaClStartParams& params) {
  struct NaClChromeMainArgs *args = NaClChromeMainArgsCreate();
  if (args == NULL) {
    LOG(ERROR) << "NaClChromeMainArgsCreate() failed";
    return;
  }

  std::vector<nacl::FileDescriptor> handles = params.handles;

#if defined(OS_LINUX) || defined(OS_MACOSX)
  args->create_memory_object_func = CreateMemoryObject;
# if defined(OS_MACOSX)
  CHECK(handles.size() >= 1);
  g_shm_fd = nacl::ToNativeHandle(handles[handles.size() - 1]);
  handles.pop_back();
# endif
#endif

  CHECK(handles.size() >= 1);
  NaClHandle irt_handle = nacl::ToNativeHandle(handles[handles.size() - 1]);
  handles.pop_back();

#if defined(OS_WIN)
  args->irt_fd = _open_osfhandle(reinterpret_cast<intptr_t>(irt_handle),
                                 _O_RDONLY | _O_BINARY);
  if (args->irt_fd < 0) {
    LOG(ERROR) << "_open_osfhandle() failed";
    return;
  }
#else
  args->irt_fd = irt_handle;
#endif

  if (CheckEnvVar("NACL_VALIDATION_CACHE", false)) {
    LOG(INFO) << "NaCl validation cache enabled.";
    // The cache structure is not freed and exists until the NaCl process exits.
    args->validation_cache = CreateValidationCache(
        new BrowserValidationDBProxy(this), params.validation_cache_key,
        params.version);
  }

  CHECK(handles.size() == 1);
  args->imc_bootstrap_handle = nacl::ToNativeHandle(handles[0]);
  args->enable_exception_handling = params.enable_exception_handling;
  args->enable_debug_stub = debug_enabled_;
#if defined(OS_WIN)
  args->broker_duplicate_handle_func = BrokerDuplicateHandle;
#endif
  NaClChromeMainStart(args);
  NOTREACHED();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"

#include "core/svg/SVGTests.h"

#include "SVGNames.h"
#include "core/dom/Attribute.h"
#include "core/dom/DOMImplementation.h"
#include "core/platform/Language.h"
#include "core/svg/SVGElement.h"
#include "core/svg/SVGStringList.h"

namespace WebCore {

// Define custom non-animated property 'requiredFeatures'.
const SVGPropertyInfo* SVGTests::requiredFeaturesPropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::requiredFeaturesAttr,
                                             SVGNames::requiredFeaturesAttr.localName(),
                                             &SVGElement::synchronizeRequiredFeatures,
                                             0);
    }
    return s_propertyInfo;
}

// Define custom non-animated property 'requiredExtensions'.
const SVGPropertyInfo* SVGTests::requiredExtensionsPropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::requiredExtensionsAttr,
                                             SVGNames::requiredExtensionsAttr.localName(),
                                             &SVGElement::synchronizeRequiredExtensions,
                                             0);
    }
    return s_propertyInfo;
}

// Define custom non-animated property 'systemLanguage'.
const SVGPropertyInfo* SVGTests::systemLanguagePropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::systemLanguageAttr,
                                             SVGNames::systemLanguageAttr.localName(),
                                             &SVGElement::synchronizeSystemLanguage,
                                             0);
    }
    return s_propertyInfo;
}

SVGTests::SVGTests()
    : m_requiredFeatures(SVGNames::requiredFeaturesAttr)
    , m_requiredExtensions(SVGNames::requiredExtensionsAttr)
    , m_systemLanguage(SVGNames::systemLanguageAttr)
{
}

SVGAttributeToPropertyMap& SVGTests::attributeToPropertyMap()
{
    DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, map, ());
    if (!map.isEmpty())
        return map;
    map.addProperty(requiredFeaturesPropertyInfo());
    map.addProperty(requiredExtensionsPropertyInfo());
    map.addProperty(systemLanguagePropertyInfo());
    return map;
}

bool SVGTests::hasExtension(const String&) const
{
    // FIXME: Implement me!
    return false;
}

bool SVGTests::isValid() const
{
    unsigned featuresSize = m_requiredFeatures.value.size();
    for (unsigned i = 0; i < featuresSize; ++i) {
        String value = m_requiredFeatures.value.at(i);
        if (value.isEmpty() || !DOMImplementation::hasFeature(value, String()))
            return false;
    }

    unsigned systemLanguageSize = m_systemLanguage.value.size();
    for (unsigned i = 0; i < systemLanguageSize; ++i) {
        String value = m_systemLanguage.value.at(i);
        if (value != defaultLanguage().substring(0, 2))
            return false;
    }

    if (!m_requiredExtensions.value.isEmpty())
        return false;

    return true;
}

bool SVGTests::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (name == SVGNames::requiredFeaturesAttr) {
        m_requiredFeatures.value.reset(value);
        return true;
    }
    if (name == SVGNames::requiredExtensionsAttr) {
        m_requiredExtensions.value.reset(value);
        return true;
    }
    if (name == SVGNames::systemLanguageAttr) {
        m_systemLanguage.value.reset(value);
        return true;
    }

    return false;
}

bool SVGTests::isKnownAttribute(const QualifiedName& attrName)
{
    return attrName == SVGNames::requiredFeaturesAttr
        || attrName == SVGNames::requiredExtensionsAttr
        || attrName == SVGNames::systemLanguageAttr;
}

bool SVGTests::handleAttributeChange(SVGElement* targetElement, const QualifiedName& attrName)
{
    ASSERT(targetElement);
    if (!isKnownAttribute(attrName))
        return false;
    if (!targetElement->inDocument())
        return true;

    bool valid = targetElement->isValid();
    bool attached = targetElement->attached();
    if (valid && !attached && targetElement->parentNode()->attached())
        targetElement->attach();
    else if (!valid && attached)
        targetElement->detach();

    return true;
}

void SVGTests::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes)
{
    supportedAttributes.add(SVGNames::requiredFeaturesAttr);
    supportedAttributes.add(SVGNames::requiredExtensionsAttr);
    supportedAttributes.add(SVGNames::systemLanguageAttr);
}

void SVGTests::synchronizeRequiredFeatures(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_requiredFeatures.shouldSynchronize)
        return;
    AtomicString value(m_requiredFeatures.value.valueAsString());
    m_requiredFeatures.synchronize(contextElement, requiredFeaturesPropertyInfo()->attributeName, value);
}

void SVGTests::synchronizeRequiredExtensions(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_requiredExtensions.shouldSynchronize)
        return;
    AtomicString value(m_requiredExtensions.value.valueAsString());
    m_requiredExtensions.synchronize(contextElement, requiredExtensionsPropertyInfo()->attributeName, value);
}

void SVGTests::synchronizeSystemLanguage(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_systemLanguage.shouldSynchronize)
        return;
    AtomicString value(m_systemLanguage.value.valueAsString());
    m_systemLanguage.synchronize(contextElement, systemLanguagePropertyInfo()->attributeName, value);
}

SVGStringList& SVGTests::requiredFeatures()
{
    m_requiredFeatures.shouldSynchronize = true;
    return m_requiredFeatures.value;
}

SVGStringList& SVGTests::requiredExtensions()
{
    m_requiredExtensions.shouldSynchronize = true;
    return m_requiredExtensions.value;
}

SVGStringList& SVGTests::systemLanguage()
{
    m_systemLanguage.shouldSynchronize = true;
    return m_systemLanguage.value;
}

}
<commit_msg>SVGTests should lazyAttach<commit_after>/*
 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"

#include "core/svg/SVGTests.h"

#include "SVGNames.h"
#include "core/dom/Attribute.h"
#include "core/dom/DOMImplementation.h"
#include "core/platform/Language.h"
#include "core/svg/SVGElement.h"
#include "core/svg/SVGStringList.h"

namespace WebCore {

// Define custom non-animated property 'requiredFeatures'.
const SVGPropertyInfo* SVGTests::requiredFeaturesPropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::requiredFeaturesAttr,
                                             SVGNames::requiredFeaturesAttr.localName(),
                                             &SVGElement::synchronizeRequiredFeatures,
                                             0);
    }
    return s_propertyInfo;
}

// Define custom non-animated property 'requiredExtensions'.
const SVGPropertyInfo* SVGTests::requiredExtensionsPropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::requiredExtensionsAttr,
                                             SVGNames::requiredExtensionsAttr.localName(),
                                             &SVGElement::synchronizeRequiredExtensions,
                                             0);
    }
    return s_propertyInfo;
}

// Define custom non-animated property 'systemLanguage'.
const SVGPropertyInfo* SVGTests::systemLanguagePropertyInfo()
{
    static const SVGPropertyInfo* s_propertyInfo = 0;
    if (!s_propertyInfo) {
        s_propertyInfo = new SVGPropertyInfo(AnimatedUnknown,
                                             PropertyIsReadWrite,
                                             SVGNames::systemLanguageAttr,
                                             SVGNames::systemLanguageAttr.localName(),
                                             &SVGElement::synchronizeSystemLanguage,
                                             0);
    }
    return s_propertyInfo;
}

SVGTests::SVGTests()
    : m_requiredFeatures(SVGNames::requiredFeaturesAttr)
    , m_requiredExtensions(SVGNames::requiredExtensionsAttr)
    , m_systemLanguage(SVGNames::systemLanguageAttr)
{
}

SVGAttributeToPropertyMap& SVGTests::attributeToPropertyMap()
{
    DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, map, ());
    if (!map.isEmpty())
        return map;
    map.addProperty(requiredFeaturesPropertyInfo());
    map.addProperty(requiredExtensionsPropertyInfo());
    map.addProperty(systemLanguagePropertyInfo());
    return map;
}

bool SVGTests::hasExtension(const String&) const
{
    // FIXME: Implement me!
    return false;
}

bool SVGTests::isValid() const
{
    unsigned featuresSize = m_requiredFeatures.value.size();
    for (unsigned i = 0; i < featuresSize; ++i) {
        String value = m_requiredFeatures.value.at(i);
        if (value.isEmpty() || !DOMImplementation::hasFeature(value, String()))
            return false;
    }

    unsigned systemLanguageSize = m_systemLanguage.value.size();
    for (unsigned i = 0; i < systemLanguageSize; ++i) {
        String value = m_systemLanguage.value.at(i);
        if (value != defaultLanguage().substring(0, 2))
            return false;
    }

    if (!m_requiredExtensions.value.isEmpty())
        return false;

    return true;
}

bool SVGTests::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (name == SVGNames::requiredFeaturesAttr) {
        m_requiredFeatures.value.reset(value);
        return true;
    }
    if (name == SVGNames::requiredExtensionsAttr) {
        m_requiredExtensions.value.reset(value);
        return true;
    }
    if (name == SVGNames::systemLanguageAttr) {
        m_systemLanguage.value.reset(value);
        return true;
    }

    return false;
}

bool SVGTests::isKnownAttribute(const QualifiedName& attrName)
{
    return attrName == SVGNames::requiredFeaturesAttr
        || attrName == SVGNames::requiredExtensionsAttr
        || attrName == SVGNames::systemLanguageAttr;
}

bool SVGTests::handleAttributeChange(SVGElement* targetElement, const QualifiedName& attrName)
{
    ASSERT(targetElement);
    if (!isKnownAttribute(attrName))
        return false;
    if (!targetElement->inDocument())
        return true;

    bool valid = targetElement->isValid();
    if (valid && !targetElement->attached())
        targetElement->lazyAttach();
    else if (!valid && targetElement->attached())
        targetElement->detach();

    return true;
}

void SVGTests::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes)
{
    supportedAttributes.add(SVGNames::requiredFeaturesAttr);
    supportedAttributes.add(SVGNames::requiredExtensionsAttr);
    supportedAttributes.add(SVGNames::systemLanguageAttr);
}

void SVGTests::synchronizeRequiredFeatures(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_requiredFeatures.shouldSynchronize)
        return;
    AtomicString value(m_requiredFeatures.value.valueAsString());
    m_requiredFeatures.synchronize(contextElement, requiredFeaturesPropertyInfo()->attributeName, value);
}

void SVGTests::synchronizeRequiredExtensions(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_requiredExtensions.shouldSynchronize)
        return;
    AtomicString value(m_requiredExtensions.value.valueAsString());
    m_requiredExtensions.synchronize(contextElement, requiredExtensionsPropertyInfo()->attributeName, value);
}

void SVGTests::synchronizeSystemLanguage(SVGElement* contextElement)
{
    ASSERT(contextElement);
    if (!m_systemLanguage.shouldSynchronize)
        return;
    AtomicString value(m_systemLanguage.value.valueAsString());
    m_systemLanguage.synchronize(contextElement, systemLanguagePropertyInfo()->attributeName, value);
}

SVGStringList& SVGTests::requiredFeatures()
{
    m_requiredFeatures.shouldSynchronize = true;
    return m_requiredFeatures.value;
}

SVGStringList& SVGTests::requiredExtensions()
{
    m_requiredExtensions.shouldSynchronize = true;
    return m_requiredExtensions.value;
}

SVGStringList& SVGTests::systemLanguage()
{
    m_systemLanguage.shouldSynchronize = true;
    return m_systemLanguage.value;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Vsevolod Stakhov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *	 * Redistributions of source code must retain the above copyright
 *	   notice, this list of conditions and the following disclaimer.
 *	 * Redistributions in binary form must reproduce the above copyright
 *	   notice, this list of conditions and the following disclaimer in the
 *	   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "printf_check.h"
#include "clang/AST/AST.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include <unordered_map>
#include <vector>
#include <sstream>
#include <ctype.h>

using namespace clang;

namespace rspamd {
	struct PrintfArgChecker;

	static bool cstring_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool int_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);

	using arg_parser_t = bool (*) (const Expr *, struct PrintfArgChecker *);

	static void
	print_error (const std::string &err, const Expr *e, const ASTContext *ast)
	{
		auto const &sm = ast->getSourceManager ();
		auto loc = e->getExprLoc ();
		llvm::errs() << err << " at " << loc.printToString (sm) << "\n";
	}

	struct PrintfArgChecker {
	private:
		arg_parser_t parser;
	public:
		int width;
		int precision;
		ASTContext *past;

		PrintfArgChecker (arg_parser_t _p, ASTContext *_ast) :
				parser(_p), past(_ast) {}
		virtual ~PrintfArgChecker () {}

		bool operator () (const Expr *e)
		{
			return parser (e, this);
		}
	};

	class PrintfCheckVisitor::impl {
		std::unordered_map<std::string, int> printf_functions;
		ASTContext *pcontext;

		std::unique_ptr<PrintfArgChecker> parseFlags (const std::string &flags)
		{
			auto type = flags.back();

			switch (type) {
			case 's':
				return llvm::make_unique<PrintfArgChecker>(cstring_arg_handler,
						this->pcontext);
			case 'd':
				return llvm::make_unique<PrintfArgChecker>(int_arg_handler,
						this->pcontext);
			default:
				llvm::errs () << "unknown parser flag: " << type << "\n";
				break;
			}

			return nullptr;
		}

		std::shared_ptr<std::vector<PrintfArgChecker> >
		genParsers (const StringRef query)
		{
			enum {
				ignore_chars = 0,
				read_percent,
				read_width,
				read_precision,
				read_arg
			} state = ignore_chars;
			int width, precision;
			std::string flags;

			auto res = std::make_shared<std::vector<PrintfArgChecker> >();

			for (const auto c : query) {
				switch (state) {
				case ignore_chars:
					if (c == '%') {
						state = read_percent;
						flags.clear ();
						width = precision = 0;
					}
					break;
				case read_percent:
					if (isdigit (c)) {
						state = read_width;
						width = c - '0';
					}
					else if (c == '.') {
						state = read_precision;
						precision = c - '0';
					}
					else if (c == '*') {
						/* %*s - need integer argument */
						res->emplace_back (int_arg_handler, this->pcontext);
						state = read_arg;
					}
					else if (c == '%') {
						/* Percent character, ignore */
						state = ignore_chars;
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_width:
					if (isdigit (c)) {
						width *= 10;
						width += c - '0';
					}
					else if (c == '.') {
						state = read_precision;
						precision = c - '0';
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_precision:
					if (isdigit (c)) {
						precision *= 10;
						precision += c - '0';
					}
					else if (c == '*') {
						res->emplace_back (int_arg_handler, this->pcontext);
						state = read_arg;
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_arg:
					if (!isalpha (c)) {
						auto handler = parseFlags (flags);

						if (handler) {
							auto handler_copy = *handler;
							handler_copy.precision = precision;
							handler_copy.width = width;
							res->emplace_back (std::move (handler_copy));
						}
						else {
							llvm::errs () << "invalid modifier\n";
							return nullptr;
						}
						state = ignore_chars;
					}
					else {
						flags.push_back (c);
					}
					break;
				}
			}

			if (state == read_arg) {
				auto handler = parseFlags (flags);

				if (handler) {
					auto handler_copy = *handler;
					handler_copy.precision = precision;
					handler_copy.width = width;
					res->emplace_back (std::move (handler_copy));
				}
				else {
					llvm::errs () << "invalid modifier\n";
					return nullptr;
				}
			}

			return res;
		}
	public:
		impl (ASTContext *_ctx) : pcontext(_ctx)
		{
			/* name -> format string position */
			printf_functions = {
					{"rspamd_printf",               0},
					{"rspamd_default_log_function", 4},
					{"rspamd_snprintf",             2},
					{"rspamd_fprintf",              1}
			};
		};

		bool VisitCallExpr (CallExpr *E)
		{
			auto callee = dyn_cast<NamedDecl> (E->getCalleeDecl ());
			if (callee == NULL) {
				llvm::errs () << "Bad callee\n";
				return false;
			}

			auto fname = callee->getNameAsString ();

			auto pos_it = printf_functions.find (fname);

			if (pos_it != printf_functions.end ()) {
				const auto args = E->getArgs ();
				auto pos = pos_it->second;
				auto query = args[pos];

				if (!query->isEvaluatable (*pcontext)) {
					llvm::errs () << "Cannot evaluate query\n";
					return false;
				}

				clang::Expr::EvalResult r;

				if (!query->EvaluateAsRValue (r, *pcontext)) {
					llvm::errs () << "Cannot evaluate query\n";
					return false;
				}

				auto qval = dyn_cast<StringLiteral> (
						r.Val.getLValueBase ().get<const Expr *> ());
				if (!qval) {
					llvm::errs () << "Bad or absent query string\n";
					return false;
				}

				auto parsers = genParsers (qval->getString ());

				if (parsers) {
					if (parsers->size () != E->getNumArgs () - (pos + 1)) {
						std::ostringstream err_buf;
						err_buf << "number of arguments for " << fname
								<< " missmatches query string '" <<
								qval->getString().str()
								<< "', expected " << parsers->size () << " args"
								<< ", got " << (E->getNumArgs () - (pos + 1))
								<< " args";
						print_error (err_buf.str (), E, this->pcontext);

						return false;
					}
					else {
						for (auto i = pos + 1; i < E->getNumArgs (); i++) {
							auto arg = args[i];

							if (arg) {
								if (!parsers->at(i - (pos + 1))(arg)) {
									return false;
								}
							}
						}
					}
				}
			}

			return true;
		}
	};

	PrintfCheckVisitor::PrintfCheckVisitor (ASTContext *ctx) :
		pimpl { new impl(ctx) }
	{
	}

	PrintfCheckVisitor::~PrintfCheckVisitor ()
	{
	}

	bool PrintfCheckVisitor::VisitCallExpr (clang::CallExpr *E)
	{
		return pimpl->VisitCallExpr (E);
	}

	/* Type handlers */
	static bool
	cstring_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		if (!type->isPointerType ()) {
			print_error (
					std::string ("bad string argument for %s: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto ptr_type = type->getPointeeType().split().Ty;

		if (!ptr_type->isCharType ()) {
			/* We might have gchar * here */
			auto desugared_type = ptr_type->getUnqualifiedDesugaredType ();

			if (!desugared_type || !desugared_type->isCharType ()) {
				if (desugared_type) {
					desugared_type->dump ();
				}
				print_error (
						std::string ("bad string argument for %s: ") +
								arg->getType ().getAsString (), arg, ctx->past);
				return false;
			}
		}

		return true;
	}

	static bool
	int_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isIntegerType ()) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
					arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
							arg->getType ().getAsString(), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType>(desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::UInt &&
				kind != BuiltinType::Kind::Int) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
					arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}
};
<commit_msg>More primitive types parsers<commit_after>/*
 * Copyright (c) 2015, Vsevolod Stakhov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *	 * Redistributions of source code must retain the above copyright
 *	   notice, this list of conditions and the following disclaimer.
 *	 * Redistributions in binary form must reproduce the above copyright
 *	   notice, this list of conditions and the following disclaimer in the
 *	   documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "printf_check.h"
#include "clang/AST/AST.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include <unordered_map>
#include <vector>
#include <sstream>
#include <ctype.h>

using namespace clang;

namespace rspamd {
	struct PrintfArgChecker;

	static bool cstring_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool int_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool long_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool size_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool char_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool double_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);
	static bool long_double_arg_handler (const Expr *arg,
			struct PrintfArgChecker *ctx);

	using arg_parser_t = bool (*) (const Expr *, struct PrintfArgChecker *);

	static void
	print_error (const std::string &err, const Expr *e, const ASTContext *ast)
	{
		auto const &sm = ast->getSourceManager ();
		auto loc = e->getExprLoc ();
		llvm::errs() << err << " at " << loc.printToString (sm) << "\n";
	}

	struct PrintfArgChecker {
	private:
		arg_parser_t parser;
	public:
		int width;
		int precision;
		bool is_unsigned;
		ASTContext *past;

		PrintfArgChecker (arg_parser_t _p, ASTContext *_ast) :
				parser(_p), past(_ast)
		{
			width = 0;
			precision = 0;
			is_unsigned = false;
		}
		virtual ~PrintfArgChecker () {}

		bool operator () (const Expr *e)
		{
			return parser (e, this);
		}
	};

	class PrintfCheckVisitor::impl {
		std::unordered_map<std::string, int> printf_functions;
		ASTContext *pcontext;

		std::unique_ptr<PrintfArgChecker> parseFlags (const std::string &flags)
		{
			auto type = flags.back();

			switch (type) {
			case 's':
				return llvm::make_unique<PrintfArgChecker>(cstring_arg_handler,
						this->pcontext);
			case 'd':
				return llvm::make_unique<PrintfArgChecker>(int_arg_handler,
						this->pcontext);
			case 'z':
				return llvm::make_unique<PrintfArgChecker> (size_arg_handler,
						this->pcontext);
			case 'l':
				return llvm::make_unique<PrintfArgChecker> (long_arg_handler,
						this->pcontext);
			case 'f':
			case 'g':
				return llvm::make_unique<PrintfArgChecker> (double_arg_handler,
						this->pcontext);
			case 'F':
			case 'G':
				return llvm::make_unique<PrintfArgChecker> (long_double_arg_handler,
						this->pcontext);
			case 'c':
				return llvm::make_unique<PrintfArgChecker> (char_arg_handler,
						this->pcontext);
			default:
				llvm::errs () << "unknown parser flag: " << type << "\n";
				break;
			}

			return nullptr;
		}

		std::shared_ptr<std::vector<PrintfArgChecker> >
		genParsers (const StringRef query)
		{
			enum {
				ignore_chars = 0,
				read_percent,
				read_width,
				read_precision,
				read_arg
			} state = ignore_chars;
			int width, precision;
			std::string flags;

			auto res = std::make_shared<std::vector<PrintfArgChecker> >();

			for (const auto c : query) {
				switch (state) {
				case ignore_chars:
					if (c == '%') {
						state = read_percent;
						flags.clear ();
						width = precision = 0;
					}
					break;
				case read_percent:
					if (isdigit (c)) {
						state = read_width;
						width = c - '0';
					}
					else if (c == '.') {
						state = read_precision;
						precision = c - '0';
					}
					else if (c == '*') {
						/* %*s - need integer argument */
						res->emplace_back (int_arg_handler, this->pcontext);
						state = read_arg;
					}
					else if (c == '%') {
						/* Percent character, ignore */
						state = ignore_chars;
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_width:
					if (isdigit (c)) {
						width *= 10;
						width += c - '0';
					}
					else if (c == '.') {
						state = read_precision;
						precision = c - '0';
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_precision:
					if (isdigit (c)) {
						precision *= 10;
						precision += c - '0';
					}
					else if (c == '*') {
						res->emplace_back (int_arg_handler, this->pcontext);
						state = read_arg;
					}
					else {
						flags.push_back (c);
						state = read_arg;
					}
					break;
				case read_arg:
					if (!isalpha (c)) {
						auto handler = parseFlags (flags);

						if (handler) {
							auto handler_copy = *handler;
							handler_copy.precision = precision;
							handler_copy.width = width;
							res->emplace_back (std::move (handler_copy));
						}
						else {
							llvm::errs () << "invalid modifier\n";
							return nullptr;
						}
						state = ignore_chars;
					}
					else {
						flags.push_back (c);
					}
					break;
				}
			}

			if (state == read_arg) {
				auto handler = parseFlags (flags);

				if (handler) {
					auto handler_copy = *handler;
					handler_copy.precision = precision;
					handler_copy.width = width;
					res->emplace_back (std::move (handler_copy));
				}
				else {
					llvm::errs () << "invalid modifier\n";
					return nullptr;
				}
			}

			return res;
		}
	public:
		impl (ASTContext *_ctx) : pcontext(_ctx)
		{
			/* name -> format string position */
			printf_functions = {
					{"rspamd_printf",               0},
					{"rspamd_default_log_function", 4},
					{"rspamd_snprintf",             2},
					{"rspamd_fprintf",              1}
			};
		};

		bool VisitCallExpr (CallExpr *E)
		{
			auto callee = dyn_cast<NamedDecl> (E->getCalleeDecl ());
			if (callee == NULL) {
				llvm::errs () << "Bad callee\n";
				return false;
			}

			auto fname = callee->getNameAsString ();

			auto pos_it = printf_functions.find (fname);

			if (pos_it != printf_functions.end ()) {
				const auto args = E->getArgs ();
				auto pos = pos_it->second;
				auto query = args[pos];

				if (!query->isEvaluatable (*pcontext)) {
					llvm::errs () << "Cannot evaluate query\n";
					return false;
				}

				clang::Expr::EvalResult r;

				if (!query->EvaluateAsRValue (r, *pcontext)) {
					llvm::errs () << "Cannot evaluate query\n";
					return false;
				}

				auto qval = dyn_cast<StringLiteral> (
						r.Val.getLValueBase ().get<const Expr *> ());
				if (!qval) {
					llvm::errs () << "Bad or absent query string\n";
					return false;
				}

				auto parsers = genParsers (qval->getString ());

				if (parsers) {
					if (parsers->size () != E->getNumArgs () - (pos + 1)) {
						std::ostringstream err_buf;
						err_buf << "number of arguments for " << fname
								<< " missmatches query string '" <<
								qval->getString().str()
								<< "', expected " << parsers->size () << " args"
								<< ", got " << (E->getNumArgs () - (pos + 1))
								<< " args";
						print_error (err_buf.str (), E, this->pcontext);

						return false;
					}
					else {
						for (auto i = pos + 1; i < E->getNumArgs (); i++) {
							auto arg = args[i];

							if (arg) {
								if (!parsers->at(i - (pos + 1))(arg)) {
									return false;
								}
							}
						}
					}
				}
			}

			return true;
		}
	};

	PrintfCheckVisitor::PrintfCheckVisitor (ASTContext *ctx) :
		pimpl { new impl(ctx) }
	{
	}

	PrintfCheckVisitor::~PrintfCheckVisitor ()
	{
	}

	bool PrintfCheckVisitor::VisitCallExpr (clang::CallExpr *E)
	{
		return pimpl->VisitCallExpr (E);
	}

	/* Type handlers */
	static bool
	cstring_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		if (!type->isPointerType ()) {
			print_error (
					std::string ("bad string argument for %s: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto ptr_type = type->getPointeeType().split().Ty;

		if (!ptr_type->isCharType ()) {
			/* We might have gchar * here */
			auto desugared_type = ptr_type->getUnqualifiedDesugaredType ();

			if (!desugared_type || !desugared_type->isCharType ()) {
				if (desugared_type) {
					desugared_type->dump ();
				}
				print_error (
						std::string ("bad string argument for %s: ") +
								arg->getType ().getAsString (), arg, ctx->past);
				return false;
			}
		}

		return true;
	}

	static bool
	int_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isIntegerType ()) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
					arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
							arg->getType ().getAsString(), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType>(desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::UInt &&
				kind != BuiltinType::Kind::Int) {
			print_error (std::string ("bad integer argument for %d or * arg: ") +
					arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}

	static bool
	long_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isIntegerType ()) {
			print_error (
					std::string ("bad integer argument for %l arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (
					std::string ("bad integer argument for %l arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType> (desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::ULong &&
				kind != BuiltinType::Kind::Long) {
			print_error (
					std::string ("bad integer argument for %l arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}

	static bool
	char_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isCharType ()) {
			print_error (
					std::string ("bad char argument for %c arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (
					std::string ("bad char argument for %c arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType> (desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::UChar &&
				kind != BuiltinType::Kind::SChar) {
			print_error (
					std::string ("bad char argument for %c arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}

	static bool
	size_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isIntegerType ()) {
			print_error (
					std::string ("bad integer argument for %z arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (
					std::string ("bad integer argument for %z arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType> (desugared_type);
		auto kind = builtin_type->getKind ();

		if (sizeof (size_t) == sizeof (long)) {
			if (kind != BuiltinType::Kind::ULong &&
					kind != BuiltinType::Kind::Long) {
				print_error (
						std::string ("bad integer argument for %z arg: ") +
								arg->getType ().getAsString (), arg, ctx->past);
				return false;
			}
		}
		else if (sizeof (size_t) == sizeof (int)) {
			if (kind != BuiltinType::Kind::UInt &&
					kind != BuiltinType::Kind::Int) {
				print_error (
						std::string ("bad integer argument for %z arg: ") +
								arg->getType ().getAsString (), arg, ctx->past);
				return false;
			}
		}

		return true;
	}

	static bool
	double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isRealFloatingType ()) {
			print_error (
					std::string ("bad double argument for %f or %g arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (
					std::string ("bad double argument for %f or %g arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType> (desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::Double) {
			print_error (
					std::string ("bad double argument for %f or %g arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}

	static bool
	long_double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx)
	{
		auto type = arg->getType ().split ().Ty;

		auto desugared_type = type->getUnqualifiedDesugaredType ();

		if (!desugared_type->isRealFloatingType ()) {
			print_error (
					std::string ("bad long double argument for %F or %G arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}
		else if (!desugared_type->isBuiltinType ()) {
			print_error (
					std::string ("bad long double argument for %F or %G arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		auto builtin_type = dyn_cast<BuiltinType> (desugared_type);
		auto kind = builtin_type->getKind ();

		if (kind != BuiltinType::Kind::LongDouble) {
			print_error (
					std::string ("bad long double argument for %F or %G arg: ") +
							arg->getType ().getAsString (), arg, ctx->past);
			return false;
		}

		return true;
	}
};
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scopeguard.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:38:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#if ! defined(INCLUDED_COMPHELPER_SCOPEGUARD_HXX)
#define INCLUDED_COMPHELPER_SCOPEGUARD_HXX

#if ! defined(INCLUDED_COMPHELPERDLLAPI_H)
#include "comphelper/comphelperdllapi.h"
#endif
#include "boost/function.hpp"
#include "boost/noncopyable.hpp"

namespace comphelper {

/** ScopeGuard to ease writing exception-safe code.
 */
class COMPHELPER_DLLPUBLIC ScopeGuard : private ::boost::noncopyable
                                        // noncopyable until we have
                                        // good reasons...
{
public:
    enum exc_handling { IGNORE_EXCEPTIONS, ALLOW_EXCEPTIONS };

    /** @param func function object to be executed in dtor
        @param excHandling switches whether thrown exceptions in dtor will be
                           silently ignored (but OSL_ asserted)
    */
    template <typename func_type>
    explicit ScopeGuard( func_type const & func,
                         exc_handling excHandling = IGNORE_EXCEPTIONS )
        : m_func( func ), m_excHandling( excHandling ) {}

    ~ScopeGuard();

    /** Dismisses the scope guard, i.e. the function won't
        be executed.
    */
    void dismiss();

private:
    ::boost::function0<void> m_func; // preferring portable syntax
    exc_handling const m_excHandling;
};

} // namespace comphelper

#endif // ! defined(INCLUDED_COMPHELPER_SCOPEGUARD_HXX)

<commit_msg>INTEGRATION: CWS changefileheader (1.5.246); FILE MERGED 2008/03/31 12:19:29 rt 1.5.246.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: scopeguard.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if ! defined(INCLUDED_COMPHELPER_SCOPEGUARD_HXX)
#define INCLUDED_COMPHELPER_SCOPEGUARD_HXX

#if ! defined(INCLUDED_COMPHELPERDLLAPI_H)
#include "comphelper/comphelperdllapi.h"
#endif
#include "boost/function.hpp"
#include "boost/noncopyable.hpp"

namespace comphelper {

/** ScopeGuard to ease writing exception-safe code.
 */
class COMPHELPER_DLLPUBLIC ScopeGuard : private ::boost::noncopyable
                                        // noncopyable until we have
                                        // good reasons...
{
public:
    enum exc_handling { IGNORE_EXCEPTIONS, ALLOW_EXCEPTIONS };

    /** @param func function object to be executed in dtor
        @param excHandling switches whether thrown exceptions in dtor will be
                           silently ignored (but OSL_ asserted)
    */
    template <typename func_type>
    explicit ScopeGuard( func_type const & func,
                         exc_handling excHandling = IGNORE_EXCEPTIONS )
        : m_func( func ), m_excHandling( excHandling ) {}

    ~ScopeGuard();

    /** Dismisses the scope guard, i.e. the function won't
        be executed.
    */
    void dismiss();

private:
    ::boost::function0<void> m_func; // preferring portable syntax
    exc_handling const m_excHandling;
};

} // namespace comphelper

#endif // ! defined(INCLUDED_COMPHELPER_SCOPEGUARD_HXX)

<|endoftext|>