xref: /llvm-project/mlir/test/Dialect/Transform/check-use-after-free.mlir (revision 938cdd60d4938e32a7f4f1620e3d9c11aabc4af5)
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