<commit_before>//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass uses the top-down data structure graphs to implement a simple
// context sensitive alias analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/DataStructure/DataStructure.h"
#include "llvm/Analysis/DataStructure/DSGraph.h"
using namespace llvm;

namespace {
  class DSAA : public ModulePass, public AliasAnalysis {
    TDDataStructures *TD;
    BUDataStructures *BU;
  public:
    DSAA() : TD(0) {}

    //------------------------------------------------
    // Implement the Pass API
    //

    // run - Build up the result graph, representing the pointer graph for the
    // program.
    //
    bool runOnModule(Module &M) {
      InitializeAliasAnalysis(this);
      TD = &getAnalysis<TDDataStructures>();
      BU = &getAnalysis<BUDataStructures>();
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.setPreservesAll();                         // Does not transform code
      AU.addRequiredTransitive<TDDataStructures>(); // Uses TD Datastructures
      AU.addRequiredTransitive<BUDataStructures>(); // Uses BU Datastructures
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //

    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);

    void getMustAliases(Value *P, std::vector<Value*> &RetVals);

    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
      return AliasAnalysis::getModRefInfo(CS1,CS2);
    }

    virtual void deleteValue(Value *V) {
      BU->deleteValue(V);
      TD->deleteValue(V);
    }

    virtual void copyValue(Value *From, Value *To) {
      if (From == To) return;
      BU->copyValue(From, To);
      TD->copyValue(From, To);
    }

  private:
    DSGraph *getGraphForValue(const Value *V);
  };

  // Register the pass...
  RegisterOpt<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");

  // Register as an implementation of AliasAnalysis
  RegisterAnalysisGroup<AliasAnalysis, DSAA> Y;
}

ModulePass *llvm::createDSAAPass() { return new DSAA(); }

// getGraphForValue - Return the DSGraph to use for queries about the specified
// value...
//
DSGraph *DSAA::getGraphForValue(const Value *V) {
  if (const Instruction *I = dyn_cast<Instruction>(V))
    return &TD->getDSGraph(*I->getParent()->getParent());
  else if (const Argument *A = dyn_cast<Argument>(V))
    return &TD->getDSGraph(*A->getParent());
  else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
    return &TD->getDSGraph(*BB->getParent());
  return 0;
}

#if 0
// isSinglePhysicalObject - For now, the only case that we know that there is
// only one memory object in the node is when there is a single global in the
// node, and the only composition bit set is Global.
//
static bool isSinglePhysicalObject(DSNode *N) {
  assert(N->isComplete() && "Can only tell if this is a complete object!");
  return N->isGlobalNode() && N->getGlobals().size() == 1 &&
         !N->isHeapNode() && !N->isAllocaNode() && !N->isUnknownNode();
}
#endif

// alias - This is the only method here that does anything interesting...
AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
                                       const Value *V2, unsigned V2Size) {
  if (V1 == V2) return MustAlias;

  DSGraph *G1 = getGraphForValue(V1);
  DSGraph *G2 = getGraphForValue(V2);
  assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");

  // Get the graph to use...
  DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));

  const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
  DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
  if (I == GSM.end()) return NoAlias;

  DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
  if (J == GSM.end()) return NoAlias;

  DSNode  *N1 = I->second.getNode(),  *N2 = J->second.getNode();
  unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
  if (N1 == 0 || N2 == 0)
    return MayAlias;  // Can't tell whether anything aliases null.

  // We can only make a judgment of one of the nodes is complete...
  if (N1->isComplete() || N2->isComplete()) {
    if (N1 != N2)
      return NoAlias;   // Completely different nodes.

#if 0  // This does not correctly handle arrays!
    // Both point to the same node and same offset, and there is only one
    // physical memory object represented in the node, return must alias.
    //
    // FIXME: This isn't correct because we do not handle array indexing
    // correctly.

    if (O1 == O2 && isSinglePhysicalObject(N1))
      return MustAlias; // Exactly the same object & offset
#endif

    // See if they point to different offsets...  if so, we may be able to
    // determine that they do not alias...
    if (O1 != O2) {
      if (O2 < O1) {    // Ensure that O1 <= O2
        std::swap(V1, V2);
        std::swap(O1, O2);
        std::swap(V1Size, V2Size);
      }

      if (O1+V1Size <= O2)
        return NoAlias;
    }
  }

  // FIXME: we could improve on this by checking the globals graph for aliased
  // global queries...
  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

/// getModRefInfo - does a callsite modify or reference a value?
///
AliasAnalysis::ModRefResult
DSAA::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  AliasAnalysis::ModRefResult Result =AliasAnalysis::getModRefInfo(CS, P, Size);
  Function *F = CS.getCalledFunction();

  if (!F || Result == NoModRef)
    return Result;

  if (F->isExternal()) {
    // If we are calling an external function, and if this global doesn't escape
    // the portion of the program we have analyzed, we can draw conclusions
    // based on whether the global escapes the program.
    Function *Caller = CS.getInstruction()->getParent()->getParent();
    DSGraph *G = &TD->getDSGraph(*Caller);
    DSScalarMap::iterator NI = G->getScalarMap().find(P);
    if (NI == G->getScalarMap().end()) {
      // If it wasn't in the local function graph, check the global graph.  This
      // can occur for globals who are locally reference but hoisted out to the
      // globals graph despite that.
      G = G->getGlobalsGraph();
      NI = G->getScalarMap().find(P);
      if (NI == G->getScalarMap().end())
        return Result;
    }

    // If we found a node and it's complete, it cannot be passed out to the
    // called function.
    if (NI->second.getNode()->isComplete())
      return NoModRef;
    return Result;
  }

  // Get the graphs for the callee and caller.  Note that we want the BU graph
  // for the callee because we don't want all caller's effects incorporated!
  const Function *Caller = CS.getInstruction()->getParent()->getParent();
  DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
  DSGraph &CalleeBUGraph = BU->getDSGraph(*F);

  // Figure out which node in the TD graph this pointer corresponds to.
  DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
  DSScalarMap::iterator NI = CallerSM.find(P);
  if (NI == CallerSM.end()) {
    if (isa<ConstantPointerNull>(P) || isa<UndefValue>(P))
      Result = NoModRef;                 // null is never modified :)
    else {
      assert(isa<GlobalVariable>(P) &&
    cast<GlobalVariable>(P)->getType()->getElementType()->isFirstClassType() &&
             "This isn't a global that DSA inconsiderately dropped "
             "from the graph?");
    }
    return Result;
  }

  const DSNode *N = NI->second.getNode();
  assert(N && "Null pointer in scalar map??");

  // Compute the mapping from nodes in the callee graph to the nodes in the
  // caller graph for this call site.
  DSGraph::NodeMapTy CalleeCallerMap;
  DSCallSite DSCS = CallerTDGraph.getDSCallSiteForCallSite(CS);
  CallerTDGraph.computeCalleeCallerMapping(DSCS, *F, CalleeBUGraph,
                                           CalleeCallerMap);

  // Loop over all of the nodes in the callee that correspond to "N", keeping
  // track of aggregate mod/ref info.
  bool NeverReads = true, NeverWrites = true;
  for (DSGraph::NodeMapTy::iterator I = CalleeCallerMap.begin(),
         E = CalleeCallerMap.end(); I != E; ++I)
    if (I->second.getNode() == N) {
      if (I->first->isModified())
        NeverWrites = false;
      if (I->first->isRead())
        NeverReads = false;
      if (NeverReads == false && NeverWrites == false)
        return Result;
    }

  if (NeverWrites)      // We proved it was not modified.
    Result = ModRefResult(Result & ~Mod);
  if (NeverReads)       // We proved it was not read.
    Result = ModRefResult(Result & ~Ref);

  return Result;
}

/// getMustAliases - If there are any pointers known that must alias this
/// pointer, return them now.  This allows alias-set based alias analyses to
/// perform a form a value numbering (which is exposed by load-vn).  If an alias
/// analysis supports this, it should ADD any must aliased pointers to the
/// specified vector.
///
void DSAA::getMustAliases(Value *P, std::vector<Value*> &RetVals) {
#if 0    // This does not correctly handle arrays!
  // Currently the only must alias information we can provide is to say that
  // something is equal to a global value. If we already have a global value,
  // don't get worked up about it.
  if (!isa<GlobalValue>(P)) {
    DSGraph *G = getGraphForValue(P);
    if (!G) G = &TD->getGlobalsGraph();

    // The only must alias information we can currently determine occurs when
    // the node for P is a global node with only one entry.
    DSGraph::ScalarMapTy::const_iterator I = G->getScalarMap().find(P);
    if (I != G->getScalarMap().end()) {
      DSNode *N = I->second.getNode();
      if (N->isComplete() && isSinglePhysicalObject(N))
        RetVals.push_back(N->getGlobals()[0]);
    }
  }
#endif
  return AliasAnalysis::getMustAliases(P, RetVals);
}

