Skip to content

Commit 26a6ded

Browse files
authored
Merge pull request #198 from madsmtm/verify-under-debug-assertions
Rework verification feature selection
2 parents 30296a2 + 0e54b46 commit 26a6ded

File tree

18 files changed

+463
-220
lines changed

18 files changed

+463
-220
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ jobs:
155155
# Use --no-fail-fast, except with dinghy
156156
TESTARGS: ${{ matrix.dinghy && ' ' || '--no-fail-fast' }} ${{ matrix.test-args }}
157157
SOME_FEATURES: ${{ matrix.features || 'malloc,block,exception,foundation' }}
158-
FEATURES: ${{ matrix.features || 'malloc,block,exception,foundation,catch-all,verify_message,uuid' }}
158+
FEATURES: ${{ matrix.features || 'malloc,block,exception,foundation,catch-all,verify,uuid' }}
159159
UNSTABLE_FEATURES: ${{ matrix.unstable-features || 'unstable-autoreleasesafe,unstable-c-unwind' }}
160160
CMD: cargo
161161

crates/objc2-encode/src/encoding_box.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,27 @@ impl EncodingBox {
105105
Encoding::ULongLong => Self::ULongLong,
106106
_ => unreachable!(),
107107
};
108+
109+
/// Parse and comsume an encoding from the start of a string.
110+
///
111+
/// This is can be used to parse concatenated encodings, such as those
112+
/// returned by `method_getTypeEncoding`.
113+
///
114+
/// [`from_str`][Self::from_str] is simpler, use that instead if you can.
115+
pub fn from_start_of_str(s: &mut &str) -> Result<Self, ParseError> {
116+
let mut parser = Parser::new(s);
117+
parser.strip_leading_qualifiers();
118+
119+
match parser.parse_encoding() {
120+
Err(err) => Err(ParseError::new(parser, err)),
121+
Ok(encoding) => {
122+
let remaining = parser.remaining();
123+
*s = remaining;
124+
125+
Ok(encoding)
126+
}
127+
}
128+
}
108129
}
109130

110131
/// Same formatting as [`Encoding`]'s `Display` implementation.
@@ -213,4 +234,19 @@ mod tests {
213234
assert_eq!(expected, actual);
214235
assert_eq!(expected.to_string(), "AA{a}");
215236
}
237+
238+
#[test]
239+
fn parse_part_of_string() {
240+
let mut s = "{a}c";
241+
242+
let expected = EncodingBox::Struct("a".into(), None);
243+
let actual = EncodingBox::from_start_of_str(&mut s).unwrap();
244+
assert_eq!(expected, actual);
245+
246+
let expected = EncodingBox::Char;
247+
let actual = EncodingBox::from_start_of_str(&mut s).unwrap();
248+
assert_eq!(expected, actual);
249+
250+
assert_eq!(s, "");
251+
}
216252
}

crates/objc2-encode/src/parse.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ impl<'a> Parser<'a> {
117117
}
118118
}
119119

120+
pub(crate) fn remaining(&self) -> &'a str {
121+
&self.data[self.split_point..]
122+
}
123+
120124
fn peek(&self) -> Result<u8> {
121125
self.try_peek().ok_or(ErrorKind::UnexpectedEnd)
122126
}

crates/objc2/CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,35 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3131
in methods declared with `extern_methods!`, and let that be the `NSError**`
3232
parameter.
3333
* Added `#[method_id(...)]` attribute to `extern_methods!`.
34+
* Added `"verify"` feature as a replacement for the `"verify_message"`
35+
feature.
3436

3537
### Changed
3638
* Allow other types than `&Class` as the receiver in `msg_send_id!` methods
3739
of the `new` family.
3840
* **BREAKING**: Changed the `Allocated` struct to be used as `Allocated<T>`
3941
instead of `Id<Allocated<T>, O>`.
4042
* Verify the message signature of overriden methods when declaring classes if
41-
the `verify_message` feature is enabled.
43+
the `verify` feature is enabled.
4244
* Verify in `declare_class!` that protocols are implemented correctly.
4345
* **BREAKING**: Changed the name of the attribute macro in `extern_methods`
4446
from `#[sel(...)]` to `#[method(...)]`.
4547
* **BREAKING**: Changed `extern_methods!` and `declare_class!` such that
4648
associated functions whoose first parameter is called `this`, is treated as
4749
instance methods instead of class methods.
50+
* **BREAKING**: Message verification is now enabled by default. Your message
51+
sends might panic with `debug_assertions` enabled if they are detected to
52+
be invalid. Test your code to see if that is the case!
4853

4954
### Fixed
5055
* Fixed duplicate selector extraction in `extern_methods!`.
5156
* Fixed using `deprecated` attributes in `declare_class!`.
5257
* Fixed `cfg` attributes on methods and implementations in `declare_class!`.
5358

59+
### Removed
60+
* **BREAKING**: Removed `"verify_message"` feature. It has been mostly
61+
replaced by `debug_assertions` and the `"verify"` feature.
62+
5463

5564
## 0.3.0-beta.3 - 2022-09-01
5665

crates/objc2/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ exception = ["objc-sys/unstable-exception"]
3434
# Wrap every `objc2::msg_send` call in a `@try/@catch` block
3535
catch-all = ["exception"]
3636

