Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
/tests/simple-client/simple-client
/tests/simple-multi-alloc/simple-multi-alloc
/tests/sloppy-dumptypes/sloppy-dumptypes
/tests/cxx-new/cxx-new
/tools/allocsites
/tools/dumptypes
/tools/ifacetypes
Expand Down Expand Up @@ -135,7 +136,11 @@ Makefile.in
/tools/dwarftypes
/tools/extrasyms
/tools/frametypes
/tools/frametypes2
/tools/metavector
/tools/dumpsyscalls
/tools/noopgen
/tools/objdumpallocs

/tests/unit-tests/metavec
/tests/unit-tests/metavec-debug
Expand Down Expand Up @@ -199,3 +204,34 @@ oopsla*.ps

/buildtest/*/Dockerfile
/buildtest/*/Dockerfile.env

# clangd
.cache
compile_commands.json

.vscode

# allocsld build artifacts
*.os
/allocsld/*.map

# LLVM bitcode
*.bc

# liballocs-generated type info
*.usedtypes.c

# standalone allocstubs assembly (not matched by *.allocstubs.s above)
allocstubs.s

# compiled tools
/tools/dwarf-machine-self-test
/tools/lang/c++/bin/clang-ast-parser

# symlinks generated by the build (point into contrib/liballocstool/include)
/include/uniqtype-defs.h
/include/uniqtype.h
/include/malloc-meta.h
/include/pageindex.h

/allocsld/allocsld.h
6 changes: 6 additions & 0 deletions allocsld/allocsld.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef LIBALLOCS_ALLOCSLD_H_
#define LIBALLOCS_ALLOCSLD_H_
#define DT_ALLOCS_BOOTSTRAP_RELA 0x6ffffa01
#define DT_ALLOCS_BOOTSTRAP_RELASZ 0x6ffffa02
#define DT_ALLOCS_BOOTSTRAP_RELAENT 0x6ffffa03
#endif
38 changes: 22 additions & 16 deletions include/malloc-meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,30 @@
#error "Variable size lifetime policies not fully supported yet"
#endif

struct insert_initial {
unsigned char always_0:1;
unsigned long alloc_site:47;
unsigned short unused:12;
unsigned char lifetime_policies:4; // should never be zero (0000 => already freed)
};

struct insert_with_type {
unsigned char always_1:1;
signed short alloc_site_id:15; /* may be zero; -1 means "no/unknown alloc site" */
unsigned long uniqtype_shifted:44; /* uniqtype ptrs are 8-byte-aligned and have top bit 0 => this field is ((unsigned long) u)>>3 */
unsigned char lifetime_policies:4; // should never be zero (0000 => already freed)
};

struct insert_common {
unsigned long _ignore:60;
unsigned char lifetime_policies:4;
};

struct insert {
union {
struct insert_initial {
unsigned char always_0:1;
unsigned long alloc_site:47;
unsigned short unused:12;
unsigned char lifetime_policies:4; // should never be zero (0000 => already freed)
} initial;
struct insert_with_type {
unsigned char always_1:1;
signed short alloc_site_id:15; /* may be zero; -1 means "no/unknown alloc site" */
unsigned long uniqtype_shifted:44; /* uniqtype ptrs are 8-byte-aligned and have top bit 0 => this field is ((unsigned long) u)>>3 */
unsigned char lifetime_policies:4; // should never be zero (0000 => already freed)
} with_type;
struct insert_common {
unsigned long _ignore:60;
unsigned char lifetime_policies:4;
} common;
struct insert_initial initial;
struct insert_with_type with_type;
struct insert_common common;
};
} __attribute((packed));

