|
@@ -20,9 +20,11 @@ use num_traits::{One, Zero};
|
|
|
use petgraph::algo::{all_simple_paths, tarjan_scc};
|
|
use petgraph::algo::{all_simple_paths, tarjan_scc};
|
|
|
use petgraph::stable_graph::IndexType;
|
|
use petgraph::stable_graph::IndexType;
|
|
|
use petgraph::Directed;
|
|
use petgraph::Directed;
|
|
|
|
|
+use phf::{phf_set, Set};
|
|
|
use solang_parser::diagnostics::Note;
|
|
use solang_parser::diagnostics::Note;
|
|
|
use solang_parser::{doccomment::DocComment, pt, pt::CodeLocation};
|
|
use solang_parser::{doccomment::DocComment, pt, pt::CodeLocation};
|
|
|
use std::collections::HashSet;
|
|
use std::collections::HashSet;
|
|
|
|
|
+use std::ops::MulAssign;
|
|
|
use std::{fmt::Write, ops::Mul};
|
|
use std::{fmt::Write, ops::Mul};
|
|
|
|
|
|
|
|
type Graph = petgraph::Graph<(), usize, Directed, usize>;
|
|
type Graph = petgraph::Graph<(), usize, Directed, usize>;
|
|
@@ -288,7 +290,8 @@ fn check_infinite_struct_size(graph: &Graph, nodes: Vec<usize>, ns: &mut Namespa
|
|
|
let mut infinite_edge = false;
|
|
let mut infinite_edge = false;
|
|
|
for edge in graph.edges_connecting(a.into(), b.into()) {
|
|
for edge in graph.edges_connecting(a.into(), b.into()) {
|
|
|
match &ns.structs[a].fields[*edge.weight()].ty {
|
|
match &ns.structs[a].fields[*edge.weight()].ty {
|
|
|
- Type::Array(_, dims) if dims.first() != Some(&ArrayLength::Dynamic) => {}
|
|
|
|
|
|
|
+ Type::Array(_, dims) if dims.contains(&ArrayLength::Dynamic) => continue,
|
|
|
|
|
+ Type::Array(_, _) => {}
|
|
|
Type::Struct(StructType::UserDefined(_)) => {}
|
|
Type::Struct(StructType::UserDefined(_)) => {}
|
|
|
_ => continue,
|
|
_ => continue,
|
|
|
}
|
|
}
|
|
@@ -367,6 +370,7 @@ fn find_struct_recursion(ns: &mut Namespace) {
|
|
|
check_recursive_struct_field(n.index(), &graph, ns);
|
|
check_recursive_struct_field(n.index(), &graph, ns);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
for n in 0..ns.structs.len() {
|
|
for n in 0..ns.structs.len() {
|
|
|
let mut notes = vec![];
|
|
let mut notes = vec![];
|
|
|
for field in ns.structs[n].fields.iter().filter(|f| f.infinite_size) {
|
|
for field in ns.structs[n].fields.iter().filter(|f| f.infinite_size) {
|
|
@@ -1579,7 +1583,11 @@ impl Type {
|
|
|
/// which is not accounted for.
|
|
/// which is not accounted for.
|
|
|
pub fn solana_storage_size(&self, ns: &Namespace) -> BigInt {
|
|
pub fn solana_storage_size(&self, ns: &Namespace) -> BigInt {
|
|
|
match self {
|
|
match self {
|
|
|
- Type::Array(_, dims) if dims.first() == Some(&ArrayLength::Dynamic) => 4.into(),
|
|
|
|
|
|
|
+ Type::Array(_, dims) if dims.contains(&ArrayLength::Dynamic) => {
|
|
|
|
|
+ let size = dynamic_array_size(dims);
|
|
|
|
|
+ // A pointer is four bytes on Solana
|
|
|
|
|
+ size * 4
|
|
|
|
|
+ }
|
|
|
Type::Array(ty, dims) => ty.solana_storage_size(ns).mul(
|
|
Type::Array(ty, dims) => ty.solana_storage_size(ns).mul(
|
|
|
dims.iter()
|
|
dims.iter()
|
|
|
.map(|d| match d {
|
|
.map(|d| match d {
|
|
@@ -1707,8 +1715,10 @@ impl Type {
|
|
|
Type::Value => BigInt::from(ns.value_length),
|
|
Type::Value => BigInt::from(ns.value_length),
|
|
|
Type::Uint(n) | Type::Int(n) => BigInt::from(n / 8),
|
|
Type::Uint(n) | Type::Int(n) => BigInt::from(n / 8),
|
|
|
Type::Rational => unreachable!(),
|
|
Type::Rational => unreachable!(),
|
|
|
- Type::Array(_, dims) if dims.first() == Some(&ArrayLength::Dynamic) => {
|
|
|
|
|
- BigInt::from(4)
|
|
|
|
|
|
|
+ Type::Array(_, dims) if dims.contains(&ArrayLength::Dynamic) => {
|
|
|
|
|
+ let size = dynamic_array_size(dims);
|
|
|
|
|
+ // A pointer is four bytes on Solana
|
|
|
|
|
+ size * 4
|
|
|
}
|
|
}
|
|
|
Type::Array(ty, dims) => {
|
|
Type::Array(ty, dims) => {
|
|
|
let pointer_size = BigInt::from(4);
|
|
let pointer_size = BigInt::from(4);
|
|
@@ -1756,7 +1766,9 @@ impl Type {
|
|
|
.filter(|f| !f.infinite_size)
|
|
.filter(|f| !f.infinite_size)
|
|
|
.map(|f| f.ty.storage_slots(ns))
|
|
.map(|f| f.ty.storage_slots(ns))
|
|
|
.sum(),
|
|
.sum(),
|
|
|
- Type::Array(_, dims) if dims.first() == Some(&ArrayLength::Dynamic) => 1.into(),
|
|
|
|
|
|
|
+ Type::Array(_, dims) if dims.contains(&ArrayLength::Dynamic) => {
|
|
|
|
|
+ dynamic_array_size(dims)
|
|
|
|
|
+ }
|
|
|
Type::Array(ty, dims) => {
|
|
Type::Array(ty, dims) => {
|
|
|
let one = 1.into();
|
|
let one = 1.into();
|
|
|
ty.storage_slots(ns)
|
|
ty.storage_slots(ns)
|
|
@@ -1787,9 +1799,7 @@ impl Type {
|
|
|
Type::Value => BigInt::from(ns.value_length),
|
|
Type::Value => BigInt::from(ns.value_length),
|
|
|
Type::Uint(n) | Type::Int(n) => BigInt::from(n / 8),
|
|
Type::Uint(n) | Type::Int(n) => BigInt::from(n / 8),
|
|
|
Type::Rational => unreachable!(),
|
|
Type::Rational => unreachable!(),
|
|
|
- Type::Array(_, dims) if dims.first() == Some(&ArrayLength::Dynamic) => {
|
|
|
|
|
- BigInt::from(4)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Type::Array(_, dims) if dims.contains(&ArrayLength::Dynamic) => BigInt::from(4),
|
|
|
Type::Array(ty, _) => {
|
|
Type::Array(ty, _) => {
|
|
|
if self.is_sparse_solana(ns) {
|
|
if self.is_sparse_solana(ns) {
|
|
|
BigInt::from(4)
|
|
BigInt::from(4)
|
|
@@ -2174,10 +2184,28 @@ impl Type {
|
|
|
|
|
|
|
|
/// These names cannot be used on Windows, even with an extension.
|
|
/// These names cannot be used on Windows, even with an extension.
|
|
|
/// shamelessly stolen from cargo
|
|
/// shamelessly stolen from cargo
|
|
|
|
|
+static WINDOWS_RESERVED: Set<&'static str> = phf_set! {
|
|
|
|
|
+ "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8",
|
|
|
|
|
+ "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
|
|
|
|
|
+};
|
|
|
fn is_windows_reserved(name: &str) -> bool {
|
|
fn is_windows_reserved(name: &str) -> bool {
|
|
|
- [
|
|
|
|
|
- "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8",
|
|
|
|
|
- "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
|
|
|
|
|
- ]
|
|
|
|
|
- .contains(&name.to_ascii_lowercase().as_str())
|
|
|
|
|
|
|
+ WINDOWS_RESERVED.contains(name.to_ascii_lowercase().as_str())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// This function calculates the size of a dynamic array.
|
|
|
|
|
+/// The reasoning is the following:
|
|
|
|
|
+/// An array `uint [2][][3][1]` is a `void * foo[3][1]`-like in C, so its size
|
|
|
|
|
+/// in storage is 3*1*ptr_size. Each pointer points to a `uint[2]` so whatever comes before the
|
|
|
|
|
+/// ultimate empty square bracket does not matter.
|
|
|
|
|
+fn dynamic_array_size(dims: &[ArrayLength]) -> BigInt {
|
|
|
|
|
+ let mut result = BigInt::one();
|
|
|
|
|
+ for dim in dims.iter().rev() {
|
|
|
|
|
+ match dim {
|
|
|
|
|
+ ArrayLength::Fixed(num) => result.mul_assign(num),
|
|
|
|
|
+ ArrayLength::Dynamic => break,
|
|
|
|
|
+ ArrayLength::AnyFixed => unreachable!("unknown dimension"),
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ result
|
|
|
}
|
|
}
|