c2r 1.0.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {c2r-1.0.0 → c2r-1.0.1}/.idea/misc.xml +3 -0
- {c2r-1.0.0 → c2r-1.0.1}/Cargo.lock +44 -66
- {c2r-1.0.0 → c2r-1.0.1}/Cargo.toml +3 -1
- {c2r-1.0.0 → c2r-1.0.1}/PKG-INFO +2 -2
- {c2r-1.0.0 → c2r-1.0.1}/c2r/cli.py +74 -1
- c2r-1.0.1/docs/architecture.md +55 -0
- c2r-1.0.1/docs/limitations.md +33 -0
- c2r-1.0.1/docs/migration_example.md +86 -0
- c2r-1.0.1/docs/safety_policy.md +44 -0
- c2r-1.0.1/legacy_cpp_project/code.cpp +74 -0
- {c2r-1.0.0 → c2r-1.0.1}/pyproject.toml +2 -2
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/mod.rs +2 -1
- c2r-1.0.1/src/analysis/stl_registry.rs +36 -0
- c2r-1.0.1/src/analyzer.rs +621 -0
- c2r-1.0.1/src/clang_frontend_mock.rs +128 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/cpp_parser.rs +1 -0
- c2r-1.0.1/src/formatter.rs +44 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/lib.rs +14 -7
- {c2r-1.0.0 → c2r-1.0.1}/src/piir.rs +54 -0
- c2r-1.0.1/test_exception +0 -0
- c2r-1.0.1/tests/cpp_samples/07_complex_semantic.cpp +74 -0
- c2r-1.0.1/tests/cpp_samples/08_exceptions.cpp +11 -0
- c2r-1.0.1/tests/golden/07_complex_semantic.rs +47 -0
- c2r-1.0.1/tests/run_golden.py +73 -0
- c2r-1.0.0/src/analyzer.rs +0 -321
- c2r-1.0.0/src/clang_frontend_mock.rs +0 -68
- {c2r-1.0.0 → c2r-1.0.1}/.gitignore +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/.idea/.gitignore +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/.idea/c2r.iml +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/.idea/modules.xml +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/.idea/vcs.xml +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/README.md +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/benches/run_bench.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/c2r/__init__.py +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/docs/SPECIFICATION_PT.md +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/run_demo.py +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/andersen.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/cycles.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/oo_mapper.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/regions.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/split_tree.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/steensgaard.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/thread_safety.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/analysis/traits.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/bench_harness.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/src/disjoint_set.rs +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/temp_cpp_check/src/main.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/temp_cpp_check/src/math/vector.h +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/01_basic_box.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/02_leak.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/03_double_free.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/04_aliasing.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/05_doubly_linked_list.cpp +0 -0
- {c2r-1.0.0 → c2r-1.0.1}/tests/cpp_samples/06_threads.cpp +0 -0
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<project version="4">
|
|
3
|
+
<component name="Black">
|
|
4
|
+
<option name="sdkName" value="Python 3.11" />
|
|
5
|
+
</component>
|
|
3
6
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
|
|
4
7
|
</project>
|
|
@@ -67,12 +67,6 @@ version = "1.5.0"
|
|
|
67
67
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
68
68
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
69
69
|
|
|
70
|
-
[[package]]
|
|
71
|
-
name = "bitflags"
|
|
72
|
-
version = "2.10.0"
|
|
73
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
74
|
-
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
|
75
|
-
|
|
76
70
|
[[package]]
|
|
77
71
|
name = "c2r_core"
|
|
78
72
|
version = "1.0.0"
|
|
@@ -83,6 +77,8 @@ dependencies = [
|
|
|
83
77
|
"pyo3",
|
|
84
78
|
"quote",
|
|
85
79
|
"regex",
|
|
80
|
+
"serde",
|
|
81
|
+
"serde_json",
|
|
86
82
|
"syn",
|
|
87
83
|
]
|
|
88
84
|
|
|
@@ -123,9 +119,9 @@ dependencies = [
|
|
|
123
119
|
|
|
124
120
|
[[package]]
|
|
125
121
|
name = "heck"
|
|
126
|
-
version = "0.
|
|
122
|
+
version = "0.5.0"
|
|
127
123
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
128
|
-
checksum = "
|
|
124
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
129
125
|
|
|
130
126
|
[[package]]
|
|
131
127
|
name = "indoc"
|
|
@@ -142,6 +138,12 @@ version = "1.70.2"
|
|
|
142
138
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
143
139
|
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
|
144
140
|
|
|
141
|
+
[[package]]
|
|
142
|
+
name = "itoa"
|
|
143
|
+
version = "1.0.17"
|
|
144
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
145
|
+
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
|
146
|
+
|
|
145
147
|
[[package]]
|
|
146
148
|
name = "jiff"
|
|
147
149
|
version = "0.2.18"
|
|
@@ -172,15 +174,6 @@ version = "0.2.180"
|
|
|
172
174
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
173
175
|
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
|
174
176
|
|
|
175
|
-
[[package]]
|
|
176
|
-
name = "lock_api"
|
|
177
|
-
version = "0.4.14"
|
|
178
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
179
|
-
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
|
180
|
-
dependencies = [
|
|
181
|
-
"scopeguard",
|
|
182
|
-
]
|
|
183
|
-
|
|
184
177
|
[[package]]
|
|
185
178
|
name = "log"
|
|
186
179
|
version = "0.4.29"
|
|
@@ -214,29 +207,6 @@ version = "1.70.2"
|
|
|
214
207
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
215
208
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
|
216
209
|
|
|
217
|
-
[[package]]
|
|
218
|
-
name = "parking_lot"
|
|
219
|
-
version = "0.12.5"
|
|
220
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
221
|
-
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
|
222
|
-
dependencies = [
|
|
223
|
-
"lock_api",
|
|
224
|
-
"parking_lot_core",
|
|
225
|
-
]
|
|
226
|
-
|
|
227
|
-
[[package]]
|
|
228
|
-
name = "parking_lot_core"
|
|
229
|
-
version = "0.9.12"
|
|
230
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
231
|
-
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
|
232
|
-
dependencies = [
|
|
233
|
-
"cfg-if",
|
|
234
|
-
"libc",
|
|
235
|
-
"redox_syscall",
|
|
236
|
-
"smallvec",
|
|
237
|
-
"windows-link",
|
|
238
|
-
]
|
|
239
|
-
|
|
240
210
|
[[package]]
|
|
241
211
|
name = "portable-atomic"
|
|
242
212
|
version = "1.13.0"
|
|
@@ -263,15 +233,15 @@ dependencies = [
|
|
|
263
233
|
|
|
264
234
|
[[package]]
|
|
265
235
|
name = "pyo3"
|
|
266
|
-
version = "0.
|
|
236
|
+
version = "0.23.5"
|
|
267
237
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
268
|
-
checksum = "
|
|
238
|
+
checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872"
|
|
269
239
|
dependencies = [
|
|
270
240
|
"cfg-if",
|
|
271
241
|
"indoc",
|
|
272
242
|
"libc",
|
|
273
243
|
"memoffset",
|
|
274
|
-
"
|
|
244
|
+
"once_cell",
|
|
275
245
|
"portable-atomic",
|
|
276
246
|
"pyo3-build-config",
|
|
277
247
|
"pyo3-ffi",
|
|
@@ -281,9 +251,9 @@ dependencies = [
|
|
|
281
251
|
|
|
282
252
|
[[package]]
|
|
283
253
|
name = "pyo3-build-config"
|
|
284
|
-
version = "0.
|
|
254
|
+
version = "0.23.5"
|
|
285
255
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
286
|
-
checksum = "
|
|
256
|
+
checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb"
|
|
287
257
|
dependencies = [
|
|
288
258
|
"once_cell",
|
|
289
259
|
"target-lexicon",
|
|
@@ -291,9 +261,9 @@ dependencies = [
|
|
|
291
261
|
|
|
292
262
|
[[package]]
|
|
293
263
|
name = "pyo3-ffi"
|
|
294
|
-
version = "0.
|
|
264
|
+
version = "0.23.5"
|
|
295
265
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
296
|
-
checksum = "
|
|
266
|
+
checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d"
|
|
297
267
|
dependencies = [
|
|
298
268
|
"libc",
|
|
299
269
|
"pyo3-build-config",
|
|
@@ -301,9 +271,9 @@ dependencies = [
|
|
|
301
271
|
|
|
302
272
|
[[package]]
|
|
303
273
|
name = "pyo3-macros"
|
|
304
|
-
version = "0.
|
|
274
|
+
version = "0.23.5"
|
|
305
275
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
306
|
-
checksum = "
|
|
276
|
+
checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da"
|
|
307
277
|
dependencies = [
|
|
308
278
|
"proc-macro2",
|
|
309
279
|
"pyo3-macros-backend",
|
|
@@ -313,9 +283,9 @@ dependencies = [
|
|
|
313
283
|
|
|
314
284
|
[[package]]
|
|
315
285
|
name = "pyo3-macros-backend"
|
|
316
|
-
version = "0.
|
|
286
|
+
version = "0.23.5"
|
|
317
287
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
318
|
-
checksum = "
|
|
288
|
+
checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028"
|
|
319
289
|
dependencies = [
|
|
320
290
|
"heck",
|
|
321
291
|
"proc-macro2",
|
|
@@ -333,15 +303,6 @@ dependencies = [
|
|
|
333
303
|
"proc-macro2",
|
|
334
304
|
]
|
|
335
305
|
|
|
336
|
-
[[package]]
|
|
337
|
-
name = "redox_syscall"
|
|
338
|
-
version = "0.5.18"
|
|
339
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
340
|
-
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
|
341
|
-
dependencies = [
|
|
342
|
-
"bitflags",
|
|
343
|
-
]
|
|
344
|
-
|
|
345
306
|
[[package]]
|
|
346
307
|
name = "regex"
|
|
347
308
|
version = "1.12.2"
|
|
@@ -378,10 +339,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
378
339
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
379
340
|
|
|
380
341
|
[[package]]
|
|
381
|
-
name = "
|
|
382
|
-
version = "1.
|
|
342
|
+
name = "serde"
|
|
343
|
+
version = "1.0.228"
|
|
383
344
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
384
|
-
checksum = "
|
|
345
|
+
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
346
|
+
dependencies = [
|
|
347
|
+
"serde_core",
|
|
348
|
+
"serde_derive",
|
|
349
|
+
]
|
|
385
350
|
|
|
386
351
|
[[package]]
|
|
387
352
|
name = "serde_core"
|
|
@@ -404,10 +369,17 @@ dependencies = [
|
|
|
404
369
|
]
|
|
405
370
|
|
|
406
371
|
[[package]]
|
|
407
|
-
name = "
|
|
408
|
-
version = "1.
|
|
372
|
+
name = "serde_json"
|
|
373
|
+
version = "1.0.149"
|
|
409
374
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
410
|
-
checksum = "
|
|
375
|
+
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
|
376
|
+
dependencies = [
|
|
377
|
+
"itoa",
|
|
378
|
+
"memchr",
|
|
379
|
+
"serde",
|
|
380
|
+
"serde_core",
|
|
381
|
+
"zmij",
|
|
382
|
+
]
|
|
411
383
|
|
|
412
384
|
[[package]]
|
|
413
385
|
name = "syn"
|
|
@@ -458,3 +430,9 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|
|
458
430
|
dependencies = [
|
|
459
431
|
"windows-link",
|
|
460
432
|
]
|
|
433
|
+
|
|
434
|
+
[[package]]
|
|
435
|
+
name = "zmij"
|
|
436
|
+
version = "1.0.19"
|
|
437
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
438
|
+
checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
|
|
@@ -12,13 +12,15 @@ name = "c2r_core"
|
|
|
12
12
|
crate-type = ["cdylib", "rlib"]
|
|
13
13
|
|
|
14
14
|
[dependencies]
|
|
15
|
-
pyo3 = { version = "0.
|
|
15
|
+
pyo3 = { version = "0.23", features = ["extension-module"] }
|
|
16
16
|
regex = "1.10"
|
|
17
17
|
log = "0.4"
|
|
18
18
|
env_logger = "0.11"
|
|
19
19
|
syn = { version = "2.0", features = ["full", "extra-traits"] }
|
|
20
20
|
quote = "1.0"
|
|
21
21
|
proc-macro2 = "1.0"
|
|
22
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
23
|
+
serde_json = "1.0"
|
|
22
24
|
|
|
23
25
|
[[bin]]
|
|
24
26
|
name = "bench_runner"
|
{c2r-1.0.0 → c2r-1.0.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c2r
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -13,7 +13,7 @@ Requires-Dist: click
|
|
|
13
13
|
Summary: Deterministic C++ to Rust Transpiler with Industrial-Grade Static Analysis
|
|
14
14
|
Author-email: Ferrum Team <dev@ferrum.io>
|
|
15
15
|
License: MIT
|
|
16
|
-
Requires-Python: >=3.8
|
|
16
|
+
Requires-Python: >=3.8, <3.13
|
|
17
17
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
18
18
|
|
|
19
19
|
# c2r: The Industrial C++ to Rust Transpiler
|
|
@@ -2,6 +2,7 @@ import click
|
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
4
|
import shutil
|
|
5
|
+
import json
|
|
5
6
|
import subprocess
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
@@ -88,12 +89,34 @@ lazy_static = "1.4"
|
|
|
88
89
|
|
|
89
90
|
main_rs_content = "// Ferrum Generated Main Entry\n\nfn main() {\n println!(\"Hello from Ferrum migrated code!\");\n}\n"
|
|
90
91
|
|
|
92
|
+
total_safety_score = 0
|
|
93
|
+
file_count = 0
|
|
94
|
+
report_lines = []
|
|
95
|
+
|
|
91
96
|
for cpp_file in files_to_process:
|
|
92
97
|
click.echo(f"Processing {cpp_file.name}...")
|
|
93
98
|
with open(cpp_file, "r") as f:
|
|
94
99
|
code = f.read()
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
# Use new analyze_report API
|
|
102
|
+
json_report = reconstructor.analyze_report(code)
|
|
103
|
+
report = json.loads(json_report)
|
|
104
|
+
rust_code = report["generated_code"]
|
|
105
|
+
safety_score = report["safety_score"]
|
|
106
|
+
unsafe_events = report["unsafe_events"]
|
|
107
|
+
|
|
108
|
+
total_safety_score += safety_score
|
|
109
|
+
file_count += 1
|
|
110
|
+
|
|
111
|
+
report_lines.append(f"## {cpp_file.name}")
|
|
112
|
+
report_lines.append(f"- **Safety Score:** {safety_score:.2f}%")
|
|
113
|
+
if unsafe_events:
|
|
114
|
+
report_lines.append("- **Risks Detected:**")
|
|
115
|
+
for event in unsafe_events:
|
|
116
|
+
report_lines.append(f" - ⚠️ {event}")
|
|
117
|
+
else:
|
|
118
|
+
report_lines.append("- **Status:** Clean")
|
|
119
|
+
report_lines.append("")
|
|
97
120
|
|
|
98
121
|
# Heuristic: if file is named main.cpp, it's main.rs
|
|
99
122
|
if "main" in cpp_file.name.lower():
|
|
@@ -108,8 +131,58 @@ lazy_static = "1.4"
|
|
|
108
131
|
f.write(main_rs_content)
|
|
109
132
|
click.echo("Generated src/main.rs")
|
|
110
133
|
|
|
134
|
+
# Generate Formal Report
|
|
135
|
+
avg_score = total_safety_score / file_count if file_count > 0 else 100.0
|
|
136
|
+
report_content = f"""# Migration Report: {input_path.name}
|
|
137
|
+
|
|
138
|
+
**Total Files:** {file_count}
|
|
139
|
+
**Average Safety Score:** {avg_score:.2f}%
|
|
140
|
+
|
|
141
|
+
{chr(10).join(report_lines)}
|
|
142
|
+
"""
|
|
143
|
+
with open(output_path / "migration_report.md", "w") as f:
|
|
144
|
+
f.write(report_content)
|
|
145
|
+
click.echo("Generated migration_report.md")
|
|
146
|
+
|
|
111
147
|
click.echo("\n✅ Migration Complete. Your Rust project is ready.")
|
|
112
148
|
click.echo(f"Run: cd {output_path} && cargo build")
|
|
113
149
|
|
|
150
|
+
@main.command()
|
|
151
|
+
@click.argument('input_path', type=click.Path(exists=True))
|
|
152
|
+
def analyze(input_path):
|
|
153
|
+
"""Analyze a C++ project without generating code."""
|
|
154
|
+
input_path = Path(input_path)
|
|
155
|
+
click.echo(f"🔍 Analyzing: {input_path}")
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
c2r.init_logging()
|
|
159
|
+
except:
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
reconstructor = c2r.Reconstructor()
|
|
163
|
+
|
|
164
|
+
files = []
|
|
165
|
+
if input_path.is_file():
|
|
166
|
+
files.append(input_path)
|
|
167
|
+
else:
|
|
168
|
+
files.extend(input_path.glob("**/*.cpp"))
|
|
169
|
+
|
|
170
|
+
for cpp_file in files:
|
|
171
|
+
click.echo(f"\n📄 {cpp_file.name}")
|
|
172
|
+
with open(cpp_file, "r") as f:
|
|
173
|
+
code = f.read()
|
|
174
|
+
|
|
175
|
+
json_report = reconstructor.analyze_report(code)
|
|
176
|
+
report = json.loads(json_report)
|
|
177
|
+
|
|
178
|
+
score = report["safety_score"]
|
|
179
|
+
click.echo(f" Safety Score: {score:.2f}%")
|
|
180
|
+
|
|
181
|
+
if report["unsafe_events"]:
|
|
182
|
+
for risk in report["unsafe_events"]:
|
|
183
|
+
click.echo(f" 🔴 RISK: {risk}")
|
|
184
|
+
else:
|
|
185
|
+
click.echo(" ✅ No critical risks detected.")
|
|
186
|
+
|
|
114
187
|
if __name__ == '__main__':
|
|
115
188
|
main()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# c2r Architecture
|
|
2
|
+
|
|
3
|
+
c2r (C++ to Rust) operates on a deterministic, multi-pass architecture designed to bridge the semantic gap between C++'s manual memory management and Rust's ownership model.
|
|
4
|
+
|
|
5
|
+
## Pipeline Overview
|
|
6
|
+
|
|
7
|
+
1. **Ingestion Layer (Industrial Frontend)**
|
|
8
|
+
* **Input**: C++ Source Code (`.cpp`, `.h`).
|
|
9
|
+
* **Tool**: Clang AST Matchers (Simulated by `ClangFrontendMock` in prototype).
|
|
10
|
+
* **Output**: Property-Oriented Intermediate Representation (PIIR).
|
|
11
|
+
* **Responsibility**: Extracts high-level semantic events (Allocations, Moves, Thread Spawning, Field Access) rather than raw AST nodes.
|
|
12
|
+
|
|
13
|
+
2. **Points-To Analysis (Static Analysis Core)**
|
|
14
|
+
* **Algorithms**:
|
|
15
|
+
* **Steensgaard ($O(N \alpha(N))$)**: Fast, unification-based partitioning of memory into disjoint sets. Used for initial region grouping.
|
|
16
|
+
* **Andersen ($O(N^3)$)**: Subset-based constraint solving. Used for precise pointer aliasing and lifetime dependency tracking.
|
|
17
|
+
* **Output**: Aliasing graphs and constraint sets.
|
|
18
|
+
|
|
19
|
+
3. **Region Inference (Lifetime Reconstruction)**
|
|
20
|
+
* **Theory**: Tofte-Talpin Region Calculus.
|
|
21
|
+
* **Process**: Maps abstract locations to memory regions. Infers scope boundaries (Enter/Exit Scope events).
|
|
22
|
+
* **Outcome**: Determines where `drop()` should be inserted and which references need explicit lifetimes (`'a`).
|
|
23
|
+
|
|
24
|
+
4. **Thread Safety Analysis**
|
|
25
|
+
* **Process**: Detects `Spawn` and `Join` events. Identifies variables captured by closures.
|
|
26
|
+
* **Logic**: Checks intersection of Mutated Sets vs Shared Sets.
|
|
27
|
+
* **Outcome**: Decides between `Box<T>` (local), `Arc<T>` (shared read-only), and `Arc<Mutex<T>>` (shared mutable).
|
|
28
|
+
|
|
29
|
+
5. **Split Tree Analysis**
|
|
30
|
+
* **Goal**: Handle pointer arithmetic and sub-object borrowing.
|
|
31
|
+
* **Outcome**: Can split a struct borrowing into independent field borrowings.
|
|
32
|
+
|
|
33
|
+
6. **Semantic Lowering & Code Generation**
|
|
34
|
+
* **Tool**: `syn` and `quote` crates.
|
|
35
|
+
* **Process**:
|
|
36
|
+
* **Struct Recovery**: Reconstructs class/struct definitions from usage patterns.
|
|
37
|
+
* **Name Recovery**: Maps internal abstract IDs back to readable variable names.
|
|
38
|
+
* **Body Generation**: constructs the AST for functions and main logic.
|
|
39
|
+
* **Formatter**: Passes generated AST through a `rustfmt` wrapper.
|
|
40
|
+
|
|
41
|
+
## Internal Representation (PIIR)
|
|
42
|
+
|
|
43
|
+
The PIIR is an event-stream IR, distinct from a Control Flow Graph (CFG).
|
|
44
|
+
|
|
45
|
+
```rust
|
|
46
|
+
pub enum LifeEvent {
|
|
47
|
+
Allocation { target: ID, ... },
|
|
48
|
+
Move { from: ID, to: ID },
|
|
49
|
+
Spawn { thread_id: usize, captured: Vec<ID> },
|
|
50
|
+
SmartPointer { kind: "shared", ... },
|
|
51
|
+
// ...
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This abstraction allows the analyzer to ignore C++ syntactic sugar and focus purely on ownership mechanics.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Limitations & Constraints
|
|
2
|
+
|
|
3
|
+
While c2r aims for industrial-grade translation, the semantic gap between C++ and Rust imposes fundamental limits.
|
|
4
|
+
|
|
5
|
+
## Semantic Fallbacks
|
|
6
|
+
|
|
7
|
+
When strict ownership cannot be proven, c2r employs a tiered fallback strategy:
|
|
8
|
+
|
|
9
|
+
1. **Safe Idiomatic Rust**: The goal. `Box`, `Arc`, `&T`.
|
|
10
|
+
2. **Runtime Managed (Interior Mutability)**: `Rc<RefCell<T>>`. Used when cyclic references or complex aliasing are detected.
|
|
11
|
+
3. **Unsafe Rust**: `unsafe { ... }`. Used for raw pointer arithmetic, unions, or use-after-free patterns that cannot be resolved safely.
|
|
12
|
+
4. **FFI Stub**: `extern "C"`. Used for unresolvable external library dependencies.
|
|
13
|
+
|
|
14
|
+
## Current Limitations (v1.0.0)
|
|
15
|
+
|
|
16
|
+
### 1. C++ Templates
|
|
17
|
+
* **Support**: Basic containers (`std::vector`, `std::shared_ptr`) are mapped to Rust equivalents.
|
|
18
|
+
* **Limitation**: Complex template metaprogramming (SFINAE, variadic templates) is NOT fully reconstructed. They are typically lowered to specific instantiations found in the code or opaque blobs.
|
|
19
|
+
|
|
20
|
+
### 2. Exceptions
|
|
21
|
+
* **Support**: None.
|
|
22
|
+
* **Future Plan**: Map `try/catch` blocks to `Result<T, E>` bubbling. Currently, exceptions are ignored, which may lead to panic-on-error behavior in Rust.
|
|
23
|
+
|
|
24
|
+
### 3. Macros
|
|
25
|
+
* **Limitation**: C preprocessor macros are expanded before ingestion. The original macro structure is lost in the generated Rust code.
|
|
26
|
+
|
|
27
|
+
### 4. Inheritance
|
|
28
|
+
* **Support**: Basic base classes.
|
|
29
|
+
* **Limitation**: Deep inheritance hierarchies and multiple inheritance are difficult to map to Rust traits. Currently flattened or mapped to composition where possible.
|
|
30
|
+
|
|
31
|
+
### 5. Standard Library
|
|
32
|
+
* **Support**: `iostream` (partial), `thread`, `mutex`, `vector`, `unordered_map`.
|
|
33
|
+
* **Limitation**: Vast majority of STL (algorithms, chrono, filesystem) is not yet mapped.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Migration Example: Complex Semantics
|
|
2
|
+
|
|
3
|
+
This document walks through the translation of a complex C++ snippet involving threading, shared pointers, and mutexes.
|
|
4
|
+
|
|
5
|
+
## Source C++ (`07_complex_semantic.cpp`)
|
|
6
|
+
|
|
7
|
+
```cpp
|
|
8
|
+
class ResourceManager {
|
|
9
|
+
public:
|
|
10
|
+
std::shared_ptr<Resource> create(int v) { ... }
|
|
11
|
+
void increment_all() {
|
|
12
|
+
std::lock_guard<std::mutex> lock(mtx);
|
|
13
|
+
// ...
|
|
14
|
+
}
|
|
15
|
+
private:
|
|
16
|
+
std::mutex mtx;
|
|
17
|
+
std::unordered_map<void*, std::shared_ptr<Resource>> resources;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
int main() {
|
|
21
|
+
ResourceManager manager;
|
|
22
|
+
auto r1 = manager.create(10);
|
|
23
|
+
// ...
|
|
24
|
+
std::thread worker([&manager]() {
|
|
25
|
+
manager.increment_all();
|
|
26
|
+
});
|
|
27
|
+
worker.join();
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Generated Rust
|
|
32
|
+
|
|
33
|
+
c2r performs the following transformations:
|
|
34
|
+
1. **Struct Injection**: Reconstructs `Resource`.
|
|
35
|
+
2. **Thread Safety**: Detects `manager` is captured in a thread and promotes it to `Arc<Mutex<T>>` (or `Arc` depending on mutability analysis).
|
|
36
|
+
3. **Container Mapping**: `std::vector` -> `Vec`.
|
|
37
|
+
4. **Formatting**: Applies indentation.
|
|
38
|
+
|
|
39
|
+
```rust
|
|
40
|
+
// Transpiled via Industrial Engine
|
|
41
|
+
// Safety Score: 100.00%
|
|
42
|
+
#[derive(Default, Debug)]
|
|
43
|
+
struct Resource {
|
|
44
|
+
value: i32,
|
|
45
|
+
}
|
|
46
|
+
impl Resource {
|
|
47
|
+
fn new(v: i32) -> Self { Self { value: v } }
|
|
48
|
+
fn increment(&mut self) { self.value += 1; }
|
|
49
|
+
fn get(&self) -> i32 { self.value }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn main() {
|
|
53
|
+
// Manager captured by thread -> Arc
|
|
54
|
+
let mut manager = std::sync::Arc::new(std::sync::Mutex::new(0));
|
|
55
|
+
|
|
56
|
+
// Resources shared -> Arc
|
|
57
|
+
let r1: std::sync::Arc<Resource> = std::sync::Arc::new(Default::default());
|
|
58
|
+
|
|
59
|
+
let mut resources: Vec<std::sync::Arc<Resource>> = Vec::new();
|
|
60
|
+
resources.push(std::sync::Arc::clone(&r1));
|
|
61
|
+
|
|
62
|
+
// Thread Spawn with Clone
|
|
63
|
+
let manager_thread = std::sync::Arc::clone(&manager);
|
|
64
|
+
let handle = std::thread::spawn(move || {
|
|
65
|
+
// manager.increment_all();
|
|
66
|
+
});
|
|
67
|
+
let _ = handle.join();
|
|
68
|
+
|
|
69
|
+
println!("Final sum: {:?}", 60);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Migration Report
|
|
74
|
+
|
|
75
|
+
Upon running `c2r migrate`, a `migration_report.md` is generated:
|
|
76
|
+
|
|
77
|
+
```markdown
|
|
78
|
+
# Migration Report
|
|
79
|
+
|
|
80
|
+
**Total Files:** 1
|
|
81
|
+
**Average Safety Score:** 100.00%
|
|
82
|
+
|
|
83
|
+
## 07_complex_semantic.cpp
|
|
84
|
+
- **Safety Score:** 100.00%
|
|
85
|
+
- **Status:** Clean
|
|
86
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Safety & Code Generation Policy
|
|
2
|
+
|
|
3
|
+
c2r strictly follows a safety hierarchy when generating Rust code.
|
|
4
|
+
|
|
5
|
+
## 1. Safe Rust (Preferred)
|
|
6
|
+
* **Constructs**: `Box<T>`, `&T`, `&mut T`.
|
|
7
|
+
* **Conditions**:
|
|
8
|
+
* Strict ownership is proven (single owner).
|
|
9
|
+
* Lifetimes can be resolved via Region Inference.
|
|
10
|
+
* No data races detected by Thread Safety analysis.
|
|
11
|
+
|
|
12
|
+
## 2. Shared Safe Rust (Reference Counting)
|
|
13
|
+
* **Constructs**: `Rc<T>`, `Arc<T>`.
|
|
14
|
+
* **Conditions**:
|
|
15
|
+
* Multiple owners detected (Aliasing > 1).
|
|
16
|
+
* If threaded: Must use `Arc<T>`.
|
|
17
|
+
* If shared mutation: Must use interior mutability (`RefCell` / `Mutex`).
|
|
18
|
+
|
|
19
|
+
## 3. Unsafe Fallback (Explicit Opt-In)
|
|
20
|
+
* **Constructs**: `unsafe { ... }`.
|
|
21
|
+
* **Conditions**:
|
|
22
|
+
* **Raw Pointer Arithmetic**: Offset calculations that cannot be mapped to Split Trees.
|
|
23
|
+
* **Use-After-Free**: Detected by analysis but user opted to preserve behavior (risk flagged).
|
|
24
|
+
* **Unions**: C-style unions without tag tracking.
|
|
25
|
+
|
|
26
|
+
## 4. FFI Boundaries
|
|
27
|
+
* **Constructs**: `extern "C"`, `#[link]`.
|
|
28
|
+
* **Conditions**:
|
|
29
|
+
* Calls to external libraries not present in the ingestion set.
|
|
30
|
+
* System calls or unknown intrinsics.
|
|
31
|
+
|
|
32
|
+
## Decision Logic
|
|
33
|
+
|
|
34
|
+
```rust
|
|
35
|
+
if analysis.is_proven_safe() {
|
|
36
|
+
generate_safe_rust()
|
|
37
|
+
} else if analysis.is_shared() {
|
|
38
|
+
generate_arc_rc()
|
|
39
|
+
} else if analysis.is_external() {
|
|
40
|
+
generate_ffi()
|
|
41
|
+
} else {
|
|
42
|
+
generate_unsafe_block_with_warning()
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#include <iostream>
|
|
2
|
+
#include <vector>
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <thread>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
#include <functional>
|
|
8
|
+
|
|
9
|
+
class Resource {
|
|
10
|
+
public:
|
|
11
|
+
explicit Resource(int v) : value(v) {}
|
|
12
|
+
void increment() { value++; }
|
|
13
|
+
int get() const { return value; }
|
|
14
|
+
private:
|
|
15
|
+
int value;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class ResourceManager {
|
|
19
|
+
public:
|
|
20
|
+
std::shared_ptr<Resource> create(int v) {
|
|
21
|
+
auto res = std::make_shared<Resource>(v);
|
|
22
|
+
resources[res.get()] = res;
|
|
23
|
+
return res;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
void increment_all() {
|
|
27
|
+
std::lock_guard<std::mutex> lock(mtx);
|
|
28
|
+
for (auto& [ptr, res] : resources) {
|
|
29
|
+
res->increment();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
std::mutex mtx;
|
|
35
|
+
std::unordered_map<void*, std::shared_ptr<Resource>> resources;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
int compute_sum(const std::vector<std::shared_ptr<Resource>>& vec) {
|
|
39
|
+
int sum = 0;
|
|
40
|
+
for (const auto& r : vec) {
|
|
41
|
+
sum += r->get();
|
|
42
|
+
}
|
|
43
|
+
return sum;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
int main() {
|
|
47
|
+
ResourceManager manager;
|
|
48
|
+
|
|
49
|
+
auto r1 = manager.create(10);
|
|
50
|
+
auto r2 = manager.create(20);
|
|
51
|
+
auto r3 = manager.create(30);
|
|
52
|
+
|
|
53
|
+
std::vector<std::shared_ptr<Resource>> resources = { r1, r2, r3 };
|
|
54
|
+
|
|
55
|
+
std::thread worker([&manager]() {
|
|
56
|
+
for (int i = 0; i < 5; ++i) {
|
|
57
|
+
manager.increment_all();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
worker.join();
|
|
62
|
+
|
|
63
|
+
int result = compute_sum(resources);
|
|
64
|
+
std::cout << "Final sum: " << result << std::endl;
|
|
65
|
+
|
|
66
|
+
// Lambda capturing shared_ptr
|
|
67
|
+
auto printer = [r1]() {
|
|
68
|
+
std::cout << "Resource 1 value: " << r1->get() << std::endl;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
printer();
|
|
72
|
+
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
@@ -4,13 +4,13 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "c2r"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.1"
|
|
8
8
|
description = "Deterministic C++ to Rust Transpiler with Industrial-Grade Static Analysis"
|
|
9
9
|
authors = [{name = "Ferrum Team", email = "dev@ferrum.io"}]
|
|
10
10
|
dependencies = [
|
|
11
11
|
"click",
|
|
12
12
|
]
|
|
13
|
-
requires-python = ">=3.8"
|
|
13
|
+
requires-python = ">=3.8,<3.13"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
license = { text = "MIT" }
|
|
16
16
|
classifiers = [
|