<commit_msg>slightly improve mod/ref for DSAA by checking the globals graph for fallback<commit_after>//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass uses the top-down data structure graphs to implement a simple
// context sensitive alias analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/DataStructure/DataStructure.h"
#include "llvm/Analysis/DataStructure/DSGraph.h"
using namespace llvm;

namespace {
  class DSAA : public ModulePass, public AliasAnalysis {
    TDDataStructures *TD;
    BUDataStructures *BU;
  public:
    DSAA() : TD(0) {}

    //------------------------------------------------
    // Implement the Pass API
    //

    // run - Build up the result graph, representing the pointer graph for the
    // program.
    //
    bool runOnModule(Module &M) {
      InitializeAliasAnalysis(this);
      TD = &getAnalysis<TDDataStructures>();
      BU = &getAnalysis<BUDataStructures>();
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.setPreservesAll();                         // Does not transform code
      AU.addRequiredTransitive<TDDataStructures>(); // Uses TD Datastructures
      AU.addRequiredTransitive<BUDataStructures>(); // Uses BU Datastructures
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //

    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);

    void getMustAliases(Value *P, std::vector<Value*> &RetVals);

    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
      return AliasAnalysis::getModRefInfo(CS1,CS2);
    }

    virtual void deleteValue(Value *V) {
      BU->deleteValue(V);
      TD->deleteValue(V);
    }

    virtual void copyValue(Value *From, Value *To) {
      if (From == To) return;
      BU->copyValue(From, To);
      TD->copyValue(From, To);
    }

  private:
    DSGraph *getGraphForValue(const Value *V);
  };

  // Register the pass...
  RegisterOpt<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");

  // Register as an implementation of AliasAnalysis
  RegisterAnalysisGroup<AliasAnalysis, DSAA> Y;
}

ModulePass *llvm::createDSAAPass() { return new DSAA(); }

// getGraphForValue - Return the DSGraph to use for queries about the specified
// value...
//
DSGraph *DSAA::getGraphForValue(const Value *V) {
  if (const Instruction *I = dyn_cast<Instruction>(V))
    return &TD->getDSGraph(*I->getParent()->getParent());
  else if (const Argument *A = dyn_cast<Argument>(V))
    return &TD->getDSGraph(*A->getParent());
  else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
    return &TD->getDSGraph(*BB->getParent());
  return 0;
}

#if 0
// isSinglePhysicalObject - For now, the only case that we know that there is
// only one memory object in the node is when there is a single global in the
// node, and the only composition bit set is Global.
//
static bool isSinglePhysicalObject(DSNode *N) {
  assert(N->isComplete() && "Can only tell if this is a complete object!");
  return N->isGlobalNode() && N->getGlobals().size() == 1 &&
         !N->isHeapNode() && !N->isAllocaNode() && !N->isUnknownNode();
}
#endif

// alias - This is the only method here that does anything interesting...
AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
                                       const Value *V2, unsigned V2Size) {
  if (V1 == V2) return MustAlias;

  DSGraph *G1 = getGraphForValue(V1);
  DSGraph *G2 = getGraphForValue(V2);
  assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");

  // Get the graph to use...
  DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));

  const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
  DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
  if (I == GSM.end()) return NoAlias;

  DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
  if (J == GSM.end()) return NoAlias;

  DSNode  *N1 = I->second.getNode(),  *N2 = J->second.getNode();
  unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
  if (N1 == 0 || N2 == 0)
    return MayAlias;  // Can't tell whether anything aliases null.

  // We can only make a judgment of one of the nodes is complete...
  if (N1->isComplete() || N2->isComplete()) {
    if (N1 != N2)
      return NoAlias;   // Completely different nodes.

#if 0  // This does not correctly handle arrays!
    // Both point to the same node and same offset, and there is only one
    // physical memory object represented in the node, return must alias.
    //
    // FIXME: This isn't correct because we do not handle array indexing
    // correctly.

    if (O1 == O2 && isSinglePhysicalObject(N1))
      return MustAlias; // Exactly the same object & offset
#endif

    // See if they point to different offsets...  if so, we may be able to
    // determine that they do not alias...
    if (O1 != O2) {
      if (O2 < O1) {    // Ensure that O1 <= O2
        std::swap(V1, V2);
        std::swap(O1, O2);
        std::swap(V1Size, V2Size);
      }

      if (O1+V1Size <= O2)
        return NoAlias;
    }
  }

  // FIXME: we could improve on this by checking the globals graph for aliased
  // global queries...
  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

/// getModRefInfo - does a callsite modify or reference a value?
///
AliasAnalysis::ModRefResult
DSAA::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  AliasAnalysis::ModRefResult Result =AliasAnalysis::getModRefInfo(CS, P, Size);
  Function *F = CS.getCalledFunction();

  if (!F || Result == NoModRef)
    return Result;

  if (F->isExternal()) {
    // If we are calling an external function, and if this global doesn't escape
    // the portion of the program we have analyzed, we can draw conclusions
    // based on whether the global escapes the program.
    Function *Caller = CS.getInstruction()->getParent()->getParent();
    DSGraph *G = &TD->getDSGraph(*Caller);
    DSScalarMap::iterator NI = G->getScalarMap().find(P);
    if (NI == G->getScalarMap().end()) {
      // If it wasn't in the local function graph, check the global graph.  This
      // can occur for globals who are locally reference but hoisted out to the
      // globals graph despite that.
      G = G->getGlobalsGraph();
      NI = G->getScalarMap().find(P);
      if (NI == G->getScalarMap().end())
        return Result;
    }

    // If we found a node and it's complete, it cannot be passed out to the
    // called function.
    if (NI->second.getNode()->isComplete())
      return NoModRef;
    return Result;
  }

  // Get the graphs for the callee and caller.  Note that we want the BU graph
  // for the callee because we don't want all caller's effects incorporated!
  const Function *Caller = CS.getInstruction()->getParent()->getParent();
  DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
  DSGraph &CalleeBUGraph = BU->getDSGraph(*F);

  // Figure out which node in the TD graph this pointer corresponds to.
  DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
  DSScalarMap::iterator NI = CallerSM.find(P);
  if (NI == CallerSM.end()) {
    if (isa<ConstantPointerNull>(P) || isa<UndefValue>(P))
      Result = NoModRef;                 // null is never modified :)
    else {
      assert(isa<GlobalVariable>(P) &&
    cast<GlobalVariable>(P)->getType()->getElementType()->isFirstClassType() &&
             "This isn't a global that DSA inconsiderately dropped "
             "from the graph?");

      DSGraph &GG = *CallerTDGraph.getGlobalsGraph();
      DSScalarMap::iterator NI = GG.getScalarMap().find(P);
      if (NI != GG.getScalarMap().end() && !NI->second.isNull()) {
        // Otherwise, if the node is only M or R, return this.  This can be
        // useful for globals that should be marked const but are not.
        DSNode *N = NI->second.getNode();
        if (!N->isModified())
          Result = (ModRefResult)(Result & ~Mod);
        if (!N->isRead())
          Result = (ModRefResult)(Result & ~Ref);
      }
    }
    return Result;
  }

  const DSNode *N = NI->second.getNode();
  assert(N && "Null pointer in scalar map??");

  // Compute the mapping from nodes in the callee graph to the nodes in the
  // caller graph for this call site.
  DSGraph::NodeMapTy CalleeCallerMap;
  DSCallSite DSCS = CallerTDGraph.getDSCallSiteForCallSite(CS);
  CallerTDGraph.computeCalleeCallerMapping(DSCS, *F, CalleeBUGraph,
                                           CalleeCallerMap);

  // Loop over all of the nodes in the callee that correspond to "N", keeping
  // track of aggregate mod/ref info.
  bool NeverReads = true, NeverWrites = true;
  for (DSGraph::NodeMapTy::iterator I = CalleeCallerMap.begin(),
         E = CalleeCallerMap.end(); I != E; ++I)
    if (I->second.getNode() == N) {
      if (I->first->isModified())
        NeverWrites = false;
      if (I->first->isRead())
        NeverReads = false;
      if (NeverReads == false && NeverWrites == false)
        return Result;
    }

  if (NeverWrites)      // We proved it was not modified.
    Result = ModRefResult(Result & ~Mod);
  if (NeverReads)       // We proved it was not read.
    Result = ModRefResult(Result & ~Ref);

  return Result;
}

