Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reject zero type when declare event fields #774

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

vuvoth
Copy link
Contributor

@vuvoth vuvoth commented Jul 29, 2022

What was wrong?

#712

How was it fixed?

Add salsa db query is_zero_type and check declare field data in event should not zero-sized

Special thank to @Y-Nak!

To-Do

  • OPTIONAL: Update Spec if applicable

  • Add entry to the release notes (may forgo for trivial changes)

  • Clean up commit history

@vuvoth vuvoth changed the title reject zero type when declare event fields Reject zero type when declare event fields Jul 29, 2022
@@ -40,7 +40,17 @@ pub fn event_type(db: &dyn AnalyzerDb, event: EventId) -> Analysis<Rc<types::Eve
} = &field.kind;

let typ = type_desc(&mut scope, typ_node).and_then(|typ| match typ {
typ if typ.has_fixed_size(scope.db()) => Ok(typ),
typ if typ.has_fixed_size(scope.db()) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to reject all zero-sized fields. It'd be better to reject a field iff its type is zero-sized and it is indexed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 502 to 505
Type::Base(Base::Unit) => true,
Type::Contract(inner) => inner.fields(db).is_empty(),
Type::Struct(inner) => inner.fields(db).is_empty(),
_ => false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contract/struct can be zero-sized even if their fields are not empty.

Example.

struct Zero {
    x: ()
}

Also, other types can be zero-sized.

  • Tuple becomes a zero-sized type if it has no elements or all elements are zero-sized type.
  • Array becomes a zero-sized type if its length is 0 or its element type is a zero-sized type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I create salsa query is_zero_sized to handle it. I think about this should be type_size will more general.

true
}
Type::Contract(contract_id) => {
for field_type_id in db.contract_all_fields(contract_id).iter() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic to handle struct and contract very similar. Have any better way to refactor it....

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A contract type is really just an address (its size is that of the address type), so you don't need to look at the fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A contract type is really just an address (its size is that of the address type), so you don't need to look at the fields.

Thanks! I fixed it

}
true
}
Type::Generic(_) | Type::Map(_) | Type::SelfContract(_) => false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Generic type always have size > 0?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be zero-sized or not, depending on how its used. For example:

event Foo<T> {
  idx val: T
}

pub fn emit_foo<T>(ctx: Context, val: T) {
  emit Foo(val)
}

emit_foo(ctx, 10) // ok
emit_foo(ctx, ())  // not ok, T is zero-sized

For now, it's safe to use unreachable!() for this case, because we don't support generic fields in structs or events yet. When we do, we'll have to determine the size of the concrete type.

(Map and SelfContract can also be unreachable!(), as they can't appear in a field.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better we should throw fe error in this case. Use unreachable!() maybe non sense I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think returning Error here is a good option since using errors to report/hide internal bugs is not a good practice. Entering the Type::Generic arm means ICE in the current state, so unreachable!() would be suitable here.

}
true
}
Type::String(FeString { max_size }) => max_size == 0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we continue using solidity ABI, String never becomes a zero-sized type even if its max_length is 0.
Also, we allocate 256 bits to store a string length, so the minimum String size is 32 bytes even in the Fe's string representation.

crates/analyzer/src/db/queries/events.rs Outdated Show resolved Hide resolved
Comment on lines +102 to +104
pub fn is_zero_sized_cycle(_db: &dyn AnalyzerDb, _cycle: &[String], _ty: &types::TypeId) -> bool {
true
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a little bit dirty hack. I think it'd be better to detect a struct cycle in type_desc, but I'm not sure.

Co-authored-by: Yoshitomo Nakanishi <yurayura.rounin.3@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants