Skip to content

Commit a051825

Browse files
committed
Fix safety issues of some LLVM components
- Remove dependency on utilities
1 parent 4c9dd8f commit a051825

File tree

13 files changed

+359
-2584
lines changed

13 files changed

+359
-2584
lines changed

Cargo.lock

+179-2,429
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
name = "wasmo_runtime"
33
version = "0.1.0"
44
edition = "2021"
5+
description = "The Wasmo Runtime"
6+
license-file = "../LICENSE"
7+
repository = "https://github.com/appcypher/wasmo"
58

69
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
710

811
[dependencies]
9-
utilities = { path = "../../utilities" }
12+
anyhow = "1.0"
1013
wasmparser = "0.82.0"
1114
env_logger = "0.9.0"
1215
wat = "1.0.41"

runtime/lib/api/instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::Store;
44
use crate::compiler::value::Value;
55
use crate::{Imports, Module};
6-
use utilities::result::Result;
6+
use anyhow::Result;
77

88
/// An Instance is a fully resolved wasm runtime context.
99
/// External references (globals, functions, memories, tables) are resolved.

runtime/lib/api/module.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright 2022 the Gigamono authors. All rights reserved. GPL-3.0 License.
22

33
use crate::{compiler::Compiler, Imports, Instance, Options};
4+
use anyhow::Result;
45
use serde::{Deserialize, Serialize};
5-
use utilities::result::Result;
66

77
/// A WebAssembly module with compiled code but with unresolved external references.
88
/// Memories and tables are also not created yet.

runtime/lib/compiler/compiler.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::pin::Pin;
55
use serde::{Deserialize, Serialize};
66

77
use log::debug;
8-
use utilities::result::Result;
8+
use anyhow::Result;
99
use wasmparser::{
1010
DataSectionReader, ElementSectionReader, ExportSectionReader, FunctionBody,
1111
FunctionSectionReader, GlobalSectionReader, ImportSectionEntryType, ImportSectionReader,

runtime/lib/compiler/llvm.rs

-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ mod function;
55
mod llvm;
66
mod module;
77
mod types;
8-
mod utils;
98

109
pub(crate) use llvm::*;

runtime/lib/compiler/llvm/context.rs

+22-22
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
// Copyright 2022 the Gigamono authors. All rights reserved. GPL-3.0 License.
22

3-
use std::pin::Pin;
3+
use std::rc::Rc;
44

5+
use anyhow::Result;
56
use llvm_sys::{
6-
core::{
7-
LLVMContextCreate, LLVMContextDispose, LLVMDoubleTypeInContext, LLVMFloatTypeInContext,
8-
LLVMInt32TypeInContext, LLVMInt64TypeInContext,
9-
},
7+
core::{LLVMContextCreate, LLVMContextDispose},
108
prelude::LLVMContextRef,
119
};
1210

13-
use super::types::{LLFunctionType, LLType, LLTypeRef};
11+
use super::{
12+
module::LLModule,
13+
types::{LLFunctionType, LLType, LLTypeKind},
14+
};
1415

1516
/// This a wrapper for LLVM Context.
17+
///
18+
/// # Ownership
19+
/// Owns the LLVM Module.
1620
#[derive(Debug)]
1721
pub(crate) struct LLContext {
1822
context_ref: LLVMContextRef,
@@ -25,40 +29,36 @@ impl LLContext {
2529
}
2630
}
2731

32+
pub(crate) fn create_module(&self, name: &str) -> Result<LLModule> {
33+
LLModule::new(name, self)
34+
}
35+
2836
pub(crate) fn as_ptr(&self) -> LLVMContextRef {
2937
self.context_ref
3038
}
3139

3240
pub(crate) fn i64_type(&self) -> LLType {
33-
LLType::I64(LLTypeRef::new(unsafe {
34-
LLVMInt64TypeInContext(self.context_ref)
35-
}))
41+
LLType::new(self, LLTypeKind::I64)
3642
}
3743

3844
pub(crate) fn i32_type(&self) -> LLType {
39-
LLType::I64(LLTypeRef::new(unsafe {
40-
LLVMInt32TypeInContext(self.context_ref)
41-
}))
45+
LLType::new(self, LLTypeKind::I32)
4246
}
4347

4448
pub(crate) fn f64_type(&self) -> LLType {
45-
LLType::I64(LLTypeRef::new(unsafe {
46-
LLVMDoubleTypeInContext(self.context_ref)
47-
}))
49+
LLType::new(self, LLTypeKind::F64)
4850
}
4951

5052
pub(crate) fn f32_type(&self) -> LLType {
51-
LLType::I64(LLTypeRef::new(unsafe {
52-
LLVMFloatTypeInContext(self.context_ref)
53-
}))
53+
LLType::new(self, LLTypeKind::F32)
5454
}
5555

56-
pub(crate) fn function_type<'t>(
56+
pub(crate) fn function_type(
5757
&self,
58-
params: &'t [LLType],
59-
result: &'t LLType,
58+
params: &[LLType],
59+
result: &LLType,
6060
is_varargs: bool,
61-
) -> Pin<Box<LLFunctionType<'t>>> {
61+
) -> Rc<LLFunctionType> {
6262
LLFunctionType::new(params, result, is_varargs)
6363
}
6464
}

