mirror of
https://github.com/radareorg/r2xsql.git
synced 2026-11-08 01:06:22 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e84eb2ae5 |
No files matched your search
+10
-5
@@ -1245,7 +1245,7 @@ its own, the identical trade-off `rop_gadgets` already made for its own
|
||||
libr).
|
||||
|
||||
#### `demangle` (read-only)
|
||||
One row per query: demangles an ARBITRARY mangled name via `r_bin_demangle`.
|
||||
One row per query: demangles an ARBITRARY mangled name via `iD`/`iDj`.
|
||||
Distinct from `funcs.name`/`imports.name`, which already demangle
|
||||
automatically (gated on `bin.demangle`) for symbols radare2 already knows
|
||||
from the loaded binary — `demangle` answers the same question for a string
|
||||
@@ -1269,10 +1269,15 @@ what `lang` says — verified live that an unrecognized `lang` string does not
|
||||
abort demangling, it just falls through to auto-detection. `mangled` is NOT
|
||||
charset-restricted the way `assemble`/`search_asm`'s `asm` is: MSVC manglings
|
||||
use `?`/`@`/`$` throughout, which a disassembly-text allowlist would reject.
|
||||
The in-process backend passes the mangled name directly to `r_bin_demangle`,
|
||||
with the current `RBinFile` and `bin.lang` default. This preserves arbitrary
|
||||
input without command parsing. A backend without an in-process RBin API
|
||||
reports an error for this table.
|
||||
Instead this table dispatches through `Backend::cmd_noeval`, seeked to a
|
||||
fixed anchor (0, unobserved by `iD`'s handler either way — same shape as
|
||||
`types`' addr-less `td`/`t-` dispatch), falling back to the
|
||||
`json_utils::r2_quote`-wrapped plain command on every backend that reports
|
||||
cmd_noeval unsupported. Verified live that the injection risk is real: `iDj
|
||||
cxx foo; ?e INJECTED` spliced through a plain `Backend::cmd()` call DOES
|
||||
execute the injected `?e` as a second command, while `cmd_noeval` reaches
|
||||
`iD`'s argument parser with the whole string, `;` included, treated as
|
||||
opaque data.
|
||||
|
||||
#### Point-lookup recipes: `name_at` / `section_at` / `string_at`
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
// That TU boundary is what forces the row struct out of its table's anonymous
|
||||
// namespace and into this header: a row struct lives beside its table until the
|
||||
// table is ported, and moves here when a second TU has to build it.
|
||||
// The demangle method also uses this boundary so arbitrary symbol text reaches
|
||||
// RBin directly, without passing through the r2 command parser.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -510,11 +508,6 @@ class Api {
|
||||
virtual void binary_info(std::vector<BinaryRow>& out) = 0;
|
||||
virtual std::string file_path() = 0;
|
||||
virtual std::string engine_version() = 0;
|
||||
// Demangle an arbitrary symbol using the current RBinFile and bin.lang
|
||||
// setting. Empty result means radare2 could not demangle the name; error
|
||||
// receives the same diagnostic as iDj in that case.
|
||||
virtual std::string demangle(const std::string& mangled,
|
||||
const std::string& lang, std::string& error) = 0;
|
||||
virtual bool entry_address(int64_t& out) = 0;
|
||||
virtual void relocs_scan(std::vector<RelocRow>& out) = 0;
|
||||
virtual void type_members_scan(std::vector<MemberRow>& out) = 0;
|
||||
|
||||
@@ -121,29 +121,6 @@ class LibrApi : public Api {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string demangle(const std::string& mangled,
|
||||
const std::string& lang, std::string& error) override {
|
||||
std::lock_guard lock(mu_);
|
||||
error = "Cannot demangle string";
|
||||
if (!core_ || !core_->bin) return {};
|
||||
const char* selected_lang = lang.empty()
|
||||
? r_config_get(core_->config, "bin.lang") : lang.c_str();
|
||||
if ((!selected_lang || !*selected_lang) && lang.empty()) {
|
||||
error = "Set the language in `e bin.lang` or pass a second argument";
|
||||
}
|
||||
RBinFile temporary_file = {};
|
||||
RBinFile* file = core_->bin->cur;
|
||||
if (!file) {
|
||||
temporary_file.rbin = core_->bin;
|
||||
file = &temporary_file;
|
||||
}
|
||||
char* result = r_bin_demangle(file, selected_lang, mangled.c_str(), 0, false);
|
||||
if (!result) return {};
|
||||
std::string demangled(result);
|
||||
free(result);
|
||||
return demangled;
|
||||
}
|
||||
|
||||
bool function_is_start(int64_t addr) override {
|
||||
std::lock_guard lock(mu_);
|
||||
return core_ && core_->anal &&
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// This file is licensed under the Human-Origin Source License v1.0.
|
||||
// See LICENSE.
|
||||
#include "json_utils.hpp"
|
||||
#include <r_util.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
@@ -56,18 +57,24 @@ bool boolean(const nlohmann::json& obj, std::string_view key, bool dflt) {
|
||||
return dflt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool valid_flag_name(std::string_view name) {
|
||||
if (name.empty()) return false;
|
||||
for (unsigned char c : name) {
|
||||
const bool ok = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$';
|
||||
if (!ok) return false;
|
||||
std::string r2_quote(std::string_view s) {
|
||||
std::string out;
|
||||
out.reserve(s.size() + 2);
|
||||
out.push_back('"');
|
||||
for (char c : s) {
|
||||
switch (c) {
|
||||
case '\\': out += "\\\\"; break;
|
||||
case '"': out += "\\\""; break;
|
||||
case '\n': out += "\\n"; break;
|
||||
case '\r': out += "\\r"; break;
|
||||
default: out.push_back(c);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
out.push_back('"');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
bool valid_type_text(std::string_view type) {
|
||||
if (type.empty()) return false;
|
||||
for (unsigned char c : type) {
|
||||
|
||||
@@ -31,14 +31,9 @@ int64_t i64_addr(const nlohmann::json& obj, int64_t dflt = 0);
|
||||
|
||||
// Quote a string for use as a shell-ish r2 command argument. r2 itself is
|
||||
// not a shell, but spaces, quotes and backslashes need escaping in CC args.
|
||||
std::string r2_quote(std::string_view s);
|
||||
|
||||
|
||||
// True iff `name` is safe to splice into an r2 flag command unquoted: a
|
||||
// non-empty string of [A-Za-z0-9._$] only. This is roughly r2's own flag-name
|
||||
// charset; rejecting anything else prevents a name with spaces or command
|
||||
// separators (`;`, `@`, `|`, backtick, …) from breaking parsing or injecting
|
||||
// extra r2 commands. Use to gate INSERT/UPDATE on the flags/bookmarks tables.
|
||||
bool valid_flag_name(std::string_view name);
|
||||
|
||||
// True iff `type` is a safe C type string to splice into an r2 `afvt` command
|
||||
// unquoted: a non-empty string of type-syntax characters only —
|
||||
|
||||
@@ -59,7 +59,7 @@ void register_class_methods_table(Session& s);
|
||||
void register_registers_table(Session& s); // static per-arch register profile (arpj)
|
||||
void register_relocs_table(Session& s); // relocation table (irj)
|
||||
void register_libs_table(Session& s); // linked library list (ilj)
|
||||
void register_demangle_table(Session& s); // one-row RBin demangler
|
||||
void register_demangle_table(Session& s); // one-row demangler (iD/iDj)
|
||||
void register_assemble_table(Session& s); // one-row assembler (pa)
|
||||
void register_search_asm_table(Session& s); // assemble-then-search (/a)
|
||||
void register_read_cstr_table(Session& s); // arbitrary-address cstring read (pszj)
|
||||
|
||||
@@ -126,7 +126,7 @@ void register_bookmarks_table(Session& s) {
|
||||
[](const BookmarkRow& r) { return r.name; },
|
||||
[be = s.backend_ptr()](BookmarkRow& r, const char* v) -> bool {
|
||||
if (!v || !*v) return false;
|
||||
if (!json_utils::valid_flag_name(v)) {
|
||||
if (!r_name_check(v.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"bookmarks: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
@@ -180,7 +180,7 @@ void register_bookmarks_table(Session& s) {
|
||||
xsql::set_vtab_error("bookmarks: INSERT requires a non-empty name");
|
||||
return false;
|
||||
}
|
||||
if (!json_utils::valid_flag_name(name)) {
|
||||
if (!r_name_check(name.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"bookmarks: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
|
||||
@@ -4,25 +4,93 @@
|
||||
// This file is licensed under the Human-Origin Source License v1.0.
|
||||
// See LICENSE.
|
||||
//
|
||||
// demangle -- one row for an arbitrary mangled name. Demangling always uses
|
||||
// r_bin_demangle through the in-process direct::Api.
|
||||
// demangle -- one-row-per-query demangler over radare2's `iD`/`iDj` (verified
|
||||
// against the CURRENT radare2 source, `libr/core/cmd_info.inc.c`'s
|
||||
// `cmd_info_demangle` + `libr/bin/demangle.c`'s `r_bin_demangle`/
|
||||
// `r_bin_demangle_type`, not assumed from a citation). This closes a REAL
|
||||
// gap: `funcs.name` and `imports.name` already demangle automatically (via
|
||||
// `r_core_anal_fcn_name`/`r_bin_demangle` respectively, gated on the
|
||||
// `bin.demangle` config) for symbols radare2 already knows about from the
|
||||
// loaded binary, but there was no SQL surface to demangle an ARBITRARY
|
||||
// string that isn't necessarily any table's row.
|
||||
//
|
||||
// The `mangled` hidden input is NOT charset-restricted the way
|
||||
// `assemble`/`search_asm`'s `asm` input is (see tables_assemble.cpp):
|
||||
// real-world manglings routinely use characters a disassembly-text
|
||||
// allowlist would reject -- MSVC uses `?`/`@`/`$` throughout
|
||||
// (`?foo@@YAHXZ`), Rust and Itanium C++ use `$`-escaped substitutions
|
||||
// heavily. So this table uses the SAME structural no-eval dispatch
|
||||
// (Backend::cmd_noeval) `types`' `td` already pilots
|
||||
// for an addr-less command with a genuinely unrestrictable free-text
|
||||
// argument -- verified live (not assumed) that the injection risk is real:
|
||||
// `iDj cxx foo; ?e INJECTED` through a plain `Backend::cmd()` splice DOES
|
||||
// execute the injected `?e` as a second command (radare2's own `;`
|
||||
// chaining), while `cmd_noeval` reaches `iD`'s single argument parser with
|
||||
// the whole string, `;` included, treated as opaque data.
|
||||
//
|
||||
// `iD`/`iDj` carries no address in its own grammar at all (same shape as
|
||||
// `td`/`t-`), so this dispatches seeked to a fixed anchor (0, same constant
|
||||
// choice as `table_utils::kTypeSystemAnchorAddr` -- kept as a small local
|
||||
// copy rather than reusing that name directly, since this table has nothing
|
||||
// to do with the type system; the anchor value is arbitrary and unobserved
|
||||
// by `iD`'s handler either way, verified against `cmd_info_demangle`, which
|
||||
// reads only its own `lang`/`text` arguments, never `core->addr`).
|
||||
//
|
||||
// `lang` is passed through UNVALIDATED against radare2's own known-language
|
||||
// list: verified live that `r_bin_demangle_type()` returning
|
||||
// `R_BIN_LANG_NONE` for an unrecognized string does NOT abort the call --
|
||||
// `cmd_info_demangle` still invokes `r_bin_demangle(bf, lang, text, ...)`,
|
||||
// which runs its OWN auto-detection from the mangled text's prefix
|
||||
// (`_Z`/`__Z`/`?`/...) regardless of what `lang` said. So a caller-supplied
|
||||
// `lang` is always advisory, never validated client-side to match; this
|
||||
// table simply forwards it and lets radare2 do what it already does.
|
||||
//
|
||||
// `iDj`'s own JSON always echoes `lang` back VERBATIM (the input string,
|
||||
// not radare2's actually-auto-detected type) -- confirmed live with
|
||||
// `iDj bogus _ZN3Foo3barEv`, which still demangled successfully via
|
||||
// auto-detection while echoing `"lang":"bogus"`. This table does not
|
||||
// surface that echo at all (mangled/lang are pure hidden inputs, never
|
||||
// duplicated as output columns, matching byte_search's own
|
||||
// pattern-is-hidden-only convention) precisely to avoid presenting that
|
||||
// potentially-misleading echo as if it were the resolved demangler.
|
||||
//
|
||||
// No JSON mode exists for the empty-`text` or unparseable-argument cases
|
||||
// either -- `iDj` still emits a well-formed `{"lang":...,"mangled":...,
|
||||
// "error":"..."}` object in every failure mode exercised (empty text,
|
||||
// non-mangled text, unrecognized lang), so `error` is always populated
|
||||
// exactly when `demangled` is not, with no separate "malformed command"
|
||||
// case to handle.
|
||||
//
|
||||
// Command-path-only, no C-API producer: a single demangle call has no N+1
|
||||
// or full-scan cost shape to collapse (same "one full-scan-equivalent
|
||||
// command, no per-row cost" reasoning `bininfo`/`rop_gadgets` already
|
||||
// documented for themselves), so both backends share the identical
|
||||
// command-based implementation and cannot disagree.
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <r2xsql/session.hpp>
|
||||
#include <r2xsql/backend.hpp>
|
||||
#include <xsql/vtable.hpp>
|
||||
|
||||
#include "tables.hpp"
|
||||
#include "direct.hpp"
|
||||
#include "json_utils.hpp"
|
||||
#include "table_utils.hpp"
|
||||
|
||||
namespace r2xsql {
|
||||
|
||||
namespace {
|
||||
|
||||
// Arbitrary, unobserved by `iD`'s handler (see file header) -- kept as a
|
||||
// small local constant rather than reusing table_utils::kTypeSystemAnchorAddr
|
||||
// so this table reads as self-contained, not borrowed from the type system.
|
||||
constexpr int64_t kDemangleAnchorAddr = 0;
|
||||
|
||||
struct DemangleRow {
|
||||
std::string demangled; // empty iff demangling failed (never a legitimate
|
||||
// empty symbol name)
|
||||
@@ -31,6 +99,18 @@ struct DemangleRow {
|
||||
|
||||
enum Col { kDemangled = 0, kError = 1, kMangled = 2, kLang = 3 };
|
||||
|
||||
// Seeked-to-a-fixed-anchor no-eval dispatch for `iDj`, mirroring
|
||||
// table_utils::dispatch_type_write's shape exactly (try cmd_noeval first,
|
||||
// fall back to the r2_quote-wrapped plain command on every backend that
|
||||
// reports it unsupported) -- a local copy, not a shared call, since this
|
||||
// table's anchor and command shape are its own (see file header).
|
||||
std::string dispatch_demangle(Backend* be, const std::string& noeval_command,
|
||||
const std::string& fallback_command) {
|
||||
std::string out;
|
||||
if (be->cmd_noeval(kDemangleAnchorAddr, noeval_command, &out)) return out;
|
||||
return be->cmd(fallback_command);
|
||||
}
|
||||
|
||||
DemangleRow run_demangle(Backend* be, const std::string& mangled,
|
||||
const std::string& lang) {
|
||||
DemangleRow row;
|
||||
@@ -38,13 +118,31 @@ DemangleRow run_demangle(Backend* be, const std::string& mangled,
|
||||
row.error = "demangle: mangled must not be empty";
|
||||
return row;
|
||||
}
|
||||
auto* api = be->direct();
|
||||
if (!api) {
|
||||
row.error = "demangle requires the in-process libr backend";
|
||||
// Two-arg form when lang is given ("iDj <lang> <mangled>"), single-arg
|
||||
// form otherwise ("iDj <mangled>", radare2 defaults lang from its own
|
||||
// bin.lang config) -- matches iD's own grammar (see file header); this
|
||||
// table never synthesizes a placeholder lang token to keep the shapes
|
||||
// separate, since args="" lang would misparse a mangled name containing
|
||||
// its own leading space.
|
||||
const std::string plain =
|
||||
lang.empty() ? ("iDj " + mangled) : ("iDj " + lang + " " + mangled);
|
||||
const std::string out = dispatch_demangle(be, plain, json_utils::r2_quote(plain));
|
||||
|
||||
nlohmann::json j = nlohmann::json::parse(out, nullptr, false);
|
||||
if (j.is_discarded() || !j.is_object()) {
|
||||
row.error = "demangle: radare2 returned no result (iDj produced no "
|
||||
"parseable output)";
|
||||
return row;
|
||||
}
|
||||
row.demangled = api->demangle(mangled, lang, row.error);
|
||||
if (!row.demangled.empty()) row.error.clear();
|
||||
if (j.contains("error") && j["error"].is_string()) {
|
||||
row.error = j["error"].get<std::string>();
|
||||
return row;
|
||||
}
|
||||
row.demangled = json_utils::str(j, "demangled");
|
||||
if (row.demangled.empty()) {
|
||||
row.error = "demangle: radare2 produced neither a demangled name nor an "
|
||||
"error (unexpected iDj shape)";
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ void build_flags(Backend* be, std::vector<FlagRow>& rows) {
|
||||
const std::string name = json_utils::str(sp, "name");
|
||||
// A space name is spliced into a command, so it gets the same charset gate
|
||||
// as every other name this project sends to radare2.
|
||||
if (name.empty() || !json_utils::valid_flag_name(name)) continue;
|
||||
if (name.empty() || !r_name_check(name.c_str())) continue;
|
||||
if (json_utils::i64(sp, "count") == 0) continue; // nothing to attribute
|
||||
|
||||
// One command, not three: selecting a flagspace is session state, so the
|
||||
@@ -163,7 +163,7 @@ void register_flags_table(Session& s) {
|
||||
[](const FlagRow& r) { return r.name; },
|
||||
[be = s.backend_ptr()](FlagRow& r, const char* v) -> bool {
|
||||
if (!v || !*v) return false;
|
||||
if (!json_utils::valid_flag_name(v)) {
|
||||
if (!r_name_check(v.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"flags: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
@@ -260,7 +260,7 @@ void register_flags_table(Session& s) {
|
||||
xsql::set_vtab_error("flags: INSERT requires a non-empty name");
|
||||
return false;
|
||||
}
|
||||
if (!json_utils::valid_flag_name(name)) {
|
||||
if (!r_name_check(name.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"flags: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// radare2's own command handler, seeked to the target address, called
|
||||
// directly without evaluating its command-chaining grammar (`;`/`@`/`|`/
|
||||
// backtick) at all. This is an ADDITIONAL layer alongside this table's
|
||||
// existing grammar/value validation (`valid_flag_name`, `valid_c_signature`,
|
||||
// existing grammar/value validation (`r_name_check`, `valid_c_signature`,
|
||||
// the `calling_convention_exists` check on `calltype`) — none replaces the
|
||||
// others. On every other backend (r2pipe, mock) cmd_noeval reports
|
||||
// unsupported and the exact same `cmd()` + spliced `@ <addr>` string this
|
||||
@@ -218,7 +218,7 @@ void register_funcs_table(Session& s) {
|
||||
[](const FuncRow& r) { return r.name; },
|
||||
[be = s.backend_ptr()](FuncRow& r, const char* v) -> bool {
|
||||
if (!v || !*v) return false;
|
||||
if (!json_utils::valid_flag_name(v)) {
|
||||
if (!r_name_check(v.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"funcs: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
@@ -371,7 +371,7 @@ void register_funcs_table(Session& s) {
|
||||
// Optional best-effort naming; a failed afn does not undo the af above.
|
||||
if (argc > 1 && !argv[1].is_null()) {
|
||||
const char* name = argv[1].as_c_str();
|
||||
if (name && *name && json_utils::valid_flag_name(name)) {
|
||||
if (name && *name && r_name_check(name.c_str())) {
|
||||
(void)dispatch_write(be, addr, std::string("afn ") + name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ void register_io_maps_table(Session& s) {
|
||||
std::string name;
|
||||
if (argc > 3 && !argv[3].is_null()) {
|
||||
name = argv[3].as_c_str();
|
||||
if (!name.empty() && !json_utils::valid_flag_name(name.c_str())) {
|
||||
if (!name.empty() && !r_name_check(name.c_str())) {
|
||||
xsql::set_vtab_error("io_maps: name must be [A-Za-z0-9._$] (no spaces)");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
// `dispatch_write(be, addr, command)` helper every sibling write-capable
|
||||
// table (`comments`, `funcs`, `flags`, `bookmarks`, `types`, `patches`)
|
||||
// already uses. This is an ADDITIONAL layer alongside this table's existing
|
||||
// grammar validation (`valid_flag_name`/`valid_type_text`), never a
|
||||
// grammar validation (`r_name_check`/`valid_type_text`), never a
|
||||
// replacement for it. On the r2pipe backend, `cmd_noeval` reports unsupported
|
||||
// and the exact `afvn`/`afvt` command text this table always issued runs
|
||||
// unchanged.
|
||||
@@ -191,12 +191,12 @@ void register_locals_table(Session& s) {
|
||||
[](const LocalRow& r) { return r.name; },
|
||||
[be = s.backend_ptr()](LocalRow& r, const char* v) -> bool {
|
||||
if (!v || !*v) return false;
|
||||
if (!json_utils::valid_flag_name(v)) {
|
||||
if (!r_name_check(v.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"locals: name must be [A-Za-z0-9._$] (no spaces or r2 metacharacters)");
|
||||
return false;
|
||||
}
|
||||
if (!json_utils::valid_flag_name(r.name)) {
|
||||
if (!r_name_check(r.name.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"locals: existing name contains r2 command metacharacters");
|
||||
return false;
|
||||
@@ -245,7 +245,7 @@ void register_locals_table(Session& s) {
|
||||
"locals: type contains an r2 metacharacter (@ ; | ` \" $ etc.)");
|
||||
return false;
|
||||
}
|
||||
if (!json_utils::valid_flag_name(r.name)) {
|
||||
if (!r_name_check(r.name.c_str())) {
|
||||
xsql::set_vtab_error(
|
||||
"locals: existing name contains r2 command metacharacters");
|
||||
return false;
|
||||
|
||||
@@ -42,7 +42,7 @@ void register_projects_table(Session& s) {
|
||||
})
|
||||
.column_text("name", [](const ProjectRow& r) { return r.name; })
|
||||
.deletable([be = s.backend_ptr()](ProjectRow& r) -> bool {
|
||||
if (r.name.empty() || !json_utils::valid_flag_name(r.name)) {
|
||||
if (r.name.empty() || !r_name_check(r.name.c_str())) {
|
||||
xsql::set_vtab_error("projects: refusing to delete an unsafe/empty project name");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ void register_types_table(Session& s) {
|
||||
// SQL creates empty struct/union/enum shells and deletes types by name.
|
||||
// Full declarations use radare2's native td command.
|
||||
.deletable([be = s.backend_ptr()](TypeRow& r) -> bool {
|
||||
if (r.name.empty() || !json_utils::valid_flag_name(r.name)) {
|
||||
if (r.name.empty() || !r_name_check(r.name.c_str())) {
|
||||
xsql::set_vtab_error("types: refusing to delete an unsafe/empty type name");
|
||||
return false;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ void register_types_table(Session& s) {
|
||||
const char* kind_c = argv[2].as_c_str();
|
||||
const std::string name = name_c ? name_c : "";
|
||||
const std::string kind = kind_c ? kind_c : "";
|
||||
if (name.empty() || !json_utils::valid_flag_name(name)) {
|
||||
if (name.empty() || !r_name_check(name.c_str())) {
|
||||
xsql::set_vtab_error("types: refusing to create an unsafe/empty type name");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user