Skip to content

Commit cc93c03

Browse files
committed
More layout checks, fixes to some tests
1 parent c500b9f commit cc93c03

File tree

15 files changed

+180
-72
lines changed

15 files changed

+180
-72
lines changed

.github/workflows/rust.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,14 @@ jobs:
3737
run: ilasm --version
3838
- name: Run cargo tests
3939
run: cargo test --verbose ::stable -- --skip f128 --skip num_test
40+
linux_c_test:
41+
runs-on: ubuntu-22.04
42+
env:
43+
C_MODE: 1
44+
steps:
45+
- uses: actions/checkout@v3
46+
- name: Build
47+
run: cargo build
48+
- name: Run cargo tests
49+
run: cargo test --verbose ::stable -- --skip f128 --skip num_test --skip arithmetic_misc --skip simd --skip round --skip interop
4050

QUICKSTART.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,4 @@ By default, `cg_clr` will keep symbol(function) names more-or-less intact. Howev
101101
```
102102
_ZN54_$LT$$LP$A$C$B$RP$$u20$as$u20$fuzz100__PrintFDebug$GT$12printf_debug17h769fc7ecbdc54ca9E
103103
```
104-
In those cases, simply set `ASCI_IDENT` enviroment variable to ensure correct symbol names.
104+
In those cases, simply set `ASCI_IDENT` enviroment variable to ensure correct symbol names

cilly/src/bin/linker/main.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -504,18 +504,20 @@ fn main() {
504504
let _ = final_assembly.tcctor();
505505
let _ = final_assembly.cctor();
506506
let float128 = final_assembly.alloc_string("f128");
507-
final_assembly.class_def(ClassDef::new(
508-
float128,
509-
true,
510-
0,
511-
None,
512-
vec![],
513-
vec![],
514-
cilly::Access::Public,
515-
NonZeroU32::new(16),
516-
NonZeroU32::new(16),
517-
true,
518-
));
507+
final_assembly
508+
.class_def(ClassDef::new(
509+
float128,
510+
true,
511+
0,
512+
None,
513+
vec![],
514+
vec![],
515+
cilly::Access::Public,
516+
NonZeroU32::new(16),
517+
NonZeroU32::new(16),
518+
true,
519+
))
520+
.unwrap();
519521

520522
final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides);
521523
final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides);

cilly/src/v2/asm.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::{
22
bimap::{BiMap, BiMapIndex, Interned, IntoBiMapIndex},
33
cilnode::{BinOp, ExtendKind, MethodKind, PtrCastRes, UnOp},
4-
class::{ClassDefIdx, StaticFieldDef},
4+
class::{ClassDefIdx, LayoutError, StaticFieldDef},
55
opt::{OptFuel, SideEffectInfoCache},
66
Access, CILNode, CILRoot, ClassDef, ClassRef, Const, Exporter, FieldDesc, FnSig, Int,
77
IntoAsmIndex, MethodDef, MethodDefIdx, MethodRef, StaticFieldDesc, Type,
@@ -480,19 +480,20 @@ impl Assembly {
480480
idx
481481
}
482482
/// Adds a new class definition to this type
483-
pub fn class_def(&mut self, def: ClassDef) -> ClassDefIdx {
483+
pub fn class_def(&mut self, def: ClassDef) -> Result<ClassDefIdx, LayoutError> {
484+
def.layout_check(self)?;
484485
let cref = def.ref_to();
485486
let cref = self.alloc_class_ref(cref);
486487

487488
if self.class_defs.contains_key(&ClassDefIdx(cref)) {
488489
if self[def.name()].contains("core.ffi.c_void") || self[def.name()].contains("RustVoid")
489490
{
490-
return ClassDefIdx(cref);
491+
return Ok(ClassDefIdx(cref));
491492
}
492493
panic!()
493494
}
494495
self.class_defs.insert(ClassDefIdx(cref), def.clone());
495-
ClassDefIdx(cref)
496+
Ok(ClassDefIdx(cref))
496497
}
497498
pub fn main_module(&mut self) -> ClassDefIdx {
498499
let main_module = self.alloc_string(MAIN_MODULE);
@@ -515,7 +516,7 @@ impl Assembly {
515516
if self.class_defs.contains_key(&ClassDefIdx(cref)) {
516517
ClassDefIdx(cref)
517518
} else {
518-
self.class_def(class_def)
519+
self.class_def(class_def).unwrap()
519520
}
520521
}
521522
/// Adds a method definition to this assembly.
@@ -794,6 +795,7 @@ impl Assembly {
794795
None,
795796
true,
796797
))
798+
.unwrap()
797799
}
798800
/// Converts the old assembly repr to the new one.
799801
#[must_use]

cilly/src/v2/builtins/mod.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -437,18 +437,20 @@ pub fn insert_exception(asm: &mut Assembly, patcher: &mut MissingMethodPatcher)
437437
let data_pointer = asm.alloc_string("data_pointer");
438438
let this = asm.alloc_string("this");
439439
let extends = Some(ClassRef::exception(asm));
440-
let rust_exception = asm.class_def(ClassDef::new(
441-
rust_exception,
442-
false,
443-
0,
444-
extends,
445-
vec![(Type::Int(Int::USize), data_pointer, None)],
446-
vec![],
447-
Access::Public,
448-
None,
449-
None,
450-
true,
451-
));
440+
let rust_exception = asm
441+
.class_def(ClassDef::new(
442+
rust_exception,
443+
false,
444+
0,
445+
extends,
446+
vec![(Type::Int(Int::USize), data_pointer, None)],
447+
vec![],
448+
Access::Public,
449+
None,
450+
None,
451+
true,
452+
))
453+
.unwrap();
452454
let ctor = asm.alloc_string(".ctor");
453455
let sig = asm.sig(
454456
[Type::ClassRef(*rust_exception), Type::Int(Int::USize)],

cilly/src/v2/builtins/thread.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,21 @@ pub fn instert_threading(asm: &mut Assembly, patcher: &mut MissingMethodPatcher)
412412
let start_fn_tpe = Type::FnPtr(start_fn_sig);
413413
let start_fn = asm.alloc_string("start_fn");
414414
let data = asm.alloc_string("data");
415-
let unmanaged_start = asm.class_def(ClassDef::new(
416-
uts,
417-
false,
418-
0,
419-
Some(object),
420-
vec![(start_fn_tpe, start_fn, None), (void_ptr, data, None)],
421-
vec![],
422-
// TODO: fix the bug which causes this to be cleaned up by dead code elimination when access is set to Public.
423-
Access::Extern,
424-
None,
425-
None,
426-
true,
427-
));
415+
let unmanaged_start = asm
416+
.class_def(ClassDef::new(
417+
uts,
418+
false,
419+
0,
420+
Some(object),
421+
vec![(start_fn_tpe, start_fn, None), (void_ptr, data, None)],
422+
vec![],
423+
// TODO: fix the bug which causes this to be cleaned up by dead code elimination when access is set to Public.
424+
Access::Extern,
425+
None,
426+
None,
427+
true,
428+
))
429+
.unwrap();
428430

429431
let ctor = asm.alloc_string(".ctor");
430432
let this = asm.alloc_node(CILNode::LdArg(0));

cilly/src/v2/class.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ use crate::Access;
66
use crate::{utilis::assert_unique, IString};
77
use serde::{Deserialize, Serialize};
88
use std::{num::NonZeroU32, ops::Deref};
9+
#[derive(Debug)]
10+
pub enum LayoutError {
11+
ManagedRefInOverlapingField {
12+
owner: String,
13+
field: String,
14+
name: String,
15+
},
16+
}
917
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
1018
pub struct ClassDefIdx(pub Interned<ClassRef>);
1119
impl ClassDefIdx {
@@ -515,6 +523,20 @@ impl ClassDef {
515523
assert_eq!(self.generics, 0);
516524
ClassRef::new(self.name, None, self.is_valuetype, vec![].into())
517525
}
526+
pub fn layout_check(&self, asm: &Assembly) -> Result<(), LayoutError> {
527+
if !self.has_nonveralpping_layout() {
528+
for (t, name, _offset) in self.fields() {
529+
if t.is_gcref(asm) {
530+
return Err(LayoutError::ManagedRefInOverlapingField {
531+
owner: asm[self.name()].into(),
532+
field: t.mangle(asm),
533+
name: asm[*name].into(),
534+
});
535+
}
536+
}
537+
}
538+
Ok(())
539+
}
518540
pub fn add_def(&mut self, val: MethodDefIdx) {
519541
self.methods.push(val);
520542
assert_unique(self.methods(), "add_def failed: method were not unique!");

cilly/src/v2/opt/mod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use root::root_opt;
44
use super::Float;
55

66
use super::{
7-
bimap::Interned, cilroot::BranchCond, method::LocalDef, typecheck::display_typecheck_err,
7+
bimap::Interned,
8+
cilroot::BranchCond,
9+
method::LocalDef,
10+
typecheck::{display_typecheck_err, TypeCheckError},
811
BasicBlock, CILIter, CILIterElem, CILNode, CILRoot, FieldDesc, FnSig, Int, MethodImpl, Type,
912
};
1013
use crate::{Assembly, MethodDef};
@@ -650,19 +653,19 @@ impl MethodDef {
650653
});
651654
}
652655
}
653-
pub fn typecheck(&mut self, asm: &mut Assembly) {
656+
pub fn typecheck(&mut self, asm: &mut Assembly) -> Result<(), TypeCheckError> {
654657
let sig = self.sig();
655658
let locals = self.iter_locals(asm).cloned().collect::<Vec<_>>();
656-
let name = self.name();
657659
if let Some(roots) = self.iter_roots_mut() {
658-
roots.for_each(|root| {
660+
for root in roots {
659661
let check = asm.get_root(*root).clone().typecheck(sig, &locals, asm);
660662
if check.is_err() {
661663
display_typecheck_err(*root, asm, sig, &locals);
662664
};
663-
check.unwrap_or_else(|_| eprintln!("Could not verify method {}", &asm[name]))
664-
})
665+
check?
666+
}
665667
}
668+
Ok(())
666669
}
667670
pub fn optimize(
668671
&mut self,

cilly/src/v2/tpe/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ pub enum GenericKind {
3939
TypeGeneric,
4040
}
4141
impl Type {
42+
/// Checks if this type is a GC reference. This function may raise false positive.
43+
pub fn is_gcref(&self, asm: &Assembly) -> bool {
44+
match self {
45+
Type::ClassRef(c) => !asm[*c].is_valuetype(),
46+
// Conservatively assume all C# generic. *could* be GC refs.
47+
Type::PlatformGeneric(_, _) => true,
48+
Type::PlatformArray { .. } | Type::PlatformObject | Type::PlatformString => true,
49+
Type::Int(_)
50+
| Type::Float(_)
51+
| Type::Bool
52+
| Type::PlatformChar
53+
| Type::Void
54+
| Type::Ptr(_)
55+
| Type::Ref(_)
56+
| Type::FnPtr(_)
57+
| Type::SIMDVector(_) => false,
58+
}
59+
}
4260
pub fn iter_class_refs<'a, 'asm: 'a>(
4361
&'a self,
4462
asm: &'asm Assembly,

cilly/src/v2/typecheck.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ pub enum TypeCheckError {
197197
/// The kind of operation that was done.
198198
op: BinOp,
199199
},
200+
ManagedPtrCast {
201+
src: String,
202+
dst: String,
203+
},
200204
}
201205
/// Converts a typecheck error to a graph representing the issue with the typecheck process.
202206
pub fn typecheck_err_to_string(
@@ -772,15 +776,27 @@ impl CILNode {
772776
let arg = asm.get_node(*arg).clone();
773777
let arg_tpe = arg.typecheck(sig, locals, asm)?;
774778
match arg_tpe {
775-
Type::Ptr(_)
776-
| Type::Ref(_)
777-
| Type::Int(Int::USize | Int::ISize)
778-
| Type::FnPtr(_) => (),
779+
Type::Ptr(inner) | Type::Ref(inner) => {
780+
if asm[inner].is_gcref(asm) {
781+
return Err(TypeCheckError::ManagedPtrCast {
782+
src: arg_tpe.mangle(asm),
783+
dst: res.as_ref().as_type().mangle(asm),
784+
});
785+
}
786+
}
787+
788+
Type::Int(Int::USize | Int::ISize) | Type::FnPtr(_) => (),
779789
_ => Err(TypeCheckError::InvalidPtrCast {
780790
expected: res.as_ref().clone(),
781791
got: arg_tpe,
782792
})?,
783793
};
794+
if res.as_ref().as_type().is_gcref(asm) {
795+
return Err(TypeCheckError::ManagedPtrCast {
796+
src: arg_tpe.mangle(asm),
797+
dst: res.as_ref().as_type().mangle(asm),
798+
});
799+
}
784800
Ok(res.as_ref().as_type())
785801
}
786802
CILNode::LdFieldAdress { addr, field } => {

0 commit comments

Comments
 (0)