Expand Down
7 changes: 7 additions & 0 deletions include/pageindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ extern bigalloc_num_t *pageindex __attribute__((weak));
#if defined(__PIC__) || defined(__code_model_large__)
extern bigalloc_num_t *__liballocs_pageindex __attribute__((weak));
#endif
/* Forward-declare the enum so C++ sees a complete-enough type for the return type.
* The enum is defined in the liballocs DSO; we only need the declaration here. */
#ifdef __cplusplus
enum object_memory_kind : int;
#else
enum object_memory_kind; /* GCC extension: incomplete enum forward declaration */
#endif
enum object_memory_kind __liballocs_get_memory_kind(const void *obj) __attribute__((visibility("protected")));

void __liballocs_print_l0_to_stream_err(void);
Expand Down
6 changes: 4 additions & 2 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,12 @@ default:

# generic clean rule that we can run from test dirs too (with $(MAKE) -f ../Makefile)
clean: # (delete anything whose name is a prefix of a .c file's and doesn't contain a dot)
rm -f $(filter-out .,$(foreach pat,% %.o %.allocstubs.o %.allocstubs.c %.linked.o %.s %.i %.cil.s %.cil.i,$(patsubst %.c,$(pat),$(shell find -name '*.c'))))
rm -f $(filter-out .,$(foreach pat,% %.o %.ii %.usedtypes.c %.allocstubs.o %.allocstubs.c %.linked.o %.s %.i %.cil.s %.cil.i,$(patsubst %.c,$(pat),$(shell find -name '*.c'))))
rm -f $(filter-out .,$(foreach pat,% %.o %.ii %.usedtypes.c %.allocstubs.o %.allocstubs.c %.linked.o %.s %.i %.cil.s %.cil.i,$(patsubst %.cpp,$(pat),$(shell find -name '*.cpp'))))
find -name '*.cil.c' -o \
-name '*.allocs' -o -name '*.so' -o -name '*.ltrans.out' -o \
-name '*.allocstubs.c' -o -name '*.fixuplog' | xargs rm -f
-name '*.allocstubs.c' -o -name '*.fixuplog' -o \
-name 'allocstubs.s' -o -name '*.bc' | xargs rm -f

.PHONY: unit-tests
unit-tests:
Expand Down
19 changes: 19 additions & 0 deletions tests/cxx-new/cxx-new.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <allocs.h>
#include <cstdio>

struct Point { int x, y; };

int main() {
Point *p = new Point;
Point *ps = new Point[10];
int *n = new int(42);

printf("p type: %s\n", UNIQTYPE_NAME(__liballocs_get_alloc_type(p)));
printf("ps type: %s\n", UNIQTYPE_NAME(__liballocs_get_alloc_type(ps)));
printf("n type: %s\n", UNIQTYPE_NAME(__liballocs_get_alloc_type(n)));

delete p;
delete[] ps;
delete n;
return 0;
}
11 changes: 11 additions & 0 deletions tests/cxx-new/mk.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CXX := $(LIBALLOCS)/tools/lang/c++/bin/allocsc++
export CXX

CXXFLAGS := $(filter-out -std=c99,$(CFLAGS)) -std=c++17
export CXXFLAGS

LDLIBS += -lallocs

cxx-new: cxx-new.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)

2 changes: 2 additions & 0 deletions tools/compilerwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ def printErrors(self, errfile):

# also the items themselves -- could be strings or SourceFiles
phaseItems = [[] for n in range(Phase.DRIVER, 1+Phase.LINK)]

phases = []

# keep a map of all source files (not items; excluding linker inputs), indexed by position
allSourceFiles = dict({})
Expand Down
6 changes: 6 additions & 0 deletions tools/gather-srcallocs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ cat "$all_obj_allocs_file" | cut -f1 | sort | uniq | while read obj rest; do
(1|2|12|29) # DW_LANG_C89, DW_LANG_C, DW_LANG_C99, DW_LANG_C11
$(dirname "$0")/lang/c/bin/c-"$our_name_rewritten" "$cu_sourcepath" "$obj" "$cu_fname" "$cu_compdir"
;;
(4|26|33|34|43|44) # DW_LANG_C_plus_plus, DW_LANG_C_plus_plus_03,
# DW_LANG_C_plus_plus_11, DW_LANG_C_plus_plus_14
# DW_LANG_C_plus_plus_17, DW_LANG_C_plus_plus_20
$(dirname "$0")/lang/c++/bin/c++-"$our_name_rewritten" \
"$cu_sourcepath" "$obj" "$cu_fname" "$cu_compdir"
;;
(*) # unknown
echo "Warning: could not gather source-level allocs for unknown language: $cu_language_fullstr ($cu_language_num, $( echo -n "$cu_language_fullstr" | hd ))" 1>&2
;;
Expand Down
22 changes: 22 additions & 0 deletions tools/lang/c++/bin/c++-gather-srcallocs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