/// getMustAliases - If there are any pointers known that must alias this
/// pointer, return them now.  This allows alias-set based alias analyses to
/// perform a form a value numbering (which is exposed by load-vn).  If an alias
/// analysis supports this, it should ADD any must aliased pointers to the
/// specified vector.
///
void DSAA::getMustAliases(Value *P, std::vector<Value*> &RetVals) {
#if 0    // This does not correctly handle arrays!
  // Currently the only must alias information we can provide is to say that
  // something is equal to a global value. If we already have a global value,
  // don't get worked up about it.
  if (!isa<GlobalValue>(P)) {
    DSGraph *G = getGraphForValue(P);
    if (!G) G = &TD->getGlobalsGraph();

    // The only must alias information we can currently determine occurs when
    // the node for P is a global node with only one entry.
    DSGraph::ScalarMapTy::const_iterator I = G->getScalarMap().find(P);
    if (I != G->getScalarMap().end()) {
      DSNode *N = I->second.getNode();
      if (N->isComplete() && isSinglePhysicalObject(N))
        RetVals.push_back(N->getGlobals()[0]);
    }
  }
#endif
  return AliasAnalysis::getMustAliases(P, RetVals);
}

<|endoftext|>


<commit_before>// Test that we do not poison the array cookie if the operator new is defined
// inside the class.
// RUN: %clangxx_asan  %s -o %t && %run %t
//
// XFAIL: android
// XFAIL: armv7l-unknown-linux-gnueabihf
#include <new>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
struct Foo {
  void *operator new(size_t s) { return Allocate(s); }
  void *operator new[] (size_t s) { return Allocate(s); }
  ~Foo();
  static void *allocated;
  static void *Allocate(size_t s) {
    assert(!allocated);
    return allocated = ::new char[s];
  }
};

Foo::~Foo() {}
void *Foo::allocated;

Foo *getFoo(size_t n) {
  return new Foo[n];
}

int main() {
  Foo *foo = getFoo(10);
  fprintf(stderr, "foo  : %p\n", foo);
  fprintf(stderr, "alloc: %p\n", Foo::allocated);
  assert(reinterpret_cast<uintptr_t>(foo) ==
         reinterpret_cast<uintptr_t>(Foo::allocated) + sizeof(void*));
  *reinterpret_cast<uintptr_t*>(Foo::allocated) = 42;
  return 0;
}
<commit_msg>[asan] Disable array cookie test on ARM, enable on Android/x86.<commit_after>// Test that we do not poison the array cookie if the operator new is defined
// inside the class.
// RUN: %clangxx_asan  %s -o %t && %run %t
//
// XFAIL: arm
#include <new>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
struct Foo {
  void *operator new(size_t s) { return Allocate(s); }
  void *operator new[] (size_t s) { return Allocate(s); }
  ~Foo();
  static void *allocated;
  static void *Allocate(size_t s) {
    assert(!allocated);
    return allocated = ::new char[s];
  }
};

Foo::~Foo() {}
void *Foo::allocated;

Foo *getFoo(size_t n) {
  return new Foo[n];
}

int main() {
  Foo *foo = getFoo(10);
  fprintf(stderr, "foo  : %p\n", foo);
  fprintf(stderr, "alloc: %p\n", Foo::allocated);
  assert(reinterpret_cast<uintptr_t>(foo) ==
         reinterpret_cast<uintptr_t>(Foo::allocated) + sizeof(void*));
  *reinterpret_cast<uintptr_t*>(Foo::allocated) = 42;
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 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.

#if defined(WIN32) || defined(__linux__)

#include <errno.h>

#include "nacl_io/kernel_wrap.h"
#include "nacl_io/kernel_wrap_real.h"

// "real" functions, i.e. the unwrapped original functions. For Windows/Linux
// host builds we don't wrap, so the real functions aren't accessible. In most
// cases, we just fail.

int _real_close(int fd) {
  return ENOSYS;
}

int _real_fstat(int fd, struct stat *buf) {
  return 0;
}

int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t *nread) {
  return ENOSYS;
}

int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
  return ENOSYS;
}

int _real_mkdir(const char* pathname, mode_t mode) {
  return ENOSYS;
}

int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
               off_t offset) {
  return ENOSYS;
}

int _real_munmap(void* addr, size_t length) {
  return ENOSYS;
}

int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
  return ENOSYS;
}

int _real_open_resource(const char* file, int* fd) {
  return ENOSYS;
}

int _real_read(int fd, void *buf, size_t count, size_t *nread) {
  *nread = count;
  return 0;
}

int _real_rmdir(const char* pathname) {
  return ENOSYS;
}

int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
  int rtn = write(fd, buf, count);
  if (rtn < 0)
    return -1;

  *nwrote = rtn;
  return 0;
}

#endif

#if defined(__linux__)

void kernel_wrap_init() {
}

void kernel_wrap_uninit() {
}

#endif
<commit_msg>[NaCl IO] Fix ODR violation when building under Chromium.<commit_after>// Copyright (c) 2013 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.

// The Chromium build system defines __linux__ even for native client builds,
// so guard against __native_client__ being defined as well.
#if defined(WIN32) || (defined(__linux__) && !defined(__native_client__))

#include <errno.h>

#include "nacl_io/kernel_wrap.h"
#include "nacl_io/kernel_wrap_real.h"

// "real" functions, i.e. the unwrapped original functions. For Windows/Linux
// host builds we don't wrap, so the real functions aren't accessible. In most
// cases, we just fail.

int _real_close(int fd) {
  return ENOSYS;
}

int _real_fstat(int fd, struct stat *buf) {
  return 0;
}

int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t *nread) {
  return ENOSYS;
}

int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
  return ENOSYS;
}

int _real_mkdir(const char* pathname, mode_t mode) {
  return ENOSYS;
}

int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
               off_t offset) {
  return ENOSYS;
}

int _real_munmap(void* addr, size_t length) {
  return ENOSYS;
}

int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
  return ENOSYS;
}

int _real_open_resource(const char* file, int* fd) {
  return ENOSYS;
}

int _real_read(int fd, void *buf, size_t count, size_t *nread) {
  *nread = count;
  return 0;
}

int _real_rmdir(const char* pathname) {
  return ENOSYS;
}

int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
  int rtn = write(fd, buf, count);
  if (rtn < 0)
    return -1;

  *nwrote = rtn;
  return 0;
}

#endif

// The Chromium build system defines __linux__ even for native client builds,
// so guard against __native_client__ being defined as well.
#if defined(__linux__) && !defined(__native_client__)

void kernel_wrap_init() {
}

void kernel_wrap_uninit() {
}

#endif
<|endoftext|>


<commit_before>//=- NSErrorChecker.cpp - Coding conventions for uses of NSError -*- 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 a CheckNSError, a flow-insenstive check
//  that determines if an Objective-C class interface correctly returns
//  a non-void return type.
//
//  File under feature request PR 2600.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace ento;

static bool IsNSError(QualType T, IdentifierInfo *II);
static bool IsCFError(QualType T, IdentifierInfo *II);

//===----------------------------------------------------------------------===//
// NSErrorMethodChecker
//===----------------------------------------------------------------------===//

namespace {
class NSErrorMethodChecker
    : public Checker< check::ASTDecl<ObjCMethodDecl> > {
  mutable IdentifierInfo *II;

public:
  NSErrorMethodChecker() : II(0) { }

  void checkASTDecl(const ObjCMethodDecl *D,
                    AnalysisManager &mgr, BugReporter &BR) const;
};
}

void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->isThisDeclarationADefinition())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("NSError");

  bool hasNSError = false;
  for (const auto *I : D->params())  {
    if (IsNSError(I->getType(), II)) {
      hasNSError = true;
      break;
    }
  }

  if (hasNSError) {
    const char *err = "Method accepting NSError** "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing NSError**",
                       "Coding conventions (Apple)", err, L);
  }
}

//===----------------------------------------------------------------------===//
// CFErrorFunctionChecker
//===----------------------------------------------------------------------===//

namespace {
class CFErrorFunctionChecker
    : public Checker< check::ASTDecl<FunctionDecl> > {
  mutable IdentifierInfo *II;

public:
  CFErrorFunctionChecker() : II(0) { }

  void checkASTDecl(const FunctionDecl *D,
                    AnalysisManager &mgr, BugReporter &BR) const;
};
}

void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->doesThisDeclarationHaveABody())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("CFErrorRef");

  bool hasCFError = false;
  for (auto I : D->params())  {
    if (IsCFError(I->getType(), II)) {
      hasCFError = true;
      break;
    }
  }

  if (hasCFError) {
    const char *err = "Function accepting CFErrorRef* "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing CFErrorRef*",
                       "Coding conventions (Apple)", err, L);
  }
}

