Commit 545008a0 authored by Brenden Blanco's avatar Brenden Blanco Committed by 4ast

frontends/clang: Safety check for invalid opLoc in ProbeVisitor (#667)

As reported in #664:
In cases where the AST contains a MemberExpr with an invalid opLoc,
rewrite will fail but prior to this change would segfault. Fail a little
more gracefully, even though the program will still be rejected.
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent 04e9598b
...@@ -158,7 +158,7 @@ class ProbeSetter : public RecursiveASTVisitor<ProbeSetter> { ...@@ -158,7 +158,7 @@ class ProbeSetter : public RecursiveASTVisitor<ProbeSetter> {
set<Decl *> *ptregs_; set<Decl *> *ptregs_;
}; };
ProbeVisitor::ProbeVisitor(Rewriter &rewriter) : rewriter_(rewriter) {} ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter) : C(C), rewriter_(rewriter) {}
bool ProbeVisitor::VisitVarDecl(VarDecl *Decl) { bool ProbeVisitor::VisitVarDecl(VarDecl *Decl) {
if (Expr *E = Decl->getInit()) { if (Expr *E = Decl->getInit()) {
...@@ -234,6 +234,10 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) { ...@@ -234,6 +234,10 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
} }
if (!found) if (!found)
return true; return true;
if (op.isInvalid()) {
error(base->getLocEnd(), "internal error: opLoc is invalid while preparing probe rewrite");
return false;
}
string rhs = rewriter_.getRewrittenText(SourceRange(rhs_start, E->getLocEnd())); string rhs = rewriter_.getRewrittenText(SourceRange(rhs_start, E->getLocEnd()));
string base_type = base->getType()->getPointeeType().getAsString(); string base_type = base->getType()->getPointeeType().getAsString();
string pre, post; string pre, post;
...@@ -246,6 +250,13 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) { ...@@ -246,6 +250,13 @@ bool ProbeVisitor::VisitMemberExpr(MemberExpr *E) {
return true; return true;
} }
template <unsigned N>
DiagnosticBuilder ProbeVisitor::error(SourceLocation loc, const char (&fmt)[N]) {
unsigned int diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, fmt);
return C.getDiagnostics().Report(loc, diag_id);
}
BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables) BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables)
: C(C), diag_(C.getDiagnostics()), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) { : C(C), diag_(C.getDiagnostics()), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) {
} }
...@@ -697,7 +708,7 @@ bool BTypeConsumer::HandleTopLevelDecl(DeclGroupRef Group) { ...@@ -697,7 +708,7 @@ bool BTypeConsumer::HandleTopLevelDecl(DeclGroupRef Group) {
} }
ProbeConsumer::ProbeConsumer(ASTContext &C, Rewriter &rewriter) ProbeConsumer::ProbeConsumer(ASTContext &C, Rewriter &rewriter)
: visitor_(rewriter) {} : visitor_(C, rewriter) {}
bool ProbeConsumer::HandleTopLevelDecl(DeclGroupRef Group) { bool ProbeConsumer::HandleTopLevelDecl(DeclGroupRef Group) {
for (auto D : Group) { for (auto D : Group) {
......
...@@ -89,7 +89,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { ...@@ -89,7 +89,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
// Do a depth-first search to rewrite all pointers that need to be probed // Do a depth-first search to rewrite all pointers that need to be probed
class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> { class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> {
public: public:
explicit ProbeVisitor(clang::Rewriter &rewriter); explicit ProbeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter);
bool VisitVarDecl(clang::VarDecl *Decl); bool VisitVarDecl(clang::VarDecl *Decl);
bool VisitCallExpr(clang::CallExpr *Call); bool VisitCallExpr(clang::CallExpr *Call);
bool VisitBinaryOperator(clang::BinaryOperator *E); bool VisitBinaryOperator(clang::BinaryOperator *E);
...@@ -97,6 +97,10 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> { ...@@ -97,6 +97,10 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> {
bool VisitMemberExpr(clang::MemberExpr *E); bool VisitMemberExpr(clang::MemberExpr *E);
void set_ptreg(clang::Decl *D) { ptregs_.insert(D); } void set_ptreg(clang::Decl *D) { ptregs_.insert(D); }
private: private:
template <unsigned N>
clang::DiagnosticBuilder error(clang::SourceLocation loc, const char (&fmt)[N]);
clang::ASTContext &C;
clang::Rewriter &rewriter_; clang::Rewriter &rewriter_;
std::set<clang::Decl *> fn_visited_; std::set<clang::Decl *> fn_visited_;
std::set<clang::Expr *> memb_visited_; std::set<clang::Expr *> memb_visited_;
......
...@@ -212,6 +212,20 @@ int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) { ...@@ -212,6 +212,20 @@ int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) {
fn = b.load_func("trace_entry1", BPF.KPROBE) fn = b.load_func("trace_entry1", BPF.KPROBE)
fn = b.load_func("trace_entry2", BPF.KPROBE) fn = b.load_func("trace_entry2", BPF.KPROBE)
def test_probe_unnamed_union_deref(self):
text = """
#include <linux/mm_types.h>
int trace(struct pt_regs *ctx, struct page *page) {
void *p = page->mapping;
return p != NULL;
}
"""
# depending on llvm, compile may pass/fail, but at least shouldn't crash
try:
b = BPF(text=text)
except:
pass
def test_probe_struct_assign(self): def test_probe_struct_assign(self):
b = BPF(text = """ b = BPF(text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment