Skip to content

Commit 7e65495

Browse files
fix(ast): safe GetSerializedType wrapper for type-map lookups
Adds GetSerializedType(key) to TypeBuilder that returns an empty QualType with a warning log instead of throwing std::out_of_range when the key is missing. Migrates 13 .at() call sites across ASTConsumer, FunctionBuilder, OperationBuilder, and OperationStmt. Supersedes #171 (rebased onto current main after the Pascal-case rename in #148). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f33e4f8 commit 7e65495

5 files changed

Lines changed: 51 additions & 24 deletions

File tree

include/patchestry/AST/TypeBuilder.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
#pragma once
99

1010
#include <functional>
11+
#include <string>
1112

1213
#include <clang/AST/ASTContext.h>
1314

1415
#include <patchestry/Ghidra/JsonDeserialize.hpp>
16+
#include <patchestry/Util/Log.hpp>
1517

1618
namespace patchestry::ast {
1719
using namespace patchestry::ghidra;
@@ -52,6 +54,28 @@ namespace patchestry::ast {
5254

5355
SerializedTypeMap &GetSerializedTypes(void) { return serialized_types; }
5456

57+
/**
58+
* @brief Safely retrieves a serialized `clang::QualType` for the given key.
59+
*
60+
* Performs a lookup in the internal `serialized_types` map without throwing
61+
* `std::out_of_range` when the key is not present. When the key is missing,
62+
* a warning is logged and an empty `clang::QualType` is returned so that
63+
* callers can propagate the failure via `QualType::isNull()`.
64+
*
65+
* @param key The type key to look up in the serialized type map.
66+
*
67+
* @return The `clang::QualType` associated with `key`, or an empty
68+
* `clang::QualType{}` if the key is not present in the map.
69+
*/
70+
clang::QualType GetSerializedType(const std::string &key) const {
71+
auto it = serialized_types.find(key);
72+
if (it == serialized_types.end()) {
73+
LOG(WARNING) << "Type key not found in serialized types: " << key;
74+
return clang::QualType{};
75+
}
76+
return it->second;
77+
}
78+
5579
/**
5680
* @brief Creates and serializes all types defined in the `lifted_types`.
5781
*

lib/patchestry/AST/ASTConsumer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,10 @@ namespace patchestry::ast {
342342
continue;
343343
}
344344

345-
auto var_type = type_builder->GetSerializedTypes().at(variable.type);
345+
auto var_type = type_builder->GetSerializedType(variable.type);
346+
if (var_type.isNull()) {
347+
continue;
348+
}
346349
auto location = SourceLocation(ctx.getSourceManager(), key);
347350
auto sanitized_name = SanitizeKeyToIdent(variable.name);
348351
auto *var_decl = clang::VarDecl::Create(

lib/patchestry/AST/FunctionBuilder.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,20 +255,21 @@ namespace patchestry::ast {
255255
return {};
256256
}
257257

258-
if (!type_builder.get().GetSerializedTypes().contains(proto.rttype_key)) {
258+
auto rttype = type_builder.get().GetSerializedType(proto.rttype_key);
259+
if (rttype.isNull()) {
259260
LOG(ERROR) << "Function return type is not serialized.\n";
260261
return {};
261262
}
262263

263264
std::vector< clang::QualType > args_vector;
264-
const auto &rttype = type_builder.get().GetSerializedTypes().at(proto.rttype_key);
265265
for (const auto &param : proto.parameters) {
266-
if (!type_builder.get().GetSerializedTypes().contains(param)) {
266+
auto param_type = type_builder.get().GetSerializedType(param);
267+
if (param_type.isNull()) {
267268
LOG(ERROR) << "Skipping, invalid parameter key in function.\n";
268269
continue;
269270
}
270271

271-
args_vector.emplace_back(type_builder.get().GetSerializedTypes().at(param));
272+
args_vector.emplace_back(param_type);
272273
}
273274

274275
clang::FunctionProtoType::ExtProtoInfo ext_proto_info;
@@ -316,12 +317,12 @@ namespace patchestry::ast {
316317
uint index = 0;
317318
std::vector< clang::ParmVarDecl * > parameter_vec;
318319
for (const auto &param_key : proto.parameters) {
319-
if (!type_builder.get().GetSerializedTypes().contains(param_key)) {
320+
auto param_type = type_builder.get().GetSerializedType(param_key);
321+
if (param_type.isNull()) {
320322
LOG(ERROR) << "Skipping, invalid paramater type key in function prototype.\n";
321323
continue;
322324
}
323325

324-
auto param_type = type_builder.get().GetSerializedTypes().at(param_key);
325326
auto *param_decl = clang::ParmVarDecl::Create(
326327
ctx, func_decl, SourceLocation(ctx.getSourceManager(), param_key),
327328
SourceLocation(ctx.getSourceManager(), param_key),

lib/patchestry/AST/OperationBuilder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ namespace patchestry::ast {
377377
bool is_wide = false;
378378
if (!vnode.type_key.empty()) {
379379
if (type_builder().GetSerializedTypes().contains(vnode.type_key)) {
380-
auto type = type_builder().GetSerializedTypes().at(vnode.type_key);
380+
auto type = type_builder().GetSerializedType(vnode.type_key);
381381
is_wide = type->isWideCharType();
382382
}
383383
}
@@ -423,7 +423,7 @@ namespace patchestry::ast {
423423
}
424424

425425
if (type_builder().GetSerializedTypes().contains(vnode.type_key)) {
426-
return type_builder().GetSerializedTypes().at(vnode.type_key);
426+
return type_builder().GetSerializedType(vnode.type_key);
427427
}
428428

429429
return GetTypeFromSize(ctx, vnode.size, /*is_signed=*/false, /*is_integer=*/true);

lib/patchestry/AST/OperationStmt.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ namespace patchestry::ast {
14621462
std::vector< clang::QualType > param_types;
14631463
for (const auto &input : op.inputs) {
14641464
if (type_builder().GetSerializedTypes().contains(input.type_key)) {
1465-
param_types.push_back(type_builder().GetSerializedTypes().at(input.type_key));
1465+
param_types.push_back(type_builder().GetSerializedType(input.type_key));
14661466
} else {
14671467
param_types.push_back(ctx.IntTy); // Fallback
14681468
}
@@ -1471,7 +1471,7 @@ namespace patchestry::ast {
14711471
// Infer return type from op.type
14721472
clang::QualType return_type = ctx.VoidTy;
14731473
if (op.type && type_builder().GetSerializedTypes().contains(*op.type)) {
1474-
return_type = type_builder().GetSerializedTypes().at(*op.type);
1474+
return_type = type_builder().GetSerializedType(*op.type);
14751475
}
14761476

14771477
// Build function type and pointer type
@@ -2494,12 +2494,12 @@ namespace patchestry::ast {
24942494
return {};
24952495
}
24962496

2497-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2497+
auto op_type = type_builder().GetSerializedType(*op.type);
2498+
if (op_type.isNull()) {
24982499
LOG(ERROR) << "INT2FLOAT operation type is not serialized. key: " << op.key << "\n";
24992500
return {};
25002501
}
25012502

2502-
const auto &op_type = type_builder().GetSerializedTypes().at(*op.type);
25032503
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
25042504

25052505
auto *input_expr =
@@ -2569,13 +2569,13 @@ namespace patchestry::ast {
25692569
return {};
25702570
}
25712571

2572-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2572+
auto op_type = type_builder().GetSerializedType(*op.type);
2573+
if (op_type.isNull()) {
25732574
LOG(ERROR) << "FLOAT2FLOAT operation type is not serialized. key: " << op.key
25742575
<< "\n";
25752576
return {};
25762577
}
25772578

2578-
const auto &op_type = type_builder().GetSerializedTypes().at(*op.type);
25792579
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
25802580

25812581
auto *input_expr =
@@ -2607,14 +2607,14 @@ namespace patchestry::ast {
26072607
return { nullptr, false };
26082608
}
26092609

2610-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2610+
auto op_type = type_builder().GetSerializedType(*op.type);
2611+
if (op_type.isNull()) {
26112612
LOG(ERROR) << "TRUNC operation type is not serialized. key: " << op.key << "\n";
26122613
return { nullptr, false };
26132614
}
26142615

26152616
auto merge_to_next = !op.output.has_value();
26162617

2617-
const auto &op_type = type_builder().GetSerializedTypes().at(*op.type);
26182618
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
26192619

26202620
auto *input_expr =
@@ -2724,14 +2724,14 @@ namespace patchestry::ast {
27242724
return { nullptr, false };
27252725
}
27262726

2727-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2727+
auto op_type = type_builder().GetSerializedType(*op.type);
2728+
if (op_type.isNull()) {
27282729
LOG(ERROR) << "PTRSUB operation type is not serialized. key: " << op.key << "\n";
27292730
return { nullptr, false };
27302731
}
27312732

27322733
auto merge_to_next = !op.output.has_value();
27332734

2734-
const auto &op_type = type_builder().GetSerializedTypes().at(*op.type);
27352735
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
27362736

27372737
auto *input_expr =
@@ -2865,13 +2865,13 @@ namespace patchestry::ast {
28652865
return {};
28662866
}
28672867

2868-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2868+
auto op_type = type_builder().GetSerializedType(*op.type);
2869+
if (op_type.isNull()) {
28692870
LOG(ERROR) << "Operation type does not exist in serialized list. key: " << op.key
28702871
<< "\n";
28712872
return {};
28722873
}
28732874

2874-
const auto &op_type = type_builder().GetSerializedTypes().at(*op.type);
28752875
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
28762876
auto *input_expr =
28772877
clang::dyn_cast< clang::Expr >(create_varnode(ctx, function, op.inputs[0]));
@@ -2911,13 +2911,12 @@ namespace patchestry::ast {
29112911
return {};
29122912
}
29132913

2914-
if (!type_builder().GetSerializedTypes().contains(*op.type)) {
2914+
auto var_type = type_builder().GetSerializedType(*op.type);
2915+
if (var_type.isNull()) {
29152916
LOG(ERROR) << "Skipping, local/temporary variable type is not serialized. key: "
29162917
<< op.key << "\n";
29172918
return {};
29182919
}
2919-
2920-
const auto &var_type = type_builder().GetSerializedTypes()[*op.type];
29212920
auto op_loc = SourceLocation(ctx.getSourceManager(), op.key);
29222921

29232922
std::string var_name = *op.name;

0 commit comments

Comments
 (0)