cu_sourcepath="$1"
obj="$2"
cu_fname="$3"
cu_compdir="$4"

# Map foo.cpp / foo.cc / foo.C / foo.cxx -> foo.i.allocs
# links all c++ related files to *.i.allocs
cu_allocspath="$( echo "$cu_sourcepath" | \
sed 's/\.\(cpp\|cc\|cxx\|C\|c++\)$/.i.allocs/' )"

if [[ "$cu_allocspath" == "$cu_sourcepath" ]]; then
echo "Warning: unrecognised C++ source extension in $cu_sourcepath" 1>&2
exit 0
fi

if [[ ! -r "$cu_allocspath" ]]; then
echo "Warning: missing expected allocs file ($cu_allocspath)" 1>&2
else
cat "$cu_allocspath"
fi
53 changes: 53 additions & 0 deletions tools/lang/c++/clang-ast-parser/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
CXX = g++

LLVM_CXXFLAGS = $(shell llvm-config-20 --cxxflags)
LLVM_LDFLAGS = $(shell llvm-config-20 --ldflags)
LLVM_LIBS = $(shell llvm-config-20 --libs --system-libs --link-static)


# 1. Get the full paths
# 2. Use 'basename' to get just the filename (e.g., libclangBasic.a)
# 3. Use 'sed' to strip the 'lib' prefix and '.a' suffix
CLANG_LIBS = $(shell ls /usr/lib/llvm-20/lib/libclang*.a | xargs -n1 basename | sed 's/^lib\(.*\)\.a/-l\1/')

CXXFLAGS = -std=c++17 -g $(LLVM_CXXFLAGS) -Iinclude

BIN = ../bin
SRC = src
BUILD = build
TARGET = $(BIN)/clang-ast-parser

SRCS = $(shell find $(SRC) -name *.cpp)
OBJS = $(subst $(SRC)/,$(BUILD)/,$(addsuffix .o,$(basename $(SRCS))))

default: ../bin/clang-ast-parser

$(BUILD)/%.o: $(SRC)/%.cpp
mkdir -p $(dir $@)
${CXX} ${CXXFLAGS} -c $< -o $@

$(TARGET): $(OBJS)
mkdir -p $(dir $@)
${CXX} ${CXXFLAGS} $(OBJS) -o $@ ${LLVM_LDFLAGS} \
-Wl,--start-group ${CLANG_LIBS} ${LLVM_LIBS} -Wl,--end-group

clang-ast-parser.o: clang-ast-parser.cpp
${CXX} ${CXXFLAGS} -c clang-ast-parser.cpp -o clang-ast-parser.o

# Group is used to tell linker to search repeatedly within the group
clang-ast-parser: clang-ast-parser.o
${CXX} ${CXXFLAGS} clang-ast-parser.o -o clang-ast-parser ${LLVM_LDFLAGS} \
-Wl,--start-group ${CLANG_LIBS} ${LLVM_LIBS} -Wl,--end-group

clean:
rm -rf build
rm -f $(TARGET)

dep:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20
rm llvm.sh
sudo apt update
sudo apt install libclang-20-dev llvm-20-dev libpolly-20-dev libisl-dev libzstd-dev

77 changes: 77 additions & 0 deletions tools/lang/c++/clang-ast-parser/src/clang-ast-parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "llvm/Support/CommandLine.h"
#include "uniqtype-name.h"

