<commit_before>#include "Introspection.h"
#include "Debug.h"
#include "LLVM_Headers.h"

#include <string>
#include <iostream>
#include <sstream>

// defines backtrace, which gets the call stack as instruction pointers
#include <execinfo.h>

namespace Halide {
namespace Internal {

#ifdef __APPLE__
extern "C" void _NSGetExecutablePath(char *, int32_t *);
void get_program_name(char *name, int32_t size) {
    _NSGetExecutablePath(name, &size);
}
#else
// glibc defines the binary name for us
extern "C" char *program_invocation_name;
void get_program_name(char *name, int32_t size) {
    strncpy(name, program_invocation_name, size);
}
#endif

class DebugSections {

public:

    bool working;

    DebugSections(std::string binary) : working(false) {
        #ifdef __APPLE__
        size_t last_slash = binary.rfind('/');
        if (last_slash == std::string::npos ||
            last_slash >= binary.size() - 1) {
            last_slash = 0;
        } else {
            last_slash++;
        }
        std::string file_only = binary.substr(last_slash, binary.size() - last_slash);
        binary += ".dSYM/Contents/Resources/DWARF/" + file_only;
        #endif

        debug(2) << "Loading " << binary << "\n";

        llvm::object::ObjectFile *obj = load_object_file(binary);
        if (obj) {
            working = true;
            parse_object_file(obj);
            delete obj;
        } else {
            debug(1) << "Could not load object file: " << binary << "\n";
            working = false;
        }

    }

    void calibrate_pc_offset(void (*fn)()) {
        // Calibrate for the offset between the
        // instruction pointers in the debug info and the instruction
        // pointers in the actual file.
        bool found = false;
        int64_t pc_adjust = 0;
        for (size_t i = 0; i < functions.size(); i++) {
            if (functions[i].name == "HalideIntrospectionCanary::offset_marker" &&
                functions[i].pc_begin) {
                uint64_t pc_lo = functions[i].pc_begin;
                uint64_t pc_hi = functions[i].pc_end;
                uint64_t pc = (uint64_t)fn;
                // Find a multiple of 4096 that places pc between pc_lo and pc_hi
                int64_t off = pc - pc_lo;
                off -= off & 0xfff;
                uint64_t pc_adj = pc - off;
                if (pc_lo <= pc_adj &&
                    pc_adj <= pc_hi &&
                    pc_adj + 4096 > pc_hi &&
                    pc_adj - 4096 < pc_lo) {
                    found = true;
                    pc_adjust = off;
                } else {
                    debug(1) << "Found HalideIntrospectionCanary::offset_marker "
                             << "but could not compute a unique offset\n";
                    working = false;
                    return;
                }
            }
        }

        if (!found) {
            debug(1) << "Failed to find HalideIntrospectionCanary::offset_marker\n";
            working = false;
            return;
        }

        debug(4) << "Program counter adjustment between debug info and actual code: " << pc_adjust << "\n";

        for (size_t i = 0; i < functions.size(); i++) {
            functions[i].pc_begin += pc_adjust;
            functions[i].pc_end += pc_adjust;
        }

        for (size_t i = 0; i < source_lines.size(); i++) {
            source_lines[i].pc += pc_adjust;
        }
    }

