Skip to content

Commit 37f0b02

Browse files
committed
ownership-semantics-lab: adoption classification probe fixtures (research-only)
Four variants of the frozen RLC# held-out Aliases.cs with the observed outputs: V0 control (silent: the wrapper is not IDisposable), V1 wrapper enrolled (the production P-005 D5.4 ctor-adopt fires: HO-12/HO-16 clean, HO-14 found, HO-15 a false positive from a null-initialised local), V2 non-adopting twin, V3 conditional-dispose twin (both declined). No analyzer code changed. Record: Own.NET-paperwork paper-eval/ownership-lab/hard-case-taxonomy-v1.json. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Am9eQwzNfbugH72eVKetC2
1 parent 19d7bd2 commit 37f0b02

9 files changed

Lines changed: 624 additions & 0 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# ownership-semantics-lab: adoption classification probe (research-only)
2+
3+
Four fixture variants of the frozen RLC# held-out file `Aliases.cs` (resource-effects
4+
Stage 5, digest in Own.NET-paperwork `paper-eval/resource-effects/stage5-heldout-freeze-v1.json`).
5+
No analyzer code changed; the probe decides which gap kind the "field adoption" family has.
6+
7+
| variant | change to the frozen file | purpose |
8+
|---|---|---|
9+
| V0 | none | control (silent: the wrapper is not IDisposable, so `cw` is never a candidate) |
10+
| V1 | `SqlConnectionWrapper : IDisposable` | the wrapper enrolled; production's P-005 D5.4 ctor-adopt (`alias_join`) fires |
11+
| V2 | V1 + ctor body `con.Open();` | non-adopting twin (the rule must decline) |
12+
| V3 | V1 + `if (connection != null) connection.Dispose();` | conditional-dispose twin (the rule must decline) |
13+
14+
Run (R1 environment of `paper-eval/ownership-lab/ab-reference-v1.json`, the System.Data.SqlClient
15+
4.8.6 `ref/netstandard2.0` assembly on `--ref-dir`):
16+
17+
```
18+
dotnet frontend/roslyn/OwnSharp.Extractor/bin/Release/net8.0/ownsharp-extract.dll --flow-locals V1.cs --ref-dir <refonly> -o V1.facts.json
19+
python -m ownlang ownir V1.facts.json --format human --severity warning
20+
```
21+
22+
`V*.expected.txt` are the observed outputs (Python engine; Rust identical on every variant).
23+
Record: Own.NET-paperwork `paper-eval/ownership-lab/hard-case-taxonomy-v1.json`
24+
(`classification_probe`). Not a fixture of any production test; never merged to `main`.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
using System;
2+
using System.Data.SqlClient;
3+
4+
namespace SqlConnectionExamples
5+
{
6+
public class SqlConnectionWrapper
7+
{
8+
SqlConnection connection;
9+
10+
public SqlConnectionWrapper(SqlConnection con)
11+
{
12+
this.connection = con;
13+
}
14+
15+
public SqlConnection GetConnection()
16+
{
17+
return connection;
18+
}
19+
20+
public void Dispose()
21+
{
22+
this.connection.Dispose();
23+
}
24+
}
25+
26+
public class Aliases
27+
{
28+
public static SqlConnection GetSqlConnection()
29+
{
30+
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
31+
builder.ConnectionString = "Server=tcp:database.windows.net,1433;Initial Catalog=leaks;Persist Security Info=False;User ID=resourceleaks;Password=ResourceLe@ks;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=300;";
32+
var sqlconnection = new SqlConnection(builder.ConnectionString);
33+
34+
return sqlconnection;
35+
}
36+
37+
public static void runSqlQuery(System.Data.SqlClient.SqlConnection con)
38+
{
39+
String sql = "select top 10 FirstName, LastName from [SalesLT].[Customer]";
40+
41+
using (SqlCommand command = new SqlCommand(sql, con))
42+
{
43+
using (SqlDataReader reader = command.ExecuteReader())
44+
{
45+
while (reader.Read())
46+
{
47+
Console.WriteLine("{0} {1}", reader.GetString(0), reader.GetString(1));
48+
}
49+
}
50+
}
51+
}
52+
53+
public static void findAliases()
54+
{
55+
SqlConnection con = GetSqlConnection(); // No resource leak
56+
57+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
58+
59+
runSqlQuery(cw.GetConnection());
60+
61+
cw.Dispose();
62+
}
63+
64+
public static void usingStmt()
65+
{
66+
using SqlConnection con = GetSqlConnection(); // No resource leak because of using statement
67+
68+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
69+
70+
runSqlQuery(cw.GetConnection());
71+
}
72+
73+
public static void exceptionalPaths1()
74+
{
75+
try
76+
{
77+
SqlConnection con = GetSqlConnection(); // Resource leak along exceptional path
78+
79+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
80+
81+
runSqlQuery(cw.GetConnection());
82+
83+
cw.Dispose();
84+
}
85+
catch (Exception ex) { }
86+
87+
}
88+
89+
public static void exceptionalPaths2()
90+
{
91+
SqlConnection con = null;
92+
93+
try
94+
{
95+
con = GetSqlConnection(); // No resource leak
96+
97+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
98+
99+
runSqlQuery(cw.GetConnection());
100+
101+
cw.Dispose();
102+
}
103+
catch (Exception ex) { }
104+
finally
105+
{
106+
if (con != null)
107+
con.Dispose();
108+
}
109+
110+
}
111+
112+
public static void multipleSinks()
113+
{
114+
Console.WriteLine("Enter count: ");
115+
int count = Convert.ToInt32(Console.ReadLine());
116+
117+
SqlConnection con = GetSqlConnection(); // No resource leak
118+
119+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
120+
121+
runSqlQuery(cw.GetConnection());
122+
123+
if(count > 10)
124+
cw.Dispose(); // Dispose 1
125+
else
126+
con.Dispose(); // Dispose 2
127+
}
128+
129+
public static void main()
130+
{
131+
Console.WriteLine($"Total memory: {GC.GetTotalMemory(true) / 1024f / 1024f} MB" + "\n---------------------------------------\n");
132+
133+
findAliases();
134+
exceptionalPaths1();
135+
exceptionalPaths2();
136+
multipleSinks();
137+
usingStmt();
138+
139+
GC.Collect();
140+
GC.WaitForFullGCComplete();
141+
Console.WriteLine("---------------------------------------\n" + $"Total memory: {GC.GetTotalMemory(true) / 1024f / 1024f} MB");
142+
}
143+
144+
}
145+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/tmp/claude-0/-home-user/8a9da608-aa27-5449-8306-1fae9426f9b9/scratchpad/lab/tax/V0.facts.json: ok — no subscription leaks found
2+
3+
0 findings.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
using System;
2+
using System.Data.SqlClient;
3+
4+
namespace SqlConnectionExamples
5+
{
6+
public class SqlConnectionWrapper : IDisposable
7+
{
8+
SqlConnection connection;
9+
10+
public SqlConnectionWrapper(SqlConnection con)
11+
{
12+
this.connection = con;
13+
}
14+
15+
public SqlConnection GetConnection()
16+
{
17+
return connection;
18+
}
19+
20+
public void Dispose()
21+
{
22+
this.connection.Dispose();
23+
}
24+
}
25+
26+
public class Aliases
27+
{
28+
public static SqlConnection GetSqlConnection()
29+
{
30+
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
31+
builder.ConnectionString = "Server=tcp:database.windows.net,1433;Initial Catalog=leaks;Persist Security Info=False;User ID=resourceleaks;Password=ResourceLe@ks;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=300;";
32+
var sqlconnection = new SqlConnection(builder.ConnectionString);
33+
34+
return sqlconnection;
35+
}
36+
37+
public static void runSqlQuery(System.Data.SqlClient.SqlConnection con)
38+
{
39+
String sql = "select top 10 FirstName, LastName from [SalesLT].[Customer]";
40+
41+
using (SqlCommand command = new SqlCommand(sql, con))
42+
{
43+
using (SqlDataReader reader = command.ExecuteReader())
44+
{
45+
while (reader.Read())
46+
{
47+
Console.WriteLine("{0} {1}", reader.GetString(0), reader.GetString(1));
48+
}
49+
}
50+
}
51+
}
52+
53+
public static void findAliases()
54+
{
55+
SqlConnection con = GetSqlConnection(); // No resource leak
56+
57+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
58+
59+
runSqlQuery(cw.GetConnection());
60+
61+
cw.Dispose();
62+
}
63+
64+
public static void usingStmt()
65+
{
66+
using SqlConnection con = GetSqlConnection(); // No resource leak because of using statement
67+
68+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
69+
70+
runSqlQuery(cw.GetConnection());
71+
}
72+
73+
public static void exceptionalPaths1()
74+
{
75+
try
76+
{
77+
SqlConnection con = GetSqlConnection(); // Resource leak along exceptional path
78+
79+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
80+
81+
runSqlQuery(cw.GetConnection());
82+
83+
cw.Dispose();
84+
}
85+
catch (Exception ex) { }
86+
87+
}
88+
89+
public static void exceptionalPaths2()
90+
{
91+
SqlConnection con = null;
92+
93+
try
94+
{
95+
con = GetSqlConnection(); // No resource leak
96+
97+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
98+
99+
runSqlQuery(cw.GetConnection());
100+
101+
cw.Dispose();
102+
}
103+
catch (Exception ex) { }
104+
finally
105+
{
106+
if (con != null)
107+
con.Dispose();
108+
}
109+
110+
}
111+
112+
public static void multipleSinks()
113+
{
114+
Console.WriteLine("Enter count: ");
115+
int count = Convert.ToInt32(Console.ReadLine());
116+
117+
SqlConnection con = GetSqlConnection(); // No resource leak
118+
119+
SqlConnectionWrapper cw = new SqlConnectionWrapper(con); // Resource aliases
120+
121+
runSqlQuery(cw.GetConnection());
122+
123+
if(count > 10)
124+
cw.Dispose(); // Dispose 1
125+
else
126+
con.Dispose(); // Dispose 2
127+
}
128+
129+
public static void main()
130+
{
131+
Console.WriteLine($"Total memory: {GC.GetTotalMemory(true) / 1024f / 1024f} MB" + "\n---------------------------------------\n");
132+
133+
findAliases();
134+
exceptionalPaths1();
135+
exceptionalPaths2();
136+
multipleSinks();
137+
usingStmt();
138+
139+
GC.Collect();
140+
GC.WaitForFullGCComplete();
141+
Console.WriteLine("---------------------------------------\n" + $"Total memory: {GC.GetTotalMemory(true) / 1024f / 1024f} MB");
142+
}
143+
144+
}
145+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
V1.cs:68: warning: [OWN001] IDisposable local 'cw' is never disposed (leak) [resource: disposable]
2+
V1.cs:77: warning: [OWN001] IDisposable local 'con' is never disposed (leak) [resource: disposable]
3+
V1.cs:97: warning: [OWN001] IDisposable local 'cw' may not be disposed on every path (leak) [resource: disposable]
4+
5+
3 findings.

0 commit comments

Comments
 (0)