From ed74551f2ec100d55b767a32b4cf2e96f4073cc1 Mon Sep 17 00:00:00 2001 From: Yi LIU Date: Wed, 11 Feb 2026 13:18:42 +0800 Subject: [PATCH] Fix updateSymbol calls misplaced inside loop in copyFunctionWithoutAdd The updateSymbol calls for prologLocation and epilogLocation were inside the for loop over debugLocations instead of outside. This caused them to be skipped when debugLocations was empty, and double-remapped when it had multiple entries. --- src/ir/module-utils.cpp | 4 +-- test/gtest/source-map.cpp | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index cf08205191b..cc13101b717 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -93,9 +93,9 @@ copyFunctionWithoutAdd(Function* func, (*symbolNameIndexMap)[*(iter.second->symbolNameIndex)]; } } - updateSymbol(ret->prologLocation, *symbolNameIndexMap); - updateSymbol(ret->epilogLocation, *symbolNameIndexMap); } + updateSymbol(ret->prologLocation, *symbolNameIndexMap); + updateSymbol(ret->epilogLocation, *symbolNameIndexMap); } ret->module = func->module; ret->base = func->base; diff --git a/test/gtest/source-map.cpp b/test/gtest/source-map.cpp index a01d064eda6..2e60075fdf1 100644 --- a/test/gtest/source-map.cpp +++ b/test/gtest/source-map.cpp @@ -15,7 +15,9 @@ */ #include "source-map.h" +#include "ir/module-utils.h" #include "print-test.h" +#include "wasm-builder.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" @@ -232,3 +234,69 @@ TEST_F(SourceMapTest, SourcesContent) { "#include int main()\\n{ printf(\\\"Gr\\u00fc\\u00df " "Gott, Welt!\\\"); return 0;}"); } + +// Regression test: updateSymbol calls for prologLocation/epilogLocation were +// inside the debugLocations loop instead of outside. When debugLocations is +// empty, the loop never executes and the locations are not updated. +TEST(SourceMapCopyTest, UpdateSymbolOutsideLoop) { + Module srcModule; + Module dstModule; + Builder builder(srcModule); + + auto func = builder.makeFunction( + "test", {}, Signature(Type::none, Type::none), {}, builder.makeNop()); + + // Set prologLocation and epilogLocation with symbolNameIndex values, + // but leave debugLocations empty. + func->prologLocation = + Function::DebugLocation{0, 1, 1, std::optional(0)}; + func->epilogLocation = + Function::DebugLocation{0, 2, 1, std::optional(1)}; + + // Symbol name index map: 0->10, 1->11. + std::vector symbolNameIndexMap = {10, 11}; + + auto copied = ModuleUtils::copyFunctionWithoutAdd( + func.get(), dstModule, Name(), std::nullopt, symbolNameIndexMap); + + ASSERT_TRUE(copied->prologLocation.has_value()); + ASSERT_TRUE(copied->prologLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->prologLocation->symbolNameIndex, 10u); + + ASSERT_TRUE(copied->epilogLocation.has_value()); + ASSERT_TRUE(copied->epilogLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->epilogLocation->symbolNameIndex, 11u); +} + +// When debugLocations has multiple entries, updateSymbol should only run once +// per location, not once per loop iteration (which would double-remap). +TEST(SourceMapCopyTest, UpdateSymbolNotDoubleRemapped) { + Module srcModule; + Module dstModule; + Builder builder(srcModule); + + auto func = builder.makeFunction( + "test", {}, Signature(Type::none, Type::none), {}, builder.makeNop()); + + func->prologLocation = + Function::DebugLocation{0, 1, 1, std::optional(0)}; + + // Add multiple debug locations so the loop runs multiple times. + auto* nop1 = srcModule.allocator.alloc(); + auto* nop2 = srcModule.allocator.alloc(); + func->debugLocations[nop1] = + Function::DebugLocation{0, 10, 1, std::optional(0)}; + func->debugLocations[nop2] = + Function::DebugLocation{0, 11, 1, std::optional(1)}; + + // Map: 0->5, 1->6. + std::vector symbolNameIndexMap = {5, 6}; + + auto copied = ModuleUtils::copyFunctionWithoutAdd( + func.get(), dstModule, Name(), std::nullopt, symbolNameIndexMap); + + // Should be remapped exactly once: 0 -> 5. + ASSERT_TRUE(copied->prologLocation.has_value()); + ASSERT_TRUE(copied->prologLocation->symbolNameIndex.has_value()); + EXPECT_EQ(*copied->prologLocation->symbolNameIndex, 5u); +}