Files
RedBear-OS/local/recipes/dev/libclc/source/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

239 lines
9.1 KiB
C++

//===---DynamicValueObjectLocalBuffer.cpp-----------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/Symbol/ClangTestUtils.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/ValueObject/ValueObjectConstResult.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::clang_utils;
// This entire class is boilerplate.
struct MockLanguage : public Language {
llvm::StringRef GetPluginName() override { return "MockLanguage"; }
lldb::LanguageType GetLanguageType() const override {
return lldb::eLanguageTypeC_plus_plus;
};
static Language *CreateInstance(lldb::LanguageType language) {
return new MockLanguage();
}
static void Initialize() {
PluginManager::RegisterPlugin("MockLanguage", "Mock Language",
CreateInstance);
};
static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
bool IsSourceFile(llvm::StringRef file_path) const override { return true; }
};
LLDB_PLUGIN_DEFINE(MockLanguage)
struct MockLanguageRuntime : public LanguageRuntime {
// This is the only method in this class that matters for this test.
// This will unconditionally succeed and return a type with size 4,
// a value_type of HostAddress, and a local buffer that points to the parent's
// local buffer.
// The tests will set that buffer to be either be larger or smaller than the
// type we're returning.
bool
GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override {
auto ast = in_value.GetCompilerType().GetTypeSystem<TypeSystemClang>();
auto int_type = createRecordWithField(
*ast, "TypeWitInt", ast->GetBasicType(lldb::BasicType::eBasicTypeInt),
"theIntField", LanguageType::eLanguageTypeC_plus_plus);
class_type_or_name.SetCompilerType(int_type);
local_buffer = in_value.GetLocalBuffer();
value_type = Value::ValueType::HostAddress;
return true;
}
// All of this is boilerplate.
MockLanguageRuntime(Process *process) : LanguageRuntime(process) {}
llvm::StringRef GetPluginName() override { return "MockLanguageRuntime"; }
lldb::LanguageType GetLanguageType() const override {
return lldb::eLanguageTypeC_plus_plus;
}
llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override {
return llvm::Error::success();
}
llvm::Error GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override {
return llvm::Error::success();
}
bool CouldHaveDynamicValue(ValueObject &in_value) override { return true; }
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override {
return type_and_or_name;
}
lldb::BreakpointResolverSP
CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
bool throw_bp) override {
return lldb::BreakpointResolverSP();
}
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
bool stop_others) override {
return {};
}
static LanguageRuntime *CreateInstance(Process *process,
LanguageType language) {
return new MockLanguageRuntime(process);
}
static void Initialize() {
PluginManager::RegisterPlugin(
"MockLanguageRuntime", "MockLanguageRuntime", CreateInstance,
[](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
return {};
},
[](lldb::LanguageType language,
bool throw_bp) -> BreakpointPreconditionSP { return {}; });
}
static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
};
LLDB_PLUGIN_DEFINE(MockLanguageRuntime)
// This entire class is boilerplate.
struct MockProcess : Process {
MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
: Process(target_sp, listener_sp) {}
llvm::StringRef GetPluginName() override { return "mock process"; }
bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
return false;
};
Status DoDestroy() override { return {}; }
void RefreshStateAfterStop() override {}
bool DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override {
return false;
};
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error) override {
// No need to read memory in these tests.
return size;
}
};
class DynamicValueObjectLocalBufferTest : public ::testing::Test {
public:
void SetUp() override {
ArchSpec arch("i386-pc-linux");
Platform::SetHostPlatform(
platform_linux::PlatformLinux::CreateInstance(true, &arch));
// std::call_once(TestUtilities::g_debugger_initialize_flag,
// []() { Debugger::Initialize(nullptr); });
m_debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(m_debugger_sp);
m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
eLoadDependentsNo,
m_platform_sp, m_target_sp);
ASSERT_TRUE(m_target_sp);
ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
ASSERT_TRUE(m_platform_sp);
m_listener_sp = Listener::MakeListener("dummy");
m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
ASSERT_TRUE(m_process_sp);
m_exe_ctx = ExecutionContext(m_process_sp);
m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
m_type_system = m_holder->GetAST();
LLDB_PLUGIN_INITIALIZE(MockLanguage);
LLDB_PLUGIN_INITIALIZE(MockLanguageRuntime);
}
void TearDown() override {
LLDB_PLUGIN_TERMINATE(MockLanguage);
LLDB_PLUGIN_TERMINATE(MockLanguageRuntime);
}
void TestValueObjectWithLocalBuffer(DataExtractor &data_extractor,
bool should_succeed) {
std::unique_ptr<TypeSystemClangHolder> holder =
std::make_unique<TypeSystemClangHolder>("test ASTContext");
TypeSystemClang *ast = holder->GetAST();
auto char_type = createRecordWithField(
*ast, "TypeWithChar",
ast->GetBasicType(lldb::BasicType::eBasicTypeChar), "theField");
ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
ConstString var_name("test_var");
auto valobj_sp = ValueObjectConstResult::Create(exe_scope, char_type,
var_name, data_extractor);
auto dyn_valobj = valobj_sp->GetDynamicValue(lldb::eDynamicCanRunTarget);
ASSERT_TRUE(dyn_valobj->GetValueIsValid() == should_succeed);
}
SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux,
ScriptInterpreterNone>
m_subsystems;
std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
lldb::DebuggerSP m_debugger_sp;
lldb::TargetSP m_target_sp;
lldb::PlatformSP m_platform_sp;
lldb::ListenerSP m_listener_sp;
lldb::ProcessSP m_process_sp;
ExecutionContext m_exe_ctx;
TypeSystemClang *m_type_system;
};
TEST_F(DynamicValueObjectLocalBufferTest, BufferTooSmall) {
/// Test that a value object with a buffer to small to fit the
/// "dynamic" type will return an invalid dynamic value object.
uint8_t value = 1;
ByteOrder endian = endian::InlHostByteOrder();
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
TestValueObjectWithLocalBuffer(data_extractor, false);
}
TEST_F(DynamicValueObjectLocalBufferTest, BufferTooBig) {
/// Test that a value object with a buffer big enough fit the
/// "dynamic" type will return a valid dynamic value object.
uint64_t value = 1;
ByteOrder endian = endian::InlHostByteOrder();
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
TestValueObjectWithLocalBuffer(data_extractor, true);
}
TEST_F(DynamicValueObjectLocalBufferTest, BufferExactlyRight) {
/// Test that a value object with a buffer exactly the size of the
/// "dynamic" type will return a valid dynamic value object.
uint32_t value = 1;
ByteOrder endian = endian::InlHostByteOrder();
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
TestValueObjectWithLocalBuffer(data_extractor, true);
}