37-
# Verify type encodings on every message send
38-
# Only intended to be used while debugging!
39-
verify_message = ["malloc"] # TODO: Remove malloc feature here
37+
# Enable all verification steps when debug assertions are enabled.
38+
verify = ["malloc"]
4039

4140
# Expose features that require linking to `libc::free`.
4241
#

crates/objc2/src/__macro_helpers.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
#[cfg(feature = "verify_message")]
1+
#[cfg(all(debug_assertions, feature = "verify"))]
22
use alloc::vec::Vec;
33
use core::ptr;
4-
#[cfg(feature = "verify_message")]
4+
#[cfg(all(debug_assertions, feature = "verify"))]
55
use std::collections::HashSet;
66

77
use crate::declare::ClassBuilder;
8-
#[cfg(feature = "verify_message")]
8+
#[cfg(all(debug_assertions, feature = "verify"))]
99
use crate::declare::MethodImplementation;
1010
use crate::encode::Encode;
1111
use crate::message::__TupleExtender;
1212
use crate::rc::{Allocated, Id, Ownership, Shared};
13-
#[cfg(feature = "verify_message")]
13+
#[cfg(all(debug_assertions, feature = "verify"))]
1414
use crate::runtime::MethodDescription;
1515
use crate::runtime::{Class, Object, Protocol, Sel};
1616
use crate::{Message, MessageArguments, MessageReceiver};
@@ -478,7 +478,7 @@ impl ModuleInfo {
478478

479479
impl ClassBuilder {
480480
#[doc(hidden)]
481-
#[cfg(feature = "verify_message")]
481+
#[cfg(all(debug_assertions, feature = "verify"))]
482482
pub fn __add_protocol_methods<'a, 'b>(
483483
&'a mut self,
484484
protocol: &'b Protocol,
@@ -497,7 +497,7 @@ impl ClassBuilder {
497497
}
498498

499499
#[doc(hidden)]
500-
#[cfg(not(feature = "verify_message"))]
500+
#[cfg(not(all(debug_assertions, feature = "verify")))]
501501
#[inline]
502502
pub fn __add_protocol_methods(&mut self, protocol: &Protocol) -> &mut Self {
503503
self.add_protocol(protocol);
@@ -509,7 +509,7 @@ impl ClassBuilder {
509509
/// - Only methods on the protocol are overriden.
510510
/// - TODO: The methods have the correct signature.
511511
/// - All required methods are overridden.
512-
#[cfg(feature = "verify_message")]
512+
#[cfg(all(debug_assertions, feature = "verify"))]
513513
pub struct ClassProtocolMethodsBuilder<'a, 'b> {
514514
builder: &'a mut ClassBuilder,
515515
protocol: &'b Protocol,
@@ -521,7 +521,7 @@ pub struct ClassProtocolMethodsBuilder<'a, 'b> {
521521
registered_class_methods: HashSet<Sel>,
522522
}
523523

524-
#[cfg(feature = "verify_message")]
524+
#[cfg(all(debug_assertions, feature = "verify"))]
525525
impl ClassProtocolMethodsBuilder<'_, '_> {
526526
#[inline]
527527
pub unsafe fn add_method<T, F>(&mut self, sel: Sel, func: F)
@@ -579,7 +579,7 @@ impl ClassProtocolMethodsBuilder<'_, '_> {
579579
}
580580
}
581581

582-
#[cfg(feature = "verify_message")]
582+
#[cfg(all(debug_assertions, feature = "verify"))]
583583
impl Drop for ClassProtocolMethodsBuilder<'_, '_> {
584584
fn drop(&mut self) {
585585
for desc in &self.required_instance_methods {
@@ -778,7 +778,7 @@ mod tests {
778778

779779
#[test]
780780
#[should_panic = "unexpected NULL newMethodOnInstance; receiver was NULL"]
781-
#[cfg(not(feature = "verify_message"))] // Does NULL receiver checks
781+
#[cfg(not(debug_assertions))] // Does NULL receiver checks
782782
fn test_new_any_with_null_receiver() {
783783
let obj: *const NSObject = ptr::null();
784784
let _obj: Id<Object, Shared> = unsafe { msg_send_id![obj, newMethodOnInstance] };
@@ -801,7 +801,7 @@ mod tests {
801801

802802
#[test]
803803
#[should_panic = "failed allocating object"]
804-
#[cfg(not(feature = "verify_message"))] // Does NULL receiver checks
804+
#[cfg(not(debug_assertions))] // Does NULL receiver checks
805805
fn test_init_with_null_receiver() {
806806
let obj: Option<Allocated<RcTestObject>> = None;
807807
let _obj: Id<RcTestObject, Owned> = unsafe { msg_send_id![obj, init] };
@@ -823,7 +823,7 @@ mod tests {
823823

824824
#[test]
825825
#[should_panic = "unexpected NULL description; receiver was NULL"]
826-
#[cfg(not(feature = "verify_message"))] // Does NULL receiver checks
826+
#[cfg(not(debug_assertions))] // Does NULL receiver checks
827827
fn test_normal_with_null_receiver() {
828828
let obj: *const NSObject = ptr::null();
829829
let _obj: Id<NSString, Shared> = unsafe { msg_send_id![obj, description] };

0 commit comments

Comments
 (0)