Skip to content

Commit

Permalink
Add APIs for BHInvocation:
Browse files Browse the repository at this point in the history
methodSignature
getReturnValue:
setReturnValue:
getArgument:atIndex:
setArgument:atIndex:
  • Loading branch information
yulingtianxia committed Aug 3, 2019
1 parent e1a6e25 commit 8af5b26
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 76 deletions.
2 changes: 1 addition & 1 deletion BlockHook.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "BlockHook"
s.version = "1.5.3"
s.version = "1.5.4"
s.summary = "Hook Objective-C blocks."
s.description = <<-DESC
Hook Objective-C blocks with libffi. It's a powerful AOP tool for blocks. BlockHook can run your code before/instead/after invoking a block. BlockHook can even notify you when a block dealloc. You can trace the whole lifecycle of a block using BlockHook!
Expand Down
30 changes: 28 additions & 2 deletions BlockHook/BlockHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
Arguments of invoking the block. Need type casting.
*/
@property (nonatomic, readonly) void *_Nullable *_Null_unspecified args;
@property (nonatomic, readonly) void *_Nullable *_Null_unspecified args DEPRECATED_MSG_ATTRIBUTE("Use getArgument:atIndex: or setArgument:atIndex: instead");

/**
Return value of invoking the block. Need type casting.
*/
@property (nonatomic, nullable, readonly) void *retValue;
@property (nonatomic, nullable, readonly) void *retValue DEPRECATED_MSG_ATTRIBUTE("Use getReturnValue: or setReturnValue: instead");

/**
Mode you want to insert your custom logic: Before, Instead, After OR Dead.
Expand Down Expand Up @@ -62,10 +62,36 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)retainArguments;

/**
Gets the receiver's return value.
If the NSInvocation object has never been invoked, the result of this method is undefined.
@param retLoc An untyped buffer into which the receiver copies its return value. It should be large enough to accommodate the value. See the discussion in NSInvocation for more information about buffer.
*/
- (void)getReturnValue:(void *)retLoc;

/**
Sets the receiver’s return value.
@param retLoc An untyped buffer whose contents are copied as the receiver's return value.
@discussion This value is normally set when you send an invokeOriginalBlock message.
*/
- (void)setReturnValue:(void *)retLoc;

/**
Sets an argument of the receiver.
@param argumentLocation An untyped buffer containing an argument to be assigned to the receiver. See the discussion in NSInvocation relating to argument values that are objects.
@param idx An integer specifying the index of the argument. Indices 0 indicates self, use indices 1 and greater for the arguments normally passed in an invocation.
*/
- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;

/**
Sets an argument of the receiver.
@param argumentLocation An untyped buffer containing an argument to be assigned to the receiver. See the discussion in NSInvocation relating to argument values that are objects.
@param idx An integer specifying the index of the argument. Indices 0 indicates self, use indices 1 and greater for the arguments normally passed in an invocation.
*/
- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;

@end
Expand Down
58 changes: 34 additions & 24 deletions BlockHook/BlockHook.m
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ @interface BHInvocation ()
@property (nonatomic, readwrite) BlockHookMode mode;
@property (nonatomic) NSMutableData *dataArgs;
@property (nonatomic) NSMutableData *dataRet;
@property (nonatomic) NSMutableDictionary *mallocMap;
@property (nonatomic) NSMutableDictionary *retainMap;
@property (nonatomic, getter=isArgumentsRetained, readwrite) BOOL argumentsRetained;
@property (nonatomic) dispatch_queue_t argumentsRetainedQueue;
Expand Down Expand Up @@ -291,14 +292,6 @@ - (void)setArgumentsRetained:(BOOL)argumentsRetained
- (void)invokeOriginalBlock
{
[self.token invokeOriginalBlockWithArgs:self.realArgs retValue:self.realRetValue];
if (self.isArgumentsRetained) {
for (NSUInteger idx = 0; idx < self.numberOfRealArgs; idx++) {
void *argBuf = self.realArgs[idx];
if (argBuf != NULL) {
free(argBuf);
}
}
}
}

- (NSMethodSignature *)methodSignature
Expand All @@ -311,7 +304,8 @@ - (void)retainArguments
if (!self.isArgumentsRetained) {
self.dataArgs = [NSMutableData dataWithLength:self.numberOfRealArgs * sizeof(void *)];
self.retainMap = [NSMutableDictionary dictionaryWithCapacity:self.numberOfRealArgs + 1];
void **args = [self.dataArgs mutableBytes];
self.mallocMap = [NSMutableDictionary dictionaryWithCapacity:self.numberOfRealArgs + 1];
void **args = self.dataArgs.mutableBytes;
for (NSUInteger idx = 0; idx < self.numberOfRealArgs; idx++) {
const char *type = NULL;
if (self.token.hasStret) {
Expand All @@ -328,7 +322,9 @@ - (void)retainArguments

NSUInteger argSize;
NSGetSizeAndAlignment(type, &argSize, NULL);
void *argBuf = malloc(argSize);
NSMutableData *argData = [NSMutableData dataWithLength:argSize];
self.mallocMap[@(idx)] = argData;
void *argBuf = argData.mutableBytes;
memcpy(argBuf, self.realArgs[idx], argSize);
args[idx] = argBuf;
[self _retainPointer:args[idx] encode:type key:@(idx)];
Expand All @@ -339,10 +335,14 @@ - (void)retainArguments
self.retValue = *((void **)args[0]);
}
else {
self.dataRet = [NSMutableData dataWithLength:sizeof(void *)];
void *ret = self.dataRet.mutableBytes;
NSUInteger retSize = self.methodSignature.methodReturnLength;
self.dataRet = [NSMutableData dataWithLength:sizeof(retSize)];
void *ret = [self.dataRet mutableBytes];
memcpy(ret, self.retValue, retSize);
NSMutableData *retData = [NSMutableData dataWithLength:retSize];
self.mallocMap[@-1] = retData;
void *retBuf = retData.mutableBytes;
memcpy(retBuf, self.retValue, retSize);
ret = retBuf;
[self _retainPointer:ret encode:self.methodSignature.methodReturnType key:@-1];
self.args = args;
self.retValue = ret;
Expand All @@ -355,23 +355,31 @@ - (void)retainArguments

- (void)getReturnValue:(void *)retLoc
{
if (!retLoc || !self.retValue) {
return;
}
NSUInteger retSize = self.methodSignature.methodReturnLength;
memcpy(retLoc, self.retValue, retSize);
}

- (void)setReturnValue:(void *)retLoc
{
if (!retLoc || !self.retValue) {
return;
}
NSUInteger retSize = self.methodSignature.methodReturnLength;
BOOL result = [self _retainPointer:retLoc encode:self.methodSignature.methodReturnType key:@-1];
if (!result) {
memcpy(self.retValue, retLoc, retSize);
if (self.isArgumentsRetained) {
[self _retainPointer:retLoc encode:self.methodSignature.methodReturnType key:@-1];
}
memcpy(self.retValue, retLoc, retSize);
}

- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx
{
if (!argumentLocation || !self.args || !self.args[idx]) {
return;
}
void *arg = self.args[idx];
assert(arg);
const char *type = [self.methodSignature getArgumentTypeAtIndex:idx];
NSUInteger argSize;
NSGetSizeAndAlignment(type, &argSize, NULL);
Expand All @@ -380,23 +388,25 @@ - (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx

- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx
{
if (!argumentLocation || !self.args || !self.args[idx]) {
return;
}
void *arg = self.args[idx];
assert(arg);
const char *type = [self.methodSignature getArgumentTypeAtIndex:idx];
NSUInteger argSize;
NSGetSizeAndAlignment(type, &argSize, NULL);
BOOL result = [self _retainPointer:argumentLocation encode:type key:@(idx)];
if (!result) {
memcpy(arg, argumentLocation, argSize);
if (self.isArgumentsRetained) {
[self _retainPointer:argumentLocation encode:type key:@(idx)];
}
memcpy(arg, argumentLocation, argSize);
}

#pragma mark - Private Helper

- (BOOL)_retainPointer:(void **)pointer encode:(const char *)encode key:(NSNumber *)key
{
void *p = *pointer;
if (p == NULL) {
if (!p) {
return NO;
}
if (encode[0] == '@') {
Expand All @@ -413,7 +423,7 @@ - (BOOL)_retainPointer:(void **)pointer encode:(const char *)encode key:(NSNumbe
char *arg = p;
NSMutableData *data = [NSMutableData dataWithLength:sizeof(char) * strlen(arg)];
self.retainMap[key] = data;
char *str = [data mutableBytes];
char *str = data.mutableBytes;
strcpy(str, arg);
*pointer = str;
return YES;
Expand Down Expand Up @@ -585,7 +595,7 @@ - (void *)_allocate:(size_t)howmuch
{
NSMutableData *data = [NSMutableData dataWithLength:howmuch];
[self.allocations addObject:data];
return [data mutableBytes];
return data.mutableBytes;
}

- (ffi_type *)_ffiTypeForStructEncode:(const char *)str
Expand Down
Loading

0 comments on commit 8af5b26

Please sign in to comment.