//===----------------------------------------------------------------------===//
// NSOrCFErrorDerefChecker
//===----------------------------------------------------------------------===//

namespace {

class NSErrorDerefBug : public BugType {
public:
  NSErrorDerefBug(const CheckerBase *Checker)
      : BugType(Checker, "NSError** null dereference",
                "Coding conventions (Apple)") {}
};

class CFErrorDerefBug : public BugType {
public:
  CFErrorDerefBug(const CheckerBase *Checker)
      : BugType(Checker, "CFErrorRef* null dereference",
                "Coding conventions (Apple)") {}
};

}

namespace {
class NSOrCFErrorDerefChecker
    : public Checker< check::Location,
                        check::Event<ImplicitNullDerefEvent> > {
  mutable IdentifierInfo *NSErrorII, *CFErrorII;
public:
  bool ShouldCheckNSError, ShouldCheckCFError;
  NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0),
                              ShouldCheckNSError(0), ShouldCheckCFError(0) { }

  void checkLocation(SVal loc, bool isLoad, const Stmt *S,
                     CheckerContext &C) const;
  void checkEvent(ImplicitNullDerefEvent event) const;
};
}

typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag)
REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag)

template <typename T>
static bool hasFlag(SVal val, ProgramStateRef state) {
  if (SymbolRef sym = val.getAsSymbol())
    if (const unsigned *attachedFlags = state->get<T>(sym))
      return *attachedFlags;
  return false;
}

template <typename T>
static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
  // We tag the symbol that the SVal wraps.
  if (SymbolRef sym = val.getAsSymbol())
    C.addTransition(state->set<T>(sym, true));
}

static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
  const StackFrameContext *
    SFC = C.getLocationContext()->getCurrentStackFrame();
  if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
    const MemRegion* R = X->getRegion();
    if (const VarRegion *VR = R->getAs<VarRegion>())
      if (const StackArgumentsSpaceRegion *
          stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
        if (stackReg->getStackFrame() == SFC)
          return VR->getValueType();
  }

  return QualType();
}

void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
                                            const Stmt *S,
                                            CheckerContext &C) const {
  if (!isLoad)
    return;
  if (loc.isUndef() || !loc.getAs<Loc>())
    return;

  ASTContext &Ctx = C.getASTContext();
  ProgramStateRef state = C.getState();

  // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting
  // SVal so that we can later check it when handling the
  // ImplicitNullDerefEvent event.
  // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of
  // function ?

  QualType parmT = parameterTypeFromSVal(loc, C);
  if (parmT.isNull())
    return;

  if (!NSErrorII)
    NSErrorII = &Ctx.Idents.get("NSError");
  if (!CFErrorII)
    CFErrorII = &Ctx.Idents.get("CFErrorRef");

  if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) {
    setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
    return;
  }

  if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) {
    setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
    return;
  }
}

void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
  if (event.IsLoad)
    return;

  SVal loc = event.Location;
  ProgramStateRef state = event.SinkNode->getState();
  BugReporter &BR = *event.BR;

  bool isNSError = hasFlag<NSErrorOut>(loc, state);
  bool isCFError = false;
  if (!isNSError)
    isCFError = hasFlag<CFErrorOut>(loc, state);

  if (!(isNSError || isCFError))
    return;

  // Storing to possible null NSError/CFErrorRef out parameter.
  SmallString<128> Buf;
  llvm::raw_svector_ostream os(Buf);

  os << "Potential null dereference.  According to coding standards ";
  os << (isNSError
         ? "in 'Creating and Returning NSError Objects' the parameter"
         : "documented in CoreFoundation/CFError.h the parameter");

  os  << " may be null";

  BugType *bug = 0;
  if (isNSError)
    bug = new NSErrorDerefBug(this);
  else
    bug = new CFErrorDerefBug(this);
  BugReport *report = new BugReport(*bug, os.str(), event.SinkNode);
  BR.emitReport(report);
}

static bool IsNSError(QualType T, IdentifierInfo *II) {

  const PointerType* PPT = T->getAs<PointerType>();
  if (!PPT)
    return false;

  const ObjCObjectPointerType* PT =
    PPT->getPointeeType()->getAs<ObjCObjectPointerType>();

  if (!PT)
    return false;

  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();

  // FIXME: Can ID ever be NULL?
  if (ID)
    return II == ID->getIdentifier();

  return false;
}

static bool IsCFError(QualType T, IdentifierInfo *II) {
  const PointerType* PPT = T->getAs<PointerType>();
  if (!PPT) return false;

  const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
  if (!TT) return false;

  return TT->getDecl()->getIdentifier() == II;
}

void ento::registerNSErrorChecker(CheckerManager &mgr) {
  mgr.registerChecker<NSErrorMethodChecker>();
  NSOrCFErrorDerefChecker *checker =
      mgr.registerChecker<NSOrCFErrorDerefChecker>();
  checker->ShouldCheckNSError = true;
}

void ento::registerCFErrorChecker(CheckerManager &mgr) {
  mgr.registerChecker<CFErrorFunctionChecker>();
  NSOrCFErrorDerefChecker *checker =
      mgr.registerChecker<NSOrCFErrorDerefChecker>();
  checker->ShouldCheckCFError = true;
}
<commit_msg>NSOrCFErrorDerefChecker: Don't leak bug type. Similar to r208110/r208155. Found by LSan.<commit_after>//=- NSErrorChecker.cpp - Coding conventions for uses of NSError -*- 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 a CheckNSError, a flow-insenstive check
//  that determines if an Objective-C class interface correctly returns
//  a non-void return type.
//
//  File under feature request PR 2600.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace ento;

static bool IsNSError(QualType T, IdentifierInfo *II);
static bool IsCFError(QualType T, IdentifierInfo *II);

//===----------------------------------------------------------------------===//
// NSErrorMethodChecker
//===----------------------------------------------------------------------===//

namespace {
class NSErrorMethodChecker
    : public Checker< check::ASTDecl<ObjCMethodDecl> > {
  mutable IdentifierInfo *II;

public:
  NSErrorMethodChecker() : II(0) { }

  void checkASTDecl(const ObjCMethodDecl *D,
                    AnalysisManager &mgr, BugReporter &BR) const;
};
}

void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->isThisDeclarationADefinition())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("NSError");

  bool hasNSError = false;
  for (const auto *I : D->params())  {
    if (IsNSError(I->getType(), II)) {
      hasNSError = true;
      break;
    }
  }

  if (hasNSError) {
    const char *err = "Method accepting NSError** "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing NSError**",
                       "Coding conventions (Apple)", err, L);
  }
}

//===----------------------------------------------------------------------===//
// CFErrorFunctionChecker
//===----------------------------------------------------------------------===//

namespace {
class CFErrorFunctionChecker
    : public Checker< check::ASTDecl<FunctionDecl> > {
  mutable IdentifierInfo *II;

public:
  CFErrorFunctionChecker() : II(0) { }

  void checkASTDecl(const FunctionDecl *D,
                    AnalysisManager &mgr, BugReporter &BR) const;
};
}

void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->doesThisDeclarationHaveABody())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("CFErrorRef");

  bool hasCFError = false;
  for (auto I : D->params())  {
    if (IsCFError(I->getType(), II)) {
      hasCFError = true;
      break;
    }
  }

  if (hasCFError) {
    const char *err = "Function accepting CFErrorRef* "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing CFErrorRef*",
                       "Coding conventions (Apple)", err, L);
  }
}

//===----------------------------------------------------------------------===//
// NSOrCFErrorDerefChecker
//===----------------------------------------------------------------------===//

namespace {

class NSErrorDerefBug : public BugType {
public:
  NSErrorDerefBug(const CheckerBase *Checker)
      : BugType(Checker, "NSError** null dereference",
                "Coding conventions (Apple)") {}
};

class CFErrorDerefBug : public BugType {
public:
  CFErrorDerefBug(const CheckerBase *Checker)
      : BugType(Checker, "CFErrorRef* null dereference",
                "Coding conventions (Apple)") {}
};

}

namespace {
class NSOrCFErrorDerefChecker
    : public Checker< check::Location,
                        check::Event<ImplicitNullDerefEvent> > {
  mutable IdentifierInfo *NSErrorII, *CFErrorII;
  mutable std::unique_ptr<NSErrorDerefBug> NSBT;
  mutable std::unique_ptr<CFErrorDerefBug> CFBT;
public:
  bool ShouldCheckNSError, ShouldCheckCFError;
  NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0),
                              ShouldCheckNSError(0), ShouldCheckCFError(0) { }

  void checkLocation(SVal loc, bool isLoad, const Stmt *S,
                     CheckerContext &C) const;
  void checkEvent(ImplicitNullDerefEvent event) const;
};
}

typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag)
REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag)

template <typename T>
static bool hasFlag(SVal val, ProgramStateRef state) {
  if (SymbolRef sym = val.getAsSymbol())
    if (const unsigned *attachedFlags = state->get<T>(sym))
      return *attachedFlags;
  return false;
}

template <typename T>
static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
  // We tag the symbol that the SVal wraps.
  if (SymbolRef sym = val.getAsSymbol())
    C.addTransition(state->set<T>(sym, true));
}

static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
  const StackFrameContext *
    SFC = C.getLocationContext()->getCurrentStackFrame();
  if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
    const MemRegion* R = X->getRegion();
    if (const VarRegion *VR = R->getAs<VarRegion>())
      if (const StackArgumentsSpaceRegion *
          stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
        if (stackReg->getStackFrame() == SFC)
          return VR->getValueType();
  }

  return QualType();
}

void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
                                            const Stmt *S,
                                            CheckerContext &C) const {
  if (!isLoad)
    return;
  if (loc.isUndef() || !loc.getAs<Loc>())
    return;

  ASTContext &Ctx = C.getASTContext();
  ProgramStateRef state = C.getState();

  // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting
  // SVal so that we can later check it when handling the
  // ImplicitNullDerefEvent event.
  // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of
  // function ?

  QualType parmT = parameterTypeFromSVal(loc, C);
  if (parmT.isNull())
    return;

  if (!NSErrorII)
    NSErrorII = &Ctx.Idents.get("NSError");
  if (!CFErrorII)
    CFErrorII = &Ctx.Idents.get("CFErrorRef");

  if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) {
    setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
    return;
  }

  if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) {
    setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
    return;
  }
}

void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
  if (event.IsLoad)
    return;

  SVal loc = event.Location;
  ProgramStateRef state = event.SinkNode->getState();
  BugReporter &BR = *event.BR;

  bool isNSError = hasFlag<NSErrorOut>(loc, state);
  bool isCFError = false;
  if (!isNSError)
    isCFError = hasFlag<CFErrorOut>(loc, state);

  if (!(isNSError || isCFError))
    return;

  // Storing to possible null NSError/CFErrorRef out parameter.
  SmallString<128> Buf;
  llvm::raw_svector_ostream os(Buf);

  os << "Potential null dereference.  According to coding standards ";
  os << (isNSError
         ? "in 'Creating and Returning NSError Objects' the parameter"
         : "documented in CoreFoundation/CFError.h the parameter");

  os  << " may be null";

  BugType *bug = 0;
  if (isNSError) {
    if (!NSBT)
      NSBT.reset(new NSErrorDerefBug(this));
    bug = NSBT.get();
  }
  else {
    if (!CFBT)
      CFBT.reset(new CFErrorDerefBug(this));
    bug = CFBT.get();
  }
  BugReport *report = new BugReport(*bug, os.str(), event.SinkNode);
  BR.emitReport(report);
}

static bool IsNSError(QualType T, IdentifierInfo *II) {

  const PointerType* PPT = T->getAs<PointerType>();
  if (!PPT)
    return false;

  const ObjCObjectPointerType* PT =
    PPT->getPointeeType()->getAs<ObjCObjectPointerType>();

  if (!PT)
    return false;

  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();

  // FIXME: Can ID ever be NULL?
  if (ID)
    return II == ID->getIdentifier();

  return false;
}

static bool IsCFError(QualType T, IdentifierInfo *II) {
  const PointerType* PPT = T->getAs<PointerType>();
  if (!PPT) return false;

  const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
  if (!TT) return false;

  return TT->getDecl()->getIdentifier() == II;
}

void ento::registerNSErrorChecker(CheckerManager &mgr) {
  mgr.registerChecker<NSErrorMethodChecker>();
  NSOrCFErrorDerefChecker *checker =
      mgr.registerChecker<NSOrCFErrorDerefChecker>();
  checker->ShouldCheckNSError = true;
}

void ento::registerCFErrorChecker(CheckerManager &mgr) {
  mgr.registerChecker<CFErrorFunctionChecker>();
  NSOrCFErrorDerefChecker *checker =
      mgr.registerChecker<NSOrCFErrorDerefChecker>();
  checker->ShouldCheckCFError = true;
}
<|endoftext|>


<commit_before>#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

int main( int argc, char** argv ){
	using namespace cv;

	if(argc != 2){
		std::cerr << "usage: ./blurs <filename>" << std::endl;
		return -1;
	}

	namedWindow("Original", CV_WINDOW_KEEPRATIO);
	namedWindow("Blur", CV_WINDOW_KEEPRATIO);
	Mat imgOriginal, imgBlur;

	imgOriginal = imread(argv[1]);
	if(!imgOriginal.data){
		std::cerr << "could not read img!" << std::endl;
		return -1;
	}

	//TODO

	return 0;
}

<commit_msg>finished blur example<commit_after>#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