    // Get the debug name of a stack variable from a pointer to it
    std::string get_variable_name(const void *stack_pointer, const std::string &type_name = "") {

        // Check it's a plausible stack pointer
        int marker = 0;
        uint64_t marker_addr = (uint64_t)&marker;
        uint64_t top_of_stack;
        if (marker_addr >> 63) {
            top_of_stack = (uint64_t)(-1);
        } else {
            // Conservatively assume top of stack is first multiple of
            // 1GB larger than the marker (seriously, who allocates
            // 1GB of stack space?).
            top_of_stack = ((marker_addr >> 30) + 1) << 30;
        }

        if ((uint64_t)stack_pointer > top_of_stack ||
            (uint64_t)stack_pointer < marker_addr) {
            return "";
        }

        // Get the backtrace
        std::vector<void *> trace(1024);
        int trace_size = backtrace(&trace[0], 1024);
        trace.resize(trace_size);

        // OS X with no frame pointer will return a backtrace of size 1 always.
        if (trace.size() <= 2) {
            debug(1) << "backtrace doesn't seem to have many frames\n";
            return "";
        }

        // OS X seems to sometimes dump a sentinel on the end of the
        // backtrace.
        if (trace.back() == (void *)1) {
            trace.pop_back();
        }


        const int addr_size = (int)(sizeof(void *));

        // Begin the search by rounding down the stack pointer to an aligned address
        uint64_t aligned_stack_pointer = (uint64_t)(stack_pointer) & (~(addr_size - 1));

        const void **stack_ptr = (const void **)aligned_stack_pointer;
        // This stack pointer doesn't belong to this function, so there
        // must have been a function call to get here, which means there
        // must be a return address on the stack somewhere down-stack from
        // the pointer.

        // Walk up and down the stack looking for a return address in our backtrace
        const void **stack_frame_top = NULL, **stack_frame_bottom = NULL;
        int frame = 0;
        for (int i = 0; i < 10240 && stack_frame_top == NULL; i++) {

            if (stack_ptr[i] == trace.back()) {
                // Don't walk off the end of the stack.
                break;
            }

            for (int j = 1; j < (int)trace.size() && frame == 0; j++) {
                if (stack_ptr[i] == trace[j]) {
                    stack_frame_top = stack_ptr + i;
                    frame = j;
                }
            }
        }<commit_msg>Extra check to prevent wandering off-stack<commit_after>#include "Introspection.h"
#include "Debug.h"
#include "LLVM_Headers.h"

#include <string>
#include <iostream>
#include <sstream>

// defines backtrace, which gets the call stack as instruction pointers
#include <execinfo.h>

namespace Halide {
namespace Internal {

#ifdef __APPLE__
extern "C" void _NSGetExecutablePath(char *, int32_t *);
void get_program_name(char *name, int32_t size) {
    _NSGetExecutablePath(name, &size);
}
#else
// glibc defines the binary name for us
extern "C" char *program_invocation_name;
void get_program_name(char *name, int32_t size) {
    strncpy(name, program_invocation_name, size);
}
#endif

class DebugSections {

public:

    bool working;

    DebugSections(std::string binary) : working(false) {
        #ifdef __APPLE__
        size_t last_slash = binary.rfind('/');
        if (last_slash == std::string::npos ||
            last_slash >= binary.size() - 1) {
            last_slash = 0;
        } else {
            last_slash++;
        }
        std::string file_only = binary.substr(last_slash, binary.size() - last_slash);
        binary += ".dSYM/Contents/Resources/DWARF/" + file_only;
        #endif

        debug(2) << "Loading " << binary << "\n";

        llvm::object::ObjectFile *obj = load_object_file(binary);
        if (obj) {
            working = true;
            parse_object_file(obj);
            delete obj;
        } else {
            debug(1) << "Could not load object file: " << binary << "\n";
            working = false;
        }

    }

    void calibrate_pc_offset(void (*fn)()) {
        // Calibrate for the offset between the
        // instruction pointers in the debug info and the instruction
        // pointers in the actual file.
        bool found = false;
        int64_t pc_adjust = 0;
        for (size_t i = 0; i < functions.size(); i++) {
            if (functions[i].name == "HalideIntrospectionCanary::offset_marker" &&
                functions[i].pc_begin) {
                uint64_t pc_lo = functions[i].pc_begin;
                uint64_t pc_hi = functions[i].pc_end;
                uint64_t pc = (uint64_t)fn;
                // Find a multiple of 4096 that places pc between pc_lo and pc_hi
                int64_t off = pc - pc_lo;
                off -= off & 0xfff;
                uint64_t pc_adj = pc - off;
                if (pc_lo <= pc_adj &&
                    pc_adj <= pc_hi &&
                    pc_adj + 4096 > pc_hi &&
                    pc_adj - 4096 < pc_lo) {
                    found = true;
                    pc_adjust = off;
                } else {
                    debug(1) << "Found HalideIntrospectionCanary::offset_marker "
                             << "but could not compute a unique offset\n";
                    working = false;
                    return;
                }
            }
        }

        if (!found) {
            debug(1) << "Failed to find HalideIntrospectionCanary::offset_marker\n";
            working = false;
            return;
        }

        debug(4) << "Program counter adjustment between debug info and actual code: " << pc_adjust << "\n";

        for (size_t i = 0; i < functions.size(); i++) {
            functions[i].pc_begin += pc_adjust;
            functions[i].pc_end += pc_adjust;
        }

        for (size_t i = 0; i < source_lines.size(); i++) {
            source_lines[i].pc += pc_adjust;
        }
    }

    // Get the debug name of a stack variable from a pointer to it
    std::string get_variable_name(const void *stack_pointer, const std::string &type_name = "") {

        // Check it's a plausible stack pointer
        int marker = 0;
        uint64_t marker_addr = (uint64_t)&marker;
        uint64_t top_of_stack;
        if (marker_addr >> 63) {
            top_of_stack = (uint64_t)(-1);
        } else {
            // Conservatively assume top of stack is first multiple of
            // 1GB larger than the marker (seriously, who allocates
            // 1GB of stack space?).
            top_of_stack = ((marker_addr >> 30) + 1) << 30;
        }

        if ((uint64_t)stack_pointer > top_of_stack ||
            (uint64_t)stack_pointer < marker_addr) {
            return "";
        }

        // Get the backtrace
        std::vector<void *> trace(1024);
        int trace_size = backtrace(&trace[0], 1024);
        trace.resize(trace_size);

        // OS X with no frame pointer will return a backtrace of size 1 always.
        if (trace.size() <= 2) {
            debug(1) << "backtrace doesn't seem to have many frames\n";
            return "";
        }

        // OS X seems to sometimes dump a sentinel on the end of the
        // backtrace.
        if (trace.back() == (void *)1) {
            trace.pop_back();
        }


        const int addr_size = (int)(sizeof(void *));

        // Begin the search by rounding down the stack pointer to an aligned address
        uint64_t aligned_stack_pointer = (uint64_t)(stack_pointer) & (~(addr_size - 1));

        const void **stack_ptr = (const void **)aligned_stack_pointer;
        // This stack pointer doesn't belong to this function, so there
        // must have been a function call to get here, which means there
        // must be a return address on the stack somewhere down-stack from
        // the pointer.

        // Walk up and down the stack looking for a return address in our backtrace
        const void **stack_frame_top = NULL, **stack_frame_bottom = NULL;
        int frame = 0;
        for (int i = 0; i < 10240 && stack_frame_top == NULL; i++) {

            if ((uint64_t)stack_ptr + i >= top_of_stack ||
                stack_ptr[i] == trace.back()) {
                // Don't walk off the end of the stack.
                break;
            }

            for (int j = 1; j < (int)trace.size() && frame == 0; j++) {
                if (stack_ptr[i] == trace[j]) {
                    stack_frame_top = stack_ptr + i;
                    frame = j;
                }
            }
        }
{'fraction_non_alphanumeric': 0.1097053437656068, 'fraction_numerical': 0.01581488263692359, 'mean_word_length': 1.7563661390227117, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5178388', 'n_tokens_mistral': 3688, 'n_tokens_neox': 3427, 'n_words': 1036}