From 4797c47b9a3109dc843fda8fd90324d21625ad45 Mon Sep 17 00:00:00 2001 From: Georgiy Komarov Date: Mon, 23 Dec 2024 11:15:40 +0000 Subject: [PATCH] fix(callgraph): Don't add extra state write effects --- CHANGELOG.md | 5 +- src/internals/ir/callGraph.ts | 2 + test/all/syntax.expected.callgraph.dot | 50 ++++++++-------- test/all/syntax.expected.callgraph.json | 78 +++++++++++++++++-------- test/all/syntax.expected.callgraph.mmd | 50 ++++++++-------- test/all/syntax.expected.cfg.dot | 12 +++- test/all/syntax.expected.cfg.json | 32 +++++++++- test/all/syntax.expected.cfg.mmd | 9 ++- test/all/syntax.tact | 6 ++ 9 files changed, 168 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac7a4e6b..5a67ca70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Callgraph: Don't add state write effects when changing local maps/strings/cells + ## [0.6.1] - 2024-12-22 ### Fixed -The `scripts` directory wasn't included in the npm release, which makes it impossible to build Misti as a dependency +- The `scripts` directory wasn't included in the npm release, which makes it impossible to build Misti as a dependency ## [0.6.0] - 2024-12-22 diff --git a/src/internals/ir/callGraph.ts b/src/internals/ir/callGraph.ts index 3b6a0789..87b26554 100644 --- a/src/internals/ir/callGraph.ts +++ b/src/internals/ir/callGraph.ts @@ -8,6 +8,7 @@ import { DATETIME_NAMES, isSelfAccess, isSendCall, + isSelf, PRG_INIT_NAMES, PRG_NATIVE_USE_NAMES, PRG_SAFE_USE_NAMES, @@ -537,6 +538,7 @@ function isContractStateWrite(stmt: AstStatement): boolean { stmt, (expr) => expr.kind === "method_call" && + isSelf(expr.self) && (MAP_MUTATING_OPERATIONS.has(idText(expr.method)) || STRING_MUTATING_OPERATIONS.has(idText(expr.method)) || CELL_MUTATING_OPERATIONS.has(idText(expr.method))), diff --git a/test/all/syntax.expected.callgraph.dot b/test/all/syntax.expected.callgraph.dot index a96d3163..a633c595 100644 --- a/test/all/syntax.expected.callgraph.dot +++ b/test/all/syntax.expected.callgraph.dot @@ -3,8 +3,7 @@ digraph "CallGraph" { node_1 [label="fun test_try(a: Int)"]; node_2 [label="fun test_loops()"]; node_3 [label="fun testTryCatch(a: Int)"]; - node_4 [label="fun testLoops() -[StateWrite]"]; + node_4 [label="fun testLoops()"]; node_5 [label="override get fun getter(): Int"]; node_6 [label="fun test()"]; node_7 [label="fun test(): Int"]; @@ -19,28 +18,33 @@ digraph "CallGraph" { [StateWrite]"]; node_13 [label="fun funcWithMultipleEffects() [AccessDatetime,PrgUse,PrgSeedInit]"]; - node_14 [label="dump"]; - node_15 [label="emptyMap"]; - node_16 [label="m::set"]; - node_17 [label="getA"]; - node_18 [label="sender"]; - node_19 [label="send"]; - node_20 [label="newAddress"]; - node_21 [label="now"]; - node_22 [label="random"]; - node_23 [label="nativeRandomizeLt"]; - node_1 -> node_14; - node_2 -> node_15; - node_3 -> node_14; - node_4 -> node_15; - node_4 -> node_16; - node_4 -> node_16; + node_14 [label="receive()"]; + node_15 [label="dump"]; + node_16 [label="emptyMap"]; + node_17 [label="m::set"]; + node_18 [label="getA"]; + node_19 [label="sender"]; + node_20 [label="send"]; + node_21 [label="newAddress"]; + node_22 [label="now"]; + node_23 [label="random"]; + node_24 [label="nativeRandomizeLt"]; + node_25 [label="beginString"]; + node_26 [label="a::append"]; + node_1 -> node_15; + node_2 -> node_16; + node_3 -> node_15; node_4 -> node_16; - node_7 -> node_17; - node_9 -> node_18; - node_10 -> node_19; - node_12 -> node_20; - node_13 -> node_21; + node_4 -> node_17; + node_4 -> node_17; + node_4 -> node_17; + node_7 -> node_18; + node_9 -> node_19; + node_10 -> node_20; + node_12 -> node_21; node_13 -> node_22; node_13 -> node_23; + node_13 -> node_24; + node_14 -> node_25; + node_14 -> node_26; } diff --git a/test/all/syntax.expected.callgraph.json b/test/all/syntax.expected.callgraph.json index d933ed51..436bd2ac 100644 --- a/test/all/syntax.expected.callgraph.json +++ b/test/all/syntax.expected.callgraph.json @@ -90,6 +90,14 @@ }, { "idx": 14, + "inEdges": [], + "outEdges": [ + 15, + 16 + ] + }, + { + "idx": 15, "inEdges": [ 1, 3 @@ -97,7 +105,7 @@ "outEdges": [] }, { - "idx": 15, + "idx": 16, "inEdges": [ 2, 4 @@ -105,7 +113,7 @@ "outEdges": [] }, { - "idx": 16, + "idx": 17, "inEdges": [ 5, 6, @@ -114,125 +122,149 @@ "outEdges": [] }, { - "idx": 17, + "idx": 18, "inEdges": [ 8 ], "outEdges": [] }, { - "idx": 18, + "idx": 19, "inEdges": [ 9 ], "outEdges": [] }, { - "idx": 19, + "idx": 20, "inEdges": [ 10 ], "outEdges": [] }, { - "idx": 20, + "idx": 21, "inEdges": [ 11 ], "outEdges": [] }, { - "idx": 21, + "idx": 22, "inEdges": [ 12 ], "outEdges": [] }, { - "idx": 22, + "idx": 23, "inEdges": [ 13 ], "outEdges": [] }, { - "idx": 23, + "idx": 24, "inEdges": [ 14 ], "outEdges": [] + }, + { + "idx": 25, + "inEdges": [ + 15 + ], + "outEdges": [] + }, + { + "idx": 26, + "inEdges": [ + 16 + ], + "outEdges": [] } ], "edges": [ { "idx": 1, "src": 1, - "dst": 14 + "dst": 15 }, { "idx": 2, "src": 2, - "dst": 15 + "dst": 16 }, { "idx": 3, "src": 3, - "dst": 14 + "dst": 15 }, { "idx": 4, "src": 4, - "dst": 15 + "dst": 16 }, { "idx": 5, "src": 4, - "dst": 16 + "dst": 17 }, { "idx": 6, "src": 4, - "dst": 16 + "dst": 17 }, { "idx": 7, "src": 4, - "dst": 16 + "dst": 17 }, { "idx": 8, "src": 7, - "dst": 17 + "dst": 18 }, { "idx": 9, "src": 9, - "dst": 18 + "dst": 19 }, { "idx": 10, "src": 10, - "dst": 19 + "dst": 20 }, { "idx": 11, "src": 12, - "dst": 20 + "dst": 21 }, { "idx": 12, "src": 13, - "dst": 21 + "dst": 22 }, { "idx": 13, "src": 13, - "dst": 22 + "dst": 23 }, { "idx": 14, "src": 13, - "dst": 23 + "dst": 24 + }, + { + "idx": 15, + "src": 14, + "dst": 25 + }, + { + "idx": 16, + "src": 14, + "dst": 26 } ] } \ No newline at end of file diff --git a/test/all/syntax.expected.callgraph.mmd b/test/all/syntax.expected.callgraph.mmd index dc7d854c..15dfbaf1 100644 --- a/test/all/syntax.expected.callgraph.mmd +++ b/test/all/syntax.expected.callgraph.mmd @@ -2,8 +2,7 @@ graph TD node_1["fun test_try(a: Int)"] node_2["fun test_loops()"] node_3["fun testTryCatch(a: Int)"] - node_4["fun testLoops() -[StateWrite]"] + node_4["fun testLoops()"] node_5["override get fun getter(): Int"] node_6["fun test()"] node_7["fun test(): Int"] @@ -18,27 +17,32 @@ graph TD [StateWrite]"] node_13["fun funcWithMultipleEffects() [AccessDatetime,PrgUse,PrgSeedInit]"] - node_14["dump"] - node_15["emptyMap"] - node_16["m::set"] - node_17["getA"] - node_18["sender"] - node_19["send"] - node_20["newAddress"] - node_21["now"] - node_22["random"] - node_23["nativeRandomizeLt"] - node_1 --> node_14 - node_2 --> node_15 - node_3 --> node_14 - node_4 --> node_15 - node_4 --> node_16 - node_4 --> node_16 + node_14["receive()"] + node_15["dump"] + node_16["emptyMap"] + node_17["m::set"] + node_18["getA"] + node_19["sender"] + node_20["send"] + node_21["newAddress"] + node_22["now"] + node_23["random"] + node_24["nativeRandomizeLt"] + node_25["beginString"] + node_26["a::append"] + node_1 --> node_15 + node_2 --> node_16 + node_3 --> node_15 node_4 --> node_16 - node_7 --> node_17 - node_9 --> node_18 - node_10 --> node_19 - node_12 --> node_20 - node_13 --> node_21 + node_4 --> node_17 + node_4 --> node_17 + node_4 --> node_17 + node_7 --> node_18 + node_9 --> node_19 + node_10 --> node_20 + node_12 --> node_21 node_13 --> node_22 node_13 --> node_23 + node_13 --> node_24 + node_14 --> node_25 + node_14 --> node_26 diff --git a/test/all/syntax.expected.cfg.dot b/test/all/syntax.expected.cfg.dot index 0d32e039..57398efa 100644 --- a/test/all/syntax.expected.cfg.dot +++ b/test/all/syntax.expected.cfg.dot @@ -108,9 +108,9 @@ digraph "syntax" { subgraph "cluster_TestContractT__receive_external_fallback_1722" { label="TestContractT__receive_external_fallback_1722"; } - subgraph "cluster_EffectTest__init_1971" { - label="EffectTest__init_1971"; - "EffectTest__init_1971_109" [label="self.addr = sender()",style=filled,fillcolor="#66A7DB"]; + subgraph "cluster_EffectTest__init_1981" { + label="EffectTest__init_1981"; + "EffectTest__init_1981_109" [label="self.addr = sender()",style=filled,fillcolor="#66A7DB"]; } subgraph "cluster_EffectTest__funcWithSend" { label="EffectTest__funcWithSend"; @@ -136,5 +136,11 @@ digraph "syntax" { "EffectTest__funcWithMultipleEffects_115" -> "EffectTest__funcWithMultipleEffects_116"; "EffectTest__funcWithMultipleEffects_116" -> "EffectTest__funcWithMultipleEffects_117"; } + subgraph "cluster_EffectTest__receive_internal_fallback_1980" { + label="EffectTest__receive_internal_fallback_1980"; + "EffectTest__receive_internal_fallback_1980_118" [label="let a = beginString()"]; + "EffectTest__receive_internal_fallback_1980_119" [label="a.append(\"f\")",style=filled,fillcolor="#66A7DB"]; + "EffectTest__receive_internal_fallback_1980_118" -> "EffectTest__receive_internal_fallback_1980_119"; + } "115" -> "26"; } diff --git a/test/all/syntax.expected.cfg.json b/test/all/syntax.expected.cfg.json index 4e6f75bf..41877dc0 100644 --- a/test/all/syntax.expected.cfg.json +++ b/test/all/syntax.expected.cfg.json @@ -705,7 +705,7 @@ "name": "EffectTest", "methods": [ { - "name": "EffectTest.init_1971", + "name": "EffectTest.init_1981", "cfg": { "nodes": [ { @@ -835,6 +835,36 @@ } ] } + }, + { + "name": "EffectTest.receive_internal_fallback_1980", + "cfg": { + "nodes": [ + { + "id": 118, + "stmtID": 1974, + "srcEdges": [], + "dstEdges": [ + 104 + ] + }, + { + "id": 119, + "stmtID": 1979, + "srcEdges": [ + 104 + ], + "dstEdges": [] + } + ], + "edges": [ + { + "id": 104, + "src": 118, + "dst": 119 + } + ] + } } ] } diff --git a/test/all/syntax.expected.cfg.mmd b/test/all/syntax.expected.cfg.mmd index 1195903c..ea970416 100644 --- a/test/all/syntax.expected.cfg.mmd +++ b/test/all/syntax.expected.cfg.mmd @@ -99,8 +99,8 @@ subgraph TestContractT__test end subgraph TestContractT__receive_external_fallback_1722 end -subgraph EffectTest__init_1971 - EffectTest__init_1971_109["self.addr = sender()"]:::exitNode +subgraph EffectTest__init_1981 + EffectTest__init_1981_109["self.addr = sender()"]:::exitNode end subgraph EffectTest__funcWithSend EffectTest__funcWithSend_110["let amount: Int = 100"] @@ -122,3 +122,8 @@ subgraph EffectTest__funcWithMultipleEffects EffectTest__funcWithMultipleEffects_115 --> EffectTest__funcWithMultipleEffects_116 EffectTest__funcWithMultipleEffects_116 --> EffectTest__funcWithMultipleEffects_117 end +subgraph EffectTest__receive_internal_fallback_1980 + EffectTest__receive_internal_fallback_1980_118["let a = beginString()"] + EffectTest__receive_internal_fallback_1980_119["a.append('f')"]:::exitNode + EffectTest__receive_internal_fallback_1980_118 --> EffectTest__receive_internal_fallback_1980_119 +end diff --git a/test/all/syntax.tact b/test/all/syntax.tact index 427ab840..2733e84c 100644 --- a/test/all/syntax.tact +++ b/test/all/syntax.tact @@ -128,4 +128,10 @@ contract EffectTest { nativeRandomizeLt(); } } + + // Doesn't add the state write effect + receive() { + let a = beginString(); + a.append("f"); + } }