int main( int argc, char** argv ){
	using namespace cv;

	if(argc != 2){
		std::cerr << "usage: ./blurs <filename>" << std::endl;
		return -1;
	}

	namedWindow("Original", CV_WINDOW_KEEPRATIO);
	namedWindow("Gauss", CV_WINDOW_KEEPRATIO);
	namedWindow("Median", CV_WINDOW_KEEPRATIO);
	namedWindow("Bilateral", CV_WINDOW_KEEPRATIO);
	Mat imgOriginal, imgGauss, imgMedian, imgBilateral;

	imgOriginal = imread(argv[1]);
	if(!imgOriginal.data){
		std::cerr << "could not read img!" << std::endl;
		return -1;
	}
	Size ksize(11, 11);
	cv::GaussianBlur(imgOriginal, imgGauss, ksize, 0);
	cv::medianBlur(imgOriginal, imgMedian, 11);

	double sigmaColor = 10, simgaSpace = 10;
	cv::bilateralFilter(imgOriginal, imgBilateral, 10, sigmaColor, simgaSpace, 0);

	imshow("Original", imgOriginal);
	imshow("Gauss", imgGauss);
	imshow("Median", imgMedian);
	imshow("Bilateral", imgBilateral);

	while(waitKey(0) != 27){}; //wait until ESC is hit
	return 0;
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkMaximumProjectionImageFilterTest3.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkCommand.h"
#include "itkSimpleFilterWatcher.h"

#include "itkMaximumProjectionImageFilter.h"
#include "itkExtractImageFilter.h"

int itkMaximumProjectionImageFilterTest3(int argc, char * argv[])
{
  if( argc < 4 )
    {
    std::cerr << "Missing parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << "Dimension Inputimage Outputimage " << std::endl;
    return EXIT_FAILURE;
    }

  int dim = atoi(argv[1]);

  typedef unsigned char PType;
  typedef itk::Image< PType, 3 > IType;
  typedef itk::Image< PType, 2 > IType2;

  typedef itk::ImageFileReader< IType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );

  typedef itk::MaximumProjectionImageFilter< IType, IType2 > FilterType;
  FilterType::Pointer filter = FilterType::New();
  filter->SetInput( reader->GetOutput() );
  filter->SetProjectionDimension( dim );
  // to be sure that the result is ok with several threads, even on a single
  // proc computer
  filter->SetNumberOfThreads( 2 );

//   itk::SimpleFilterWatcher watcher(filter, "filter");

  typedef itk::ImageFileWriter< IType2 > WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetInput( filter->GetOutput() );
  writer->SetFileName( argv[3] );

  try
  {
  writer->Update();
  }
  catch ( itk::ExceptionObject & excp )
  {
  std::cerr << excp << std::endl;
  return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

<commit_msg>STYLE: Fixing style violations, and making more explicit typedefs.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkMaximumProjectionImageFilterTest3.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkCommand.h"
#include "itkSimpleFilterWatcher.h"

#include "itkMaximumProjectionImageFilter.h"
#include "itkExtractImageFilter.h"

int itkMaximumProjectionImageFilterTest3(int argc, char * argv[])
{
  if( argc < 4 )
    {
    std::cerr << "Missing parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << "Dimension Inputimage Outputimage " << std::endl;
    return EXIT_FAILURE;
    }

  int dim = atoi(argv[1]);

  typedef unsigned char PixelType;

  typedef itk::Image< PixelType, 3 > ImageType;
  typedef itk::Image< PixelType, 2 > Image2DType;

  typedef itk::ImageFileReader< ImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );

  typedef itk::MaximumProjectionImageFilter<
    ImageType, Image2DType > FilterType;

  FilterType::Pointer filter = FilterType::New();
  filter->SetInput( reader->GetOutput() );
  filter->SetProjectionDimension( dim );

  // to be sure that the result is ok with several threads, even on a single
  // proc computer
  filter->SetNumberOfThreads( 2 );

  itk::SimpleFilterWatcher watcher(filter, "filter");

  typedef itk::ImageFileWriter< Image2DType > WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetInput( filter->GetOutput() );
  writer->SetFileName( argv[3] );

  try
    {
    writer->Update();
    }
  catch ( itk::ExceptionObject & excp )
    {
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "stdio.h"
#include "unistd.h"
#include "sys/time.h"
#include "mpi.h"

#include "master.h"
#include "failure.h"
#include "protocol.h"
#include "log.h"
#include "tools.h"

Master::Master(const std::string &program, Engine &engine, DAG &dag,
               const std::string &dagfile, const std::string &outfile,
               const std::string &errfile) {
    this->program = program;
    this->dagfile = dagfile;
    this->outfile = dagfile + "." + outfile;
    this->errfile = dagfile + "." + errfile;
    this->engine = &engine;
    this->dag = &dag;

    total_count = 0;
    success_count = 0;
    failed_count = 0;
}

Master::~Master() {
}

void Master::submit_task(Task *task, int worker) {
    int rc;
    log_debug("Submitting task %s to worker %d", task->name.c_str(), worker);
    rc = send_request(task->name, task->command, task->extra_id, worker);
    if (rc != 0 ) {
        myfailure("Sending task failed");
    }

    this->total_count++;
}

void Master::wait_for_result() {
    log_trace("Waiting for task to finish");

    std::string name;
    int exitcode;
    double start_time;
    double end_time;
    int worker;
    recv_response(name, start_time, end_time, exitcode, worker);

    // Mark worker idle
    log_trace("Worker %d is idle", worker);
    this->mark_worker_idle(worker);

    // Mark task finished
    if (exitcode == 0) {
        log_debug("Task %s finished with exitcode %d", name.c_str(), exitcode);
        this->success_count++;
    } else {
        log_error("Task %s failed with exitcode %d", name.c_str(), exitcode);
        this->failed_count++;
    }
    Task *t = this->dag->get_task(name);
    this->engine->mark_task_finished(t, exitcode);
}

void Master::add_worker(int worker) {
    this->mark_worker_idle(worker);
}

bool Master::has_idle_worker() {
    return !this->idle.empty();
}

int Master::next_idle_worker() {
    if (!this->has_idle_worker()) {
        myfailure("No idle workers");
    }
    int worker = this->idle.front();
    this->idle.pop();
    return worker;
}

void Master::mark_worker_idle(int worker) {
    this->idle.push(worker);
}

void Master::merge_task_stdio(FILE *dest, const std::string &srcfile, const std::string &stream) {
    log_trace("Merging %s file: %s", stream.c_str(), srcfile.c_str());

    FILE *src = fopen(srcfile.c_str(), "r");
    if (src == NULL) {
        // The file may not exist if the worker didn't run any tasks, just print a warning
        if (errno == ENOENT) {
            log_warn("No %s file: %s", stream.c_str(), srcfile.c_str());
            return;
        } else {
            myfailures("Unable to open task %s file: %s", stream.c_str(), srcfile.c_str());
        }
    }

    char buf[BUFSIZ];
    while (1) {
        int r = fread(buf, 1, BUFSIZ, src);
        if (r < 0) {
            myfailures("Error reading source file: %s", srcfile.c_str());
        }
        if (r == 0) {
            break;
        }
        int w = fwrite(buf, 1, r, dest);
        if (w < r) {
            myfailures("Error writing to dest file");
        }
    }

    fclose(src);

    if (unlink(srcfile.c_str())) {
        myfailures("Unable to delete task %s file: %s", stream.c_str(), srcfile.c_str());
    }
}

int Master::run() {
    // Start time of workflow
    struct timeval start;
    gettimeofday(&start, NULL);

    int numprocs;
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);

    int numworkers = numprocs - 1;
    if (numworkers == 0) {
        myfailure("Need at least 1 worker");
    }

    log_info("Master starting with %d workers", numworkers);

    // First, send out the paths to the outfile/errfile
    send_stdio_paths(this->outfile, this->errfile);

    // Queue up the workers
    for (int i=1; i<=numworkers; i++) {
        this->add_worker(i);
    }

    // While DAG has tasks to run
    while (!this->engine->is_finished()) {

        // Submit as many tasks as we can
        while (this->engine->has_ready_task() && this->has_idle_worker()) {
            int worker = this->next_idle_worker();
            Task *task = this->engine->next_ready_task();
            this->submit_task(task, worker);
        }

        if (!this->engine->has_ready_task()) {
            log_debug("No ready tasks");
        }

        if (!this->has_idle_worker()) {
            log_debug("No idle workers");
        }

        this->wait_for_result();
    }

    log_info("Workflow finished");

    // Finish time of workflow
    struct timeval finish;
    gettimeofday(&finish, NULL);

    // Tell workers to exit
    // TODO Change this to MPI_Bcast
    log_trace("Sending workers shutdown messages");
    for (int i=1; i<=numworkers; i++) {
        send_shutdown(i);
    }

    log_trace("Waiting for workers to finish");

    double total_runtime = collect_total_runtimes();
    log_info("Total runtime of tasks: %f", total_runtime);

    double stime = start.tv_sec + (start.tv_usec/1000000.0);
    double ftime = finish.tv_sec + (finish.tv_usec/1000000.0);
    double walltime = ftime - stime;
    log_info("Wall time: %lf seconds", walltime);

    // Compute resource utilization
    if (total_runtime > 0) {
        double master_util = total_runtime / (walltime * numprocs);
        double worker_util = total_runtime / (walltime * numworkers);
        log_info("Resource utilization (with master): %lf", master_util);
        log_info("Resource utilization (without master): %lf", worker_util);
    }

    // Merge stdout/stderr from all tasks
    log_trace("Merging stdio from workers");
    FILE *outf = stdout;
    if (outfile != "stdout") {
        fopen(this->outfile.c_str(), "w");
        if (outf == NULL) {
            myfailures("Unable to open stdout file: %s\n", this->outfile.c_str());
        }
    }
    FILE *errf = stderr;
    if (errfile != "stderr") {
        fopen(this->errfile.c_str(), "w");
        if (errf == NULL) {
            myfailures("Unable to open stderr file: %s\n", this->outfile.c_str());
        }
    }

    // Collect all stdout/stderr
    char dotrank[25];
    for (int i=1; i<=numworkers; i++) {
        sprintf(dotrank, ".%d", i);

        std::string toutfile = this->outfile;
        toutfile += dotrank;
        this->merge_task_stdio(outf, toutfile, "stdout");

        std::string terrfile = this->errfile;
        terrfile += dotrank;
        this->merge_task_stdio(errf, terrfile, "stderr");
    }

    // pegasus cluster output - used for provenance
    char buf[BUFSIZ];
    char stat[10];
    char date[32];
    if (this->engine->is_failed()) {
        strcpy(stat, "failed");
    }
    else {
        strcpy(stat, "ok");
    }
    iso2date(stime, date, sizeof(date));
    sprintf(buf, "[cluster-summary stat=\"%s\" tasks=%ld, succeeded=%ld, failed=%ld, extra=%d,"
                 " start=\"%s\", duration=%.3f, pid=%d, app=\"%s\"]\n",
                 stat,
                 this->total_count,
                 this->success_count,
                 this->failed_count,
                 0,
                 date,
                 walltime * numprocs, /* duration is for all cores */
                 getpid(),
                 this->program.c_str());
    fwrite(buf, 1, strlen(buf), outf);

    if (errfile != "stderr") {
        fclose(errf);
    }
    if (outfile != "stdout") {
        fclose(outf);
    }

    if (this->engine->max_failures_reached()) {
        log_error("Max myfailures reached: DAG prematurely aborted");
    }

    if (this->engine->is_failed()) {
        log_error("Workflow failed");
        return 1;
    } else {
        log_info("Workflow suceeded");
        return 0;
    }
}
<commit_msg>Fix outfile and errfile bug<commit_after>#include "stdio.h"
#include "unistd.h"
#include "sys/time.h"
#include "mpi.h"

#include "master.h"
#include "failure.h"
#include "protocol.h"
#include "log.h"
#include "tools.h"

Master::Master(const std::string &program, Engine &engine, DAG &dag,
               const std::string &dagfile, const std::string &outfile,
               const std::string &errfile) {
    this->program = program;
    this->dagfile = dagfile;
    this->outfile = outfile;
    this->errfile = errfile;
    this->engine = &engine;
    this->dag = &dag;

    total_count = 0;
    success_count = 0;
    failed_count = 0;
}

Master::~Master() {
}

void Master::submit_task(Task *task, int worker) {
    int rc;
    log_debug("Submitting task %s to worker %d", task->name.c_str(), worker);
    rc = send_request(task->name, task->command, task->extra_id, worker);
    if (rc != 0 ) {
        myfailure("Sending task failed");
    }

    this->total_count++;
}

void Master::wait_for_result() {
    log_trace("Waiting for task to finish");

    std::string name;
    int exitcode;
    double start_time;
    double end_time;
    int worker;
    recv_response(name, start_time, end_time, exitcode, worker);

    // Mark worker idle
    log_trace("Worker %d is idle", worker);
    this->mark_worker_idle(worker);

    // Mark task finished
    if (exitcode == 0) {
        log_debug("Task %s finished with exitcode %d", name.c_str(), exitcode);
        this->success_count++;
    } else {
        log_error("Task %s failed with exitcode %d", name.c_str(), exitcode);
        this->failed_count++;
    }
    Task *t = this->dag->get_task(name);
    this->engine->mark_task_finished(t, exitcode);
}

void Master::add_worker(int worker) {
    this->mark_worker_idle(worker);
}

bool Master::has_idle_worker() {
    return !this->idle.empty();
}

int Master::next_idle_worker() {
    if (!this->has_idle_worker()) {
        myfailure("No idle workers");
    }
    int worker = this->idle.front();
    this->idle.pop();
    return worker;
}

void Master::mark_worker_idle(int worker) {
    this->idle.push(worker);
}

void Master::merge_task_stdio(FILE *dest, const std::string &srcfile, const std::string &stream) {
    log_trace("Merging %s file: %s", stream.c_str(), srcfile.c_str());

    FILE *src = fopen(srcfile.c_str(), "r");
    if (src == NULL) {
        // The file may not exist if the worker didn't run any tasks, just print a warning
        if (errno == ENOENT) {
            log_warn("No %s file: %s", stream.c_str(), srcfile.c_str());
            return;
        } else {
            myfailures("Unable to open task %s file: %s", stream.c_str(), srcfile.c_str());
        }
    }

    char buf[BUFSIZ];
    while (1) {
        int r = fread(buf, 1, BUFSIZ, src);
        if (r < 0) {
            myfailures("Error reading source file: %s", srcfile.c_str());
        }
        if (r == 0) {
            break;
        }
        int w = fwrite(buf, 1, r, dest);
        if (w < r) {
            myfailures("Error writing to dest file");
        }
    }

    fclose(src);

    if (unlink(srcfile.c_str())) {
        myfailures("Unable to delete task %s file: %s", stream.c_str(), srcfile.c_str());
    }
}

int Master::run() {
    // Start time of workflow
    struct timeval start;
    gettimeofday(&start, NULL);

    int numprocs;
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);

    int numworkers = numprocs - 1;
    if (numworkers == 0) {
        myfailure("Need at least 1 worker");
    }

    log_info("Master starting with %d workers", numworkers);

    // First, send out the paths to the outfile/errfile
    send_stdio_paths(this->outfile, this->errfile);

    // Queue up the workers
    for (int i=1; i<=numworkers; i++) {
        this->add_worker(i);
    }

    // While DAG has tasks to run
    while (!this->engine->is_finished()) {

        // Submit as many tasks as we can
        while (this->engine->has_ready_task() && this->has_idle_worker()) {
            int worker = this->next_idle_worker();
            Task *task = this->engine->next_ready_task();
            this->submit_task(task, worker);
        }

        if (!this->engine->has_ready_task()) {
            log_debug("No ready tasks");
        }

        if (!this->has_idle_worker()) {
            log_debug("No idle workers");
        }

        this->wait_for_result();
    }

    log_info("Workflow finished");

    // Finish time of workflow
    struct timeval finish;
    gettimeofday(&finish, NULL);

    // Tell workers to exit
    // TODO Change this to MPI_Bcast
    log_trace("Sending workers shutdown messages");
    for (int i=1; i<=numworkers; i++) {
        send_shutdown(i);
    }

    log_trace("Waiting for workers to finish");

    double total_runtime = collect_total_runtimes();
    log_info("Total runtime of tasks: %f", total_runtime);

    double stime = start.tv_sec + (start.tv_usec/1000000.0);
    double ftime = finish.tv_sec + (finish.tv_usec/1000000.0);
    double walltime = ftime - stime;
    log_info("Wall time: %lf seconds", walltime);

    // Compute resource utilization
    if (total_runtime > 0) {
        double master_util = total_runtime / (walltime * numprocs);
        double worker_util = total_runtime / (walltime * numworkers);
        log_info("Resource utilization (with master): %lf", master_util);
        log_info("Resource utilization (without master): %lf", worker_util);
    }

    // Merge stdout/stderr from all tasks
    log_trace("Merging stdio from workers");
    FILE *outf = stdout;
    if (outfile != "stdout") {
        outf = fopen(this->outfile.c_str(), "w");
        if (outf == NULL) {
            myfailures("Unable to open stdout file: %s\n", this->outfile.c_str());
        }
    }
    FILE *errf = stderr;
    if (errfile != "stderr") {
        errf = fopen(this->errfile.c_str(), "w");
        if (errf == NULL) {
            myfailures("Unable to open stderr file: %s\n", this->outfile.c_str());
        }
    }

    // Collect all stdout/stderr
    char dotrank[25];
    for (int i=1; i<=numworkers; i++) {
        sprintf(dotrank, ".%d", i);

        std::string toutfile = this->outfile;
        toutfile += dotrank;
        this->merge_task_stdio(outf, toutfile, "stdout");

        std::string terrfile = this->errfile;
        terrfile += dotrank;
        this->merge_task_stdio(errf, terrfile, "stderr");
    }

    // pegasus cluster output - used for provenance
    char buf[BUFSIZ];
    char stat[10];
    char date[32];
    if (this->engine->is_failed()) {
        strcpy(stat, "failed");
    }
    else {
        strcpy(stat, "ok");
    }
    iso2date(stime, date, sizeof(date));
    sprintf(buf, "[cluster-summary stat=\"%s\" tasks=%ld, succeeded=%ld, failed=%ld, extra=%d,"
                 " start=\"%s\", duration=%.3f, pid=%d, app=\"%s\"]\n",
                 stat,
                 this->total_count,
                 this->success_count,
                 this->failed_count,
                 0,
                 date,
                 walltime * numprocs, /* duration is for all cores */
                 getpid(),
                 this->program.c_str());
    fwrite(buf, 1, strlen(buf), outf);

    if (errfile != "stderr") {
        fclose(errf);
    }
    if (outfile != "stdout") {
        fclose(outf);
    }

    if (this->engine->max_failures_reached()) {
        log_error("Max failures reached: DAG prematurely aborted");
    }

    if (this->engine->is_failed()) {
        log_error("Workflow failed");
        return 1;
    } else {
        log_info("Workflow suceeded");
        return 0;
    }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_XML_PARSE_HPP
#define TORRENT_XML_PARSE_HPP

#include <cctype>

namespace libtorrent
{
	enum
	{
		xml_start_tag,
		xml_end_tag,
		xml_empty_tag,
		xml_declaration_tag,
		xml_string,
		xml_attribute,
		xml_comment,
		xml_parse_error
	};

	// callback(int type, char const* name, char const* val)
	// str2 is only used for attributes. name is element or attribute
	// name and val is attribute value

	template <class CallbackType>
	void xml_parse(char* p, char* end, CallbackType callback)
	{
		for(;p != end; ++p)
		{
			char const* start = p;
			char const* val_start = 0;
			int token;
			// look for tag start
			for(; *p != '<' && p != end; ++p);

			if (p != start)
			{
				if (p != end)
				{
					TORRENT_ASSERT(*p == '<');
					*p = 0;
				}
				token = xml_string;
				callback(token, start, val_start);
				if (p != end) *p = '<';
			}

			if (p == end) break;

			// skip '<'
			++p;

			// parse the name of the tag.
			for (start = p; p != end && *p != '>' && !std::isspace(*p); ++p);

			char* tag_name_end = p;

			// skip the attributes for now
			for (; p != end && *p != '>'; ++p);

			// parse error
			if (p == end)
			{
				token = xml_parse_error;
				start = "unexpected end of file";
				callback(token, start, val_start);
				break;
			}

			TORRENT_ASSERT(*p == '>');
			// save the character that terminated the tag name
			// it could be both '>' and ' '.
			char save = *tag_name_end;
			*tag_name_end = 0;

			char* tag_end = p;
			if (*start == '/')
			{
				++start;
				token = xml_end_tag;
				callback(token, start, val_start);
			}
			else if (*(p-1) == '/')
			{
				*(p-1) = 0;
				token = xml_empty_tag;
				callback(token, start, val_start);
				*(p-1) = '/';
				tag_end = p - 1;
			}
			else if (*start == '?' && *(p-1) == '?')
			{
				*(p-1) = 0;
				++start;
				token = xml_declaration_tag;
				callback(token, start, val_start);
				*(p-1) = '?';
				tag_end = p - 1;
			}
			else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
			{
				start += 3;
				*(p-2) = 0;
				token = xml_comment;
				callback(token, start, val_start);
				*(p-2) = '-';
				tag_end = p - 2;
			}
			else
			{
				token = xml_start_tag;
				callback(token, start, val_start);
			}

			*tag_name_end = save;

			// parse attributes
			for (char* i = tag_name_end; i < tag_end; ++i)
			{
				// find start of attribute name
				for (; i != tag_end && std::isspace(*i); ++i);
				if (i == tag_end) break;
				start = i;
				// find end of attribute name
				for (; i != tag_end && *i != '=' && !std::isspace(*i); ++i);
				char* name_end = i;

				// look for equality sign
				for (; i != tag_end && *i != '='; ++i);

				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "garbage inside element brackets";
					callback(token, start, val_start);
					break;
				}

				++i;
				for (; i != tag_end && std::isspace(*i); ++i);
				// check for parse error (values must be quoted)
				if (i == tag_end || (*i != '\'' && *i != '\"'))
				{
					token = xml_parse_error;
					val_start = 0;
					start = "unquoted attribute value";
					callback(token, start, val_start);
					break;
				}
				char quote = *i;
				++i;
				val_start = i;
				for (; i != tag_end && *i != quote; ++i);
				// parse error (missing end quote)
				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "missing end quote on attribute";
					callback(token, start, val_start);
					break;
				}
				save = *i;
				*i = 0;
				*name_end = 0;
				token = xml_attribute;
				callback(token, start, val_start);
				*name_end = '=';
				*i = save;
			}
		}

	}

}