using namespace clang;
using namespace clang::tooling;
using namespace llvm;

static cl::OptionCategory MyToolCategory("my-tool-options");

class NewDetectorVisitor : public RecursiveASTVisitor<NewDetectorVisitor> {
public:
explicit NewDetectorVisitor(ASTContext *Context, std::shared_ptr<raw_fd_ostream> outStream) : Context(Context), OutStream(outStream) {}

bool VisitCXXNewExpr(CXXNewExpr *E) {
// skip placement operator
if(E->getNumPlacementArgs() > 0) return true;

FullSourceLoc FullLocation = Context->getFullLoc(E->getBeginLoc());
if (FullLocation.isValid()) {
std::string TypeName = E->getAllocatedType().getAsString();
*OutStream << FullLocation.getFileEntry()->tryGetRealPathName() << "\t"
<< FullLocation.getSpellingLineNumber() << "\t"
<< FullLocation.getSpellingColumnNumber() << "\t"
<< "new" << "\t"
<< uniqtypeNameFromClangType(E->getAllocatedType(), Context) << "\t"
<< (E->isArray() ? "1": "0") << "\n";
}
return true;
}

private:
ASTContext *Context;
std::shared_ptr<raw_fd_ostream> OutStream;
};

class NewDetectorConsumer : public ASTConsumer {
public:
explicit NewDetectorConsumer(ASTContext *Context, std::shared_ptr<raw_fd_ostream> outStream) : Visitor(Context, outStream) {}
void HandleTranslationUnit(ASTContext &Context) override {
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
}
private:
NewDetectorVisitor Visitor;
};

class NewDetectorAction : public ASTFrontendAction {
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) override {
// *.cpp -> *.i.allocs
SmallString<256> outPath(file);
sys::path::replace_extension(outPath, "");
std::string outputPath = std::string(outPath) + ".i.allocs";
std::error_code ec;
auto outStream = std::make_shared<raw_fd_ostream>(outputPath, ec);
return std::make_unique<NewDetectorConsumer>(&CI.getASTContext(), std::move(outStream));
}
};

int main(int argc, const char **argv) {
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);

if (!ExpectedParser) {
errs() << ExpectedParser.takeError();
return 1;
}

CommonOptionsParser& OptionsParser = ExpectedParser.get();
ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());

return Tool.run(newFrontendActionFactory<NewDetectorAction>().get());
}
33 changes: 33 additions & 0 deletions tools/lang/c++/clang-ast-parser/src/uniqtype-name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"

using namespace clang;

std::string uniqtypeNameFromClangType(QualType qt, ASTContext *ctx) {
const Type *T = qt.getTypePtr();

// For records (struct/class): use tag name
if (const RecordType *RT = T->getAs<RecordType>()) {
std::string name = RT->getDecl()->getNameAsString();
if (!name.empty()) return "__uniqtype__" + name;
}

// For built-in types: use canonical name + bit width
if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
uint64_t bits = ctx->getTypeSize(qt);
std::string canonName = BT->getName(ctx->getPrintingPolicy()).str();
// Map to DWARF canonical name (e.g. "int" → "int", "char" → "signed char")
return "__uniqtype__" + canonName + "$$" + std::to_string(bits);
}

// Pointer types
if (T->isPointerType()) {
QualType pointee = T->getPointeeType();
return "__uniqtype____PTR_" + uniqtypeNameFromClangType(pointee, ctx);
}

// Unknown / too complex — fall back to uninterpreted byte
return "__uniqtype____uninterpreted_byte";
}

11 changes: 11 additions & 0 deletions tools/lang/c++/clang-ast-parser/src/uniqtype-name.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef UNIQTYPE_NAME_H

#define UNIQTYPE_NAME_H

#include "clang/AST/Type.h"
#include <string>

std::string uniqtypeNameFromClangType(clang::QualType qt, clang::ASTContext *ctx);

#endif

Loading