1// RUN: mlir-opt %s --transform-dialect-check-uses --split-input-file --verify-diagnostics 2 3func.func @use_after_free_branching_control_flow() { 4 // expected-note @below {{allocated here}} 5 %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op 6 transform.test_transform_op_with_regions { 7 "transform.test_branching_transform_op_terminator"() : () -> () 8 }, 9 { 10 ^bb0: 11 "transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> () 12 ^bb1: 13 // expected-note @below {{freed here}} 14 transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op 15 "transform.test_branching_transform_op_terminator"()[^bb3] : () -> () 16 ^bb2: 17 "transform.test_branching_transform_op_terminator"()[^bb3] : () -> () 18 ^bb3: 19 // expected-warning @below {{operand #0 may be used after free}} 20 transform.sequence %0 : !transform.any_op failures(propagate) { 21 ^bb0(%arg0: !transform.any_op): 22 } 23 "transform.test_branching_transform_op_terminator"() : () -> () 24 } 25 return 26} 27 28// ----- 29 30func.func @use_after_free_in_nested_op() { 31 // expected-note @below {{allocated here}} 32 %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op 33 // expected-note @below {{freed here}} 34 transform.test_transform_op_with_regions { 35 "transform.test_branching_transform_op_terminator"() : () -> () 36 }, 37 { 38 ^bb0: 39 "transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> () 40 ^bb1: 41 transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op 42 "transform.test_branching_transform_op_terminator"()[^bb3] : () -> () 43 ^bb2: 44 "transform.test_branching_transform_op_terminator"()[^bb3] : () -> () 45 ^bb3: 46 "transform.test_branching_transform_op_terminator"() : () -> () 47 } 48 // expected-warning @below {{operand #0 may be used after free}} 49 transform.sequence %0 : !transform.any_op failures(propagate) { 50 ^bb0(%arg0: !transform.any_op): 51 } 52 return 53} 54 55// ----- 56 57func.func @use_after_free_recursive_side_effects() { 58 transform.sequence failures(propagate) { 59 ^bb0(%arg0: !transform.any_op): 60 // expected-note @below {{allocated here}} 61 %0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) attributes { ord = 1 } { 62 ^bb1(%arg1: !transform.any_op): 63 yield %arg1 : !transform.any_op 64 } 65 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 2 } { 66 ^bb2(%arg2: !transform.any_op): 67 } 68 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 3 } { 69 ^bb3(%arg3: !transform.any_op): 70 } 71 72 // `transform.sequence` has recursive side effects so it has the same "free" 73 // as the child op it contains. 74 // expected-note @below {{freed here}} 75 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 4 } { 76 ^bb4(%arg4: !transform.any_op): 77 test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op 78 } 79 // expected-warning @below {{operand #0 may be used after free}} 80 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 5 } { 81 ^bb3(%arg3: !transform.any_op): 82 } 83 } 84 return 85} 86 87// ----- 88 89func.func @use_after_free() { 90 transform.sequence failures(propagate) { 91 ^bb0(%arg0: !transform.any_op): 92 // expected-note @below {{allocated here}} 93 %0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) attributes { ord = 1 } { 94 ^bb1(%arg1: !transform.any_op): 95 yield %arg1 : !transform.any_op 96 } 97 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 2 } { 98 ^bb2(%arg2: !transform.any_op): 99 } 100 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 3 } { 101 ^bb3(%arg3: !transform.any_op): 102 } 103 104 // expected-note @below {{freed here}} 105 test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op 106 // expected-warning @below {{operand #0 may be used after free}} 107 transform.sequence %0 : !transform.any_op failures(propagate) attributes { ord = 5 } { 108 ^bb3(%arg3: !transform.any_op): 109 } 110 } 111 return 112} 113 114// ----- 115 116// In the case of a control flow cycle, the operation that uses the value may 117// precede the one that frees it in the same block. Both operations should 118// be reported as use-after-free. 119func.func @use_after_free_self_cycle() { 120 // expected-note @below {{allocated here}} 121 %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op 122 transform.test_transform_op_with_regions { 123 "transform.test_branching_transform_op_terminator"() : () -> () 124 }, 125 { 126 ^bb0: 127 "transform.test_branching_transform_op_terminator"()[^bb1] : () -> () 128 ^bb1: 129 // expected-warning @below {{operand #0 may be used after free}} 130 transform.sequence %0 : !transform.any_op failures(propagate) { 131 ^bb0(%arg0: !transform.any_op): 132 } 133 // expected-warning @below {{operand #0 may be used after free}} 134 // expected-note @below {{freed here}} 135 transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op 136 "transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> () 137 ^bb2: 138 "transform.test_branching_transform_op_terminator"() : () -> () 139 } 140 return 141} 142 143 144// ----- 145 146// Check that the "free" that happens in a cycle is also reported as potential 147// use-after-free. 148func.func @use_after_free_cycle() { 149 // expected-note @below {{allocated here}} 150 %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op 151 transform.test_transform_op_with_regions { 152 "transform.test_branching_transform_op_terminator"() : () -> () 153 }, 154 { 155 ^bb0: 156 "transform.test_branching_transform_op_terminator"()[^bb1, ^bb2] : () -> () 157 ^bb1: 158 // expected-warning @below {{operand #0 may be used after free}} 159 // expected-note @below {{freed here}} 160 transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op 161 "transform.test_branching_transform_op_terminator"()[^bb2, ^bb3] : () -> () 162 ^bb2: 163 "transform.test_branching_transform_op_terminator"()[^bb1] : () -> () 164 ^bb3: 165 "transform.test_branching_transform_op_terminator"() : () -> () 166 } 167 return 168} 169 170// ----- 171 172// This should not crash. 173 174transform.sequence failures(propagate) { 175^bb0(%arg0: !transform.any_op): 176 alternatives %arg0 : !transform.any_op { 177 ^bb0(%arg1: !transform.any_op): 178 } 179} 180 181// ----- 182 183// This should not crash. 184 185module attributes {transform.with_named_sequence} { 186 transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) { 187 %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op 188 transform.apply_patterns to %0 { 189 transform.apply_patterns.memref.extract_address_computations 190 } : !transform.any_op 191 transform.yield 192 } 193} 194