#endif

<commit_msg>replaced dependency on locale dependent isspace<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.

*/

#ifndef TORRENT_XML_PARSE_HPP
#define TORRENT_XML_PARSE_HPP

#include <cctype>
#include <cstring>

namespace libtorrent
{
	enum
	{
		xml_start_tag,
		xml_end_tag,
		xml_empty_tag,
		xml_declaration_tag,
		xml_string,
		xml_attribute,
		xml_comment,
		xml_parse_error
	};

	inline bool isspace(char c)
	{
		const static char* ws = " \t\n\r\f\v";
		return std::strchr(ws, c);
	}

	// callback(int type, char const* name, char const* val)
	// str2 is only used for attributes. name is element or attribute
	// name and val is attribute value

	template <class CallbackType>
	void xml_parse(char* p, char* end, CallbackType callback)
	{
		for(;p != end; ++p)
		{
			char const* start = p;
			char const* val_start = 0;
			int token;
			// look for tag start
			for(; *p != '<' && p != end; ++p);

			if (p != start)
			{
				if (p != end)
				{
					TORRENT_ASSERT(*p == '<');
					*p = 0;
				}
				token = xml_string;
				callback(token, start, val_start);
				if (p != end) *p = '<';
			}

			if (p == end) break;

			// skip '<'
			++p;

			// parse the name of the tag.
			for (start = p; p != end && *p != '>' && !isspace(*p); ++p);

			char* tag_name_end = p;

			// skip the attributes for now
			for (; p != end && *p != '>'; ++p);

			// parse error
			if (p == end)
			{
				token = xml_parse_error;
				start = "unexpected end of file";
				callback(token, start, val_start);
				break;
			}

			TORRENT_ASSERT(*p == '>');
			// save the character that terminated the tag name
			// it could be both '>' and ' '.
			char save = *tag_name_end;
			*tag_name_end = 0;

			char* tag_end = p;
			if (*start == '/')
			{
				++start;
				token = xml_end_tag;
				callback(token, start, val_start);
			}
			else if (*(p-1) == '/')
			{
				*(p-1) = 0;
				token = xml_empty_tag;
				callback(token, start, val_start);
				*(p-1) = '/';
				tag_end = p - 1;
			}
			else if (*start == '?' && *(p-1) == '?')
			{
				*(p-1) = 0;
				++start;
				token = xml_declaration_tag;
				callback(token, start, val_start);
				*(p-1) = '?';
				tag_end = p - 1;
			}
			else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
			{
				start += 3;
				*(p-2) = 0;
				token = xml_comment;
				callback(token, start, val_start);
				*(p-2) = '-';
				tag_end = p - 2;
			}
			else
			{
				token = xml_start_tag;
				callback(token, start, val_start);
			}

			*tag_name_end = save;

			// parse attributes
			for (char* i = tag_name_end; i < tag_end; ++i)
			{
				// find start of attribute name
				for (; i != tag_end && isspace(*i); ++i);
				if (i == tag_end) break;
				start = i;
				// find end of attribute name
				for (; i != tag_end && *i != '=' && !isspace(*i); ++i);
				char* name_end = i;

				// look for equality sign
				for (; i != tag_end && *i != '='; ++i);

				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "garbage inside element brackets";
					callback(token, start, val_start);
					break;
				}

				++i;
				for (; i != tag_end && isspace(*i); ++i);
				// check for parse error (values must be quoted)
				if (i == tag_end || (*i != '\'' && *i != '\"'))
				{
					token = xml_parse_error;
					val_start = 0;
					start = "unquoted attribute value";
					callback(token, start, val_start);
					break;
				}
				char quote = *i;
				++i;
				val_start = i;
				for (; i != tag_end && *i != quote; ++i);
				// parse error (missing end quote)
				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "missing end quote on attribute";
					callback(token, start, val_start);
					break;
				}
				save = *i;
				*i = 0;
				*name_end = 0;
				token = xml_attribute;
				callback(token, start, val_start);
				*name_end = '=';
				*i = save;
			}
		}

	}

}

