diff --git a/CMakeLists.txt b/CMakeLists.txt index 49e48ac0..0ff8cf48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,17 +146,20 @@ add_custom_target("check" DEPENDS check-libcc2rs check-unit ) -file(GLOB rule_src_files ${PROJECT_SOURCE_DIR}/rules/*/src.cpp) +file(GLOB rule_subdirs ${PROJECT_SOURCE_DIR}/rules/*) set(cpp_rules_ir_outputs) set(rust_rules_ir_outputs) set(rust_rules_inputs) -foreach(_src IN LISTS rule_src_files) - get_filename_component(_rule_dir ${_src} DIRECTORY) +foreach(_rule_dir IN LISTS rule_subdirs) + file(GLOB _srcs ${_rule_dir}/src.c ${_rule_dir}/src.cpp) + if(NOT _srcs) + continue() + endif() set(_out ${_rule_dir}/ir_src.json) add_custom_command( OUTPUT ${_out} - COMMAND $ --file ${_src} - DEPENDS ${_src} ${PROJECT_SOURCE_DIR}/cpp2rust/cpp_rule_preprocessor.cpp + COMMAND $ --dir ${_rule_dir} + DEPENDS ${_srcs} ${PROJECT_SOURCE_DIR}/cpp2rust/cpp_rule_preprocessor.cpp VERBATIM ) list(APPEND cpp_rules_ir_outputs ${_out}) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 457379f1..a0c5ae8c 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -405,7 +405,8 @@ TranslationRule::TypeRule *search(clang::QualType qual_type) { void addRulesFromDirectory(const std::filesystem::path &dir, Model model) { for (const auto &entry : std::filesystem::recursive_directory_iterator(dir)) { auto &path = entry.path(); - if (entry.is_regular_file() && path.extension() == ".cpp") { + if (entry.is_regular_file() && + (path.extension() == ".cpp" || path.extension() == ".c")) { auto [expr_rules, type_rules] = TranslationRule::Load(path, model); if (expr_rules.empty() && type_rules.empty()) { log() << "No rules found in " << path << '\n'; diff --git a/cpp2rust/cpp_rule_preprocessor.cpp b/cpp2rust/cpp_rule_preprocessor.cpp index 22329aee..957a6c83 100644 --- a/cpp2rust/cpp_rule_preprocessor.cpp +++ b/cpp2rust/cpp_rule_preprocessor.cpp @@ -751,11 +751,11 @@ namespace { llvm::cl::OptionCategory cat("cpp-rule-preprocessor options"); llvm::cl::opt - SrcFile("file", - llvm::cl::desc("Path to a rule's src.cpp. ir_src.json is written " - "next to it"), - llvm::cl::value_desc("src.cpp"), llvm::cl::Required, - llvm::cl::cat(cat)); + SrcDir("dir", + llvm::cl::desc("Path to a rule directory containing src.c and/or " + "src.cpp. ir_src.json is written into this dir."), + llvm::cl::value_desc("rule-dir"), llvm::cl::Required, + llvm::cl::cat(cat)); } // namespace @@ -763,12 +763,27 @@ int main(int argc, char *argv[]) { llvm::cl::HideUnrelatedOptions(cat); llvm::cl::ParseCommandLineOptions(argc, argv); - fs::path src = SrcFile.getValue(); - llvm::errs() << "Preprocessing " << src.string() << '\n'; + fs::path dir = SrcDir.getValue(); llvm::json::Object root; - cpp2rust::Extract(src, root); + for (const char *name : {"src.c", "src.cpp"}) { + auto path = dir / name; + if (!fs::exists(path)) { + continue; + } + llvm::errs() << "Preprocessing " << path.string() << '\n'; + llvm::json::Object file_root; + cpp2rust::Extract(path, file_root); + for (auto &[k, v] : file_root) { + if (!root.try_emplace(k, std::move(v)).second) { + llvm::errs() << "ERROR: rule name " << k.str() + << " defined in multiple files in " << dir.string() + << '\n'; + return EXIT_FAILURE; + } + } + } - auto out_path = src.parent_path() / "ir_src.json"; + auto out_path = dir / "ir_src.json"; std::error_code ec; llvm::raw_fd_ostream out(out_path.string(), ec); if (ec) { diff --git a/rules/cstring/ir_unsafe.json b/rules/cstring/ir_unsafe.json index 4ddb64c0..91b7b08f 100644 --- a/rules/cstring/ir_unsafe.json +++ b/rules/cstring/ir_unsafe.json @@ -312,5 +312,81 @@ "type": "*mut u8", "is_unsafe_pointer": true } + }, + "f5": { + "body": [ + { + "text": "libc::strchr(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ") as *mut u8" + } + ], + "params": { + "a0": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "i32" + } + }, + "return_type": { + "type": "*mut u8", + "is_unsafe_pointer": true + } + }, + "f6": { + "body": [ + { + "text": "libc::strchr(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ") as *const u8" + } + ], + "params": { + "a0": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "i32" + } + }, + "return_type": { + "type": "*const u8", + "is_unsafe_pointer": true + } } } diff --git a/rules/cstring/src.c b/rules/cstring/src.c new file mode 100644 index 00000000..24cbd0e5 --- /dev/null +++ b/rules/cstring/src.c @@ -0,0 +1,14 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +void *f1(void *dst, const void *src, size_t n) { return memcpy(dst, src, n); } + +void *f2(void *dst, int c, size_t n) { return memset(dst, c, n); } + +int f3(const void *s1, const void *s2, size_t n) { return memcmp(s1, s2, n); } + +void *f4(void *dst, const void *src, size_t n) { return memmove(dst, src, n); } + +char *f5(const char *a0, int a1) { return strchr(a0, a1); } diff --git a/rules/cstring/src.cpp b/rules/cstring/src.cpp index d6397c77..3e1c77cc 100644 --- a/rules/cstring/src.cpp +++ b/rules/cstring/src.cpp @@ -3,10 +3,4 @@ #include -void *f1(void *dst, const void *src, size_t n) { return memcpy(dst, src, n); } - -void *f2(void *dst, int c, size_t n) { return memset(dst, c, n); } - -int f3(const void *s1, const void *s2, size_t n) { return memcmp(s1, s2, n); } - -void *f4(void *dst, const void *src, size_t n) { return memmove(dst, src, n); } +const char *f6(const char *a0, int a1) { return strchr(a0, a1); } diff --git a/rules/cstring/tgt_unsafe.rs b/rules/cstring/tgt_unsafe.rs index b399dab5..8e0ab804 100644 --- a/rules/cstring/tgt_unsafe.rs +++ b/rules/cstring/tgt_unsafe.rs @@ -35,3 +35,11 @@ unsafe fn f4(a0: *mut u8, a1: *const u8, a2: usize) -> *mut u8 { } a0 } + +unsafe fn f5(a0: *const u8, a1: i32) -> *mut u8 { + libc::strchr(a0 as *const i8, a1) as *mut u8 +} + +unsafe fn f6(a0: *const u8, a1: i32) -> *const u8 { + libc::strchr(a0 as *const i8, a1) as *const u8 +} diff --git a/tests/unit/out/unsafe/strchr_c.rs b/tests/unit/out/unsafe/strchr_c.rs new file mode 100644 index 00000000..efce259d --- /dev/null +++ b/tests/unit/out/unsafe/strchr_c.rs @@ -0,0 +1,21 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: *const u8 = b"hello world\0".as_ptr().cast_mut().cast_const(); + let mut r: *mut u8 = libc::strchr(s as *const i8, ('w' as i32)) as *mut u8; + assert!((((!((r).is_null())) as i32) != 0)); + assert!((((((*r) as i32) == ('w' as i32)) as i32) != 0)); + assert!(((((libc::strchr(s as *const i8, ('z' as i32)) as *mut u8).is_null()) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/strchr_cpp.rs b/tests/unit/out/unsafe/strchr_cpp.rs new file mode 100644 index 00000000..309f23e6 --- /dev/null +++ b/tests/unit/out/unsafe/strchr_cpp.rs @@ -0,0 +1,21 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: *const u8 = b"hello world\0".as_ptr(); + let mut r: *const u8 = libc::strchr(s as *const i8, (('w' as u8) as i32)) as *const u8; + assert!(!((r).is_null())); + assert!((((*r) as i32) == (('w' as u8) as i32))); + assert!((libc::strchr(s as *const i8, (('z' as u8) as i32)) as *const u8).is_null()); + return 0; +} diff --git a/tests/unit/strchr_c.c b/tests/unit/strchr_c.c new file mode 100644 index 00000000..eb23549b --- /dev/null +++ b/tests/unit/strchr_c.c @@ -0,0 +1,12 @@ +// no-compile: refcount +#include +#include + +int main() { + const char *s = "hello world"; + char *r = strchr(s, 'w'); + assert(r != NULL); + assert(*r == 'w'); + assert(strchr(s, 'z') == NULL); + return 0; +} diff --git a/tests/unit/strchr_cpp.cpp b/tests/unit/strchr_cpp.cpp new file mode 100644 index 00000000..4a9e5be5 --- /dev/null +++ b/tests/unit/strchr_cpp.cpp @@ -0,0 +1,12 @@ +// no-compile: refcount +#include +#include + +int main() { + const char *s = "hello world"; + const char *r = strchr(s, 'w'); + assert(r != NULL); + assert(*r == 'w'); + assert(strchr(s, 'z') == NULL); + return 0; +}