[llvm] [llubi] Implements common library functions (PR #190147)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 6 09:33:24 PDT 2026
================
@@ -0,0 +1,319 @@
+//===- Library.cpp - Library calls for llubi ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements common libcalls for llubi.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Library.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm::ubi {
+
+static uint64_t getMaxAlign(const DataLayout &DL) {
+ // Return an alignment of 16 for 64-bit platforms, and 8 for 32-bit ones.
+ return DL.getPointerABIAlignment(0).value() >= 8 ? 16 : 8;
+}
+
+Library::Library(Context &Ctx, EventHandler &Handler, const DataLayout &DL,
+ ExecutorBase &Executor)
+ : Ctx(Ctx), Handler(Handler), DL(DL), Executor(Executor) {}
+
+std::optional<std::string> Library::readStringFromMemory(const Pointer &Ptr) {
+ auto *MO = Ptr.getMemoryObject();
+ if (!MO) {
+ Executor.reportImmediateUB(
+ "Invalid memory access via a pointer with nullary "
+ "provenance.");
+ return std::nullopt;
+ }
+
+ std::string Result;
+ const uint64_t Address = Ptr.address().getZExtValue();
+ uint64_t Offset = 0;
+
+ while (true) {
+ auto ValidOffset = Executor.verifyMemAccess(
+ *MO, APInt(DL.getPointerSizeInBits(0), Address + Offset), 1, Align(1),
+ false);
+ if (!ValidOffset)
+ return std::nullopt;
+
+ Byte B = (*MO)[*ValidOffset];
+ if (B.ConcreteMask != 0xFF) {
+ Executor.reportImmediateUB("Read uninitialized or poison memory while "
+ "parsing C-string.");
+ return std::nullopt;
+ }
+
+ if (B.Value == 0)
+ break;
+
+ Result.push_back(static_cast<char>(B.Value));
+ ++Offset;
+ }
+
+ return Result;
+}
+
+AnyValue Library::executeMalloc(StringRef Name, Type *Type,
+ ArrayRef<AnyValue> Args) {
+ const auto &SizeVal = Args[0];
+
+ const uint64_t AllocSize = SizeVal.asInteger().getLimitedValue();
+ const uint64_t MaxAlign = getMaxAlign(DL);
+
+ const auto Obj =
+ Ctx.allocate(AllocSize, MaxAlign, Name, 0, MemInitKind::Uninitialized);
+
+ if (!Obj)
+ return AnyValue::getNullValue(Ctx, Type);
+
+ return Ctx.deriveFromMemoryObject(Obj);
+}
+
+AnyValue Library::executeCalloc(StringRef Name, Type *Type,
+ ArrayRef<AnyValue> Args) {
+ const auto &CountVal = Args[0];
+ const auto &SizeVal = Args[1];
+
+ const uint64_t Count = CountVal.asInteger().getLimitedValue();
+ const uint64_t Size = SizeVal.asInteger().getLimitedValue();
+
+ bool Overflow = false;
+ const uint64_t AllocSize = SaturatingMultiply(Count, Size, &Overflow);
+ if (Overflow)
+ return AnyValue::getNullValue(Ctx, Type);
+
+ const uint64_t MaxAlign = getMaxAlign(DL);
+
+ const auto Obj =
+ Ctx.allocate(AllocSize, MaxAlign, Name, 0, MemInitKind::Zeroed);
+
+ if (!Obj)
+ return AnyValue::getNullValue(Ctx, Type);
+
+ return Ctx.deriveFromMemoryObject(Obj);
+}
+
+AnyValue Library::executeFree(ArrayRef<AnyValue> Args) {
+ const auto &PtrVal = Args[0];
+
+ auto &Ptr = PtrVal.asPointer();
+ // no-op when free is called with a null pointer.
+ if (Ptr.address().isZero())
+ return AnyValue();
+
+ if (!Ctx.free(Ptr.address().getZExtValue())) {
----------------
nikic wrote:
Hm... this isn't right. We should change the Context::free() implementation to not just work on an address. We need to check that the address matches the base address of the MemoryObject and free that MemoryObject. Otherwise free() can free an unrelated object (or via a pointer without provenance).
https://github.com/llvm/llvm-project/pull/190147
More information about the llvm-commits
mailing list