#endif

<|endoftext|>


<commit_before>#include "Class/DlOpen.hpp"
#include "Class/Parsed.hpp"
#include "ClassResolver.hpp"

#include <iostream>

static int _result = 0;

extern "C" void ZN4java4lang6System4exitEi(int code) {
    std::cerr << "java/lang/System.exit(I)V called with code: " << code << std::endl;
    _result = code;
}

int main(int argc, char ** argv) {
    if (argc != 2) {
        std::cerr << "Test must be called with the path to the test class" << std::endl;
        return 1;
    }

    auto classdb = Espresso::VM::ClassResolver();
    classdb.addClass(new Espresso::VM::Class::DlOpen("java/lang/Object"));
    classdb.addClass(new Espresso::VM::Class::DlOpen("java/lang/System"));

    auto cls = Espresso::ClassParser::Class(argv[1]);
    classdb.addClass(new Espresso::VM::Class::Parsed(cls));

    // Remaining Tasks:
    // 1. Pass CR to VM
    // 2. Ask VM to init "argv[1]"
    // 3. ...
    // 4. Profit!

    if (_result != 99) {
        std::cerr << "java/lang/System.exit(I)V was not properly called" << std::endl;
        return 99;
    }
    return 0;
}

<commit_msg>evolving Milestone 1 test<commit_after>#include "Class/DlOpen.hpp"
#include "Class/Parsed.hpp"
#include "ClassResolver.hpp"

#include <iostream>

static int _result = 0;

extern "C" void ZN4java4lang6System4exitEi(int code) {
    std::cerr << "java/lang/System.exit(I)V called with code: " << code << std::endl;
    _result = code;
}

int main(int argc, char ** argv) {
    if (argc != 2) {
        std::cerr << "Test must be called with the path to the test class" << std::endl;
        return 1;
    }

    auto classdb = Espresso::VM::ClassResolver();
    classdb.addClass(new Espresso::VM::Class::DlOpen("java/lang/Object"));
    classdb.addClass(new Espresso::VM::Class::DlOpen("java/lang/System"));

    auto cls = Espresso::ClassParser::Class(argv[1]);
    if (!cls) {
        std::cerr << argv[1] << " wasn't loaded: " << cls.error() << std::endl;
        return 1;
    }
    auto pcls = new Espresso::VM::Class::Parsed(cls);
    classdb.addClass(pcls);

    void (*fn)() = (void (*)())pcls->findMethod("<clinit>", "()V");
    if (!fn) {
        std::cerr << argv[1] << " does not contain <clinit>()V" << std::endl;
        return 1;
    }

    fn();

    if (_result != 99) {
        std::cerr << "java/lang/System.exit(I)V was not properly called" << std::endl;
        return 99;
    }
    return 0;
}

<|endoftext|>