runtime/lib/compiler/llvm/function.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
11
// Copyright 2022 the Gigamono authors. All rights reserved. GPL-3.0 License.
22

3-
use std::marker::PhantomData;
4-
use utilities::result::Result;
3+
use anyhow::Result;
4+
use std::{ffi::CString, rc::Rc};
55

66
use llvm_sys::{core::LLVMAddFunction, prelude::LLVMValueRef};
77

8-
use super::{module::LLModule, types::LLFunctionType, utils::LLString};
8+
use super::{module::LLModule, types::LLFunctionType};
99

10-
pub(crate) struct LLFunction<'m, 's, 't> {
10+
/// This is a wrapper for LLVM Function.
11+
///
12+
/// # Safety
13+
/// It is unsafe to use the reference of `LLFunctionType` because its params can be independently freed.
14+
/// Holding an `Rc` to it ensures that that does not happen.
15+
pub(crate) struct LLFunction {
1116
function_ref: LLVMValueRef,
12-
_module: PhantomData<&'m ()>,
13-
_name: PhantomData<&'s ()>,
14-
_signature: PhantomData<&'t ()>,
17+
function_type: Rc<LLFunctionType>,
1518
}
1619

17-
impl<'m, 's, 't> LLFunction<'m, 's, 't> {
18-
pub(crate) fn attach(
19-
module: &'m LLModule,
20-
name: &'s LLString,
21-
signature: &'t LLFunctionType,
20+
impl LLFunction {
21+
/// Creates a new LLVM function.
22+
///
23+
/// # Safety
24+
/// The use of temporary `CString` expecting that value will be copied in `LLVMAddFunction` might not be safe.
25+
///
26+
/// - https://llvm.org/doxygen/Twine_8h_source.html#l00477
27+
/// - https://llvm.org/doxygen/Value_8cpp_source.html#l00315
28+
pub(crate) fn new(
29+
name: &str,
30+
module: &LLModule,
31+
function_type: Rc<LLFunctionType>,
2232
) -> Result<Self> {
2333
Ok(Self {
2434
function_ref: unsafe {
25-
LLVMAddFunction(module.as_ptr(), name.as_ptr(), signature.as_ptr())
35+
LLVMAddFunction(
36+
module.as_ptr(),
37+
CString::new(name)?.as_ptr(),
38+
function_type.as_ptr(),
39+
)
2640
},
27-
_module: PhantomData,
28-
_name: PhantomData,
29-
_signature: PhantomData,
41+
function_type,
3042
})
3143
}
3244
}

runtime/lib/compiler/llvm/llvm.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
use std::pin::Pin;
44

5-
use super::{context::LLContext, module::LLModule, utils::LLString};
5+
use super::{context::LLContext, module::LLModule};
66
use llvm_sys::core::LLVMShutdown;
7-
use utilities::result::Result;
7+
use anyhow::Result;
88

99
/// Converts WebAssembly semantics to LLVM code, handles materialization.
1010
///
@@ -44,8 +44,8 @@ use utilities::result::Result;
4444
/// - loading important values like memory address into registers
4545
#[derive(Debug)]
4646
pub(crate) struct LLVM {
47-
pub(crate) module: Option<Pin<Box<LLModule>>>,
48-
context: LLContext,
47+
pub(crate) context: LLContext,
48+
pub(crate) module: Option<LLModule>,
4949
}
5050

5151
impl LLVM {
@@ -59,10 +59,7 @@ impl LLVM {
5959
});
6060

6161
// The module field references the context field so this is self-referential.
62-
this.module = Some(LLModule::new(
63-
LLString::try_from("main module")?,
64-
this.context.as_ptr(),
65-
)?);
62+
this.module = Some(LLModule::new("initial", &this.context)?);
6663

6764
Ok(this)
6865
}

runtime/lib/compiler/llvm/module.rs

+35-23
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// Copyright 2022 the Gigamono authors. All rights reserved. GPL-3.0 License.
22

3-
use std::pin::Pin;
3+
use std::{ffi::CString, rc::Rc};
44

5-
use utilities::result::Result;
5+
use anyhow::Result;
66

77
use llvm_sys::{
88
core::{LLVMDumpModule, LLVMModuleCreateWithNameInContext},
9-
prelude::{LLVMContextRef, LLVMModuleRef},
9+
prelude::LLVMModuleRef,
1010
};
1111

12-
use super::{function::LLFunction, types::LLFunctionType, utils::LLString};
12+
use super::{context::LLContext, function::LLFunction, types::LLFunctionType};
1313

1414
/// A wrapper for LLVM Module.
1515
///
@@ -18,36 +18,48 @@ use super::{function::LLFunction, types::LLFunctionType, utils::LLString};
1818
/// When a Module references a Context, the Context frees it when it gets dropped.
1919
///
2020
/// We leverage this behavior by not disposing the Module explicitly on drop, letting associated Context do the job.
21-
/// This is safe because we can only create a Module from a Context.
21+
///
22+
/// WARNING: This is safe only if we can only create a Module from a Context.
2223
///
2324
/// NOTE: We can't use lifetime parameter since it leads to unresolvable self-referential structs when an `LLModule` is stored in the same struct as the associated `LLContext`.
2425
///
25-
/// https://lists.llvm.org/pipermail/llvm-dev/2018-September/126134.html
26+
/// - https://lists.llvm.org/pipermail/llvm-dev/2018-September/126134.html
27+
/// - https://llvm.org/doxygen/Module_8cpp_source.html#l00079
28+
/// - https://llvm.org/doxygen/LLVMContextImpl_8cpp_source.html#l00052
29+
///
30+
/// # Ownership
31+
/// ???
32+
///
2633
#[derive(Debug)]
2734
pub(crate) struct LLModule {
28-
name: Pin<Box<LLString>>,
2935
module_ref: LLVMModuleRef,
3036
}
3137

3238
impl LLModule {
33-
/// This is the only way to create an LLModule to ensure it has an associated Context.
34-
pub(crate) fn new(name: Pin<Box<LLString>>, context: LLVMContextRef) -> Result<Pin<Box<Self>>> {
35-
let mut this = Self {
36-
name,
37-
module_ref: std::ptr::null_mut(),
38-
};
39-
40-
this.module_ref = unsafe { LLVMModuleCreateWithNameInContext(this.name.as_ptr(), context) };
41-
42-
Ok(Box::pin(this))
39+
/// This is the only way to create an LLModule to ensure it has an associated Context that can dispose it.
40+
///
41+
/// # Safety
42+
/// A temporary `CString` name is safe to use here because it is copied into the LLVM Module.
43+
///
44+
/// - https://llvm.org/doxygen/Module_8cpp_source.html#l00072
45+
pub(crate) fn new(name: &str, context: &LLContext) -> Result<Self> {
46+
Ok(Self {
47+
module_ref: unsafe {
48+
LLVMModuleCreateWithNameInContext(CString::new(name)?.as_ptr(), context.as_ptr())
49+
},
50+
})
4351
}
4452

45-
pub(crate) fn add_function<'m, 's, 't>(
46-
&'m self,
47-
name: &'s LLString,
48-
signature: &'t LLFunctionType,
49-
) -> Result<LLFunction<'m, 's, 't>> {
50-
LLFunction::attach(self, name, signature)
53+
/// Adds a function to the module.
54+
///
55+
/// # Safety
56+
/// TODO(appcypher): Investigate safety properly.
57+
pub(crate) fn add_function(
58+
&self,
59+
name: &str,
60+
signature: Rc<LLFunctionType>,
61+
) -> Result<LLFunction> {
62+
LLFunction::new(name, self, signature)
5163
}
5264

5365
pub(crate) fn as_ptr(&self) -> LLVMModuleRef {

0 commit comments

Comments
 (0)