Skip to content
Open
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
9 changes: 9 additions & 0 deletions database_writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,15 @@ absl::Status DatabaseReader::Read(CallGraph& call_graph1,
.Into(&similarity_)
.Into(&confidence_);
ABSL_RETURN_IF_ERROR(statement.Execute());
if (primary_filename_ == secondary_filename_) {
// Both sides would be read from the same .BinExport next to the results
// file; one of them has necessarily been overwritten by the other.
return absl::FailedPreconditionError(absl::StrCat(
"primary and secondary BinExport files both resolve to \"",
JoinPath(path_, primary_filename_ + ".BinExport"),
"\". Results for same-named binaries need to be re-diffed and saved "
"again"));
}

// Function matches
ABSL_ASSIGN_OR_RETURN(
Expand Down
31 changes: 28 additions & 3 deletions ida/main_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,20 @@ absl::StatusOr<bool> ExportIdbs() {
RemoveAll(secondary_temp_dir).IgnoreError();
ABSL_RETURN_IF_ERROR(CreateDirectories(secondary_temp_dir));

// The export names end up as the "filename" column of the result file and
// as the names of the .BinExport files saved next to it. Same-named
// databases (e.g. two versions of the same binary in different directories)
// would overwrite each other there, so disambiguate both sides the same way
// the BinDiff UI does.
std::string primary_name =
ReplaceFileExtension(Basename(primary_idb_path), "");
const std::string secondary_name =
ReplaceFileExtension(Basename(secondary_idb_path), "");
const bool same_name = primary_name == secondary_name;
if (same_name) {
primary_name += "_primary";
}

{
const auto& config = config::Proto();
auto options =
Expand All @@ -254,9 +268,8 @@ absl::StatusOr<bool> ExportIdbs() {
std::thread export_thread(
[&status, &exporter]() { status = exporter.Export(); });

const std::string primary_binexport = JoinPath(
primary_temp_dir,
ReplaceFileExtension(Basename(primary_idb_path), ".BinExport"));
const std::string primary_binexport =
JoinPath(primary_temp_dir, absl::StrCat(primary_name, ".BinExport"));
idc_value_t arg = primary_binexport.c_str();
if (qstring errbuf; !call_idc_func(
/*result=*/nullptr, "BinExportBinary", &arg,
Expand All @@ -272,6 +285,18 @@ absl::StatusOr<bool> ExportIdbs() {
"Export of the secondary database failed: ", status.message()));
}
}
if (same_name) {
// IdbExporter always names its output after the database.
const std::string exported = JoinPath(
secondary_temp_dir, absl::StrCat(secondary_name, ".BinExport"));
const std::string renamed =
JoinPath(secondary_temp_dir,
absl::StrCat(secondary_name, "_secondary.BinExport"));
if (std::rename(exported.c_str(), renamed.c_str()) != 0) {
return absl::UnknownError(absl::StrCat(
"Failed to rename secondary export to \"", renamed, "\""));
}
}
return true;
}

Expand Down
Loading