Permalink
Browse files

@synchronized statement added to fix multi-threading crashes

  • Loading branch information...
1 parent 85cb34e commit f54830fe2d6a5c1ca7c7c2604ad4d94eb2278e9b @Romes-- Romes-- committed Jul 12, 2014
@@ -31,39 +31,44 @@ - (id)initWithAttrTypes:(HTMLPurifier_AttrTypes*)attr_types modules:(NSArray*)mo
{
//TO DO: fix this - there really shouldn't be a string at this stage. ever.
if([module isKindOfClass:[HTMLPurifier_HTMLModule class]])
- for(NSString* coll_i in module.attr_collections)
- {
- NSDictionary* coll = module.attr_collections[coll_i];
-
- if(!self.info[coll_i])
- self.info[coll_i] = [NSMutableDictionary new];
-
- for(id<NSCopying> attr_i in coll)
- {
- NSObject* attr = coll[attr_i];
-
-
- if([(NSObject*)attr_i isEqual:@0] && self.info[coll_i][attr_i])
+ for(NSString* coll_i in module.attr_collections)
{
- NSMutableArray* array1 = [self.info[coll_i][attr_i] mutableCopy];
- if(!array1)
- array1 = [@[] mutableCopy];
- if(![array1 isKindOfClass:[NSArray class]])
- array1 = [@[array1] mutableCopy];
- NSArray* array2 = (NSArray*)attr;
- if(!attr)
- array2 = @[];
- if(![array2 isKindOfClass:[NSArray class]])
- array2 = @[array2];
- self.info[coll_i][attr_i] = [array1 arrayByAddingObjectsFromArray:array2];
- continue;
+ NSDictionary* coll = module.attr_collections[coll_i];
+
+ if(!self.info[coll_i])
+ self.info[coll_i] = [NSMutableDictionary new];
+
+ if(![coll isKindOfClass:[NSDictionary class]])
+ {
+ NSLog(@"HTMLPurifier: coll is not an NSDictionary on HTMLPurifier_AttrCollections initWithAttrTypes! %@", coll);
+ continue;
+ }
+
+ for(id<NSCopying> attr_i in coll)
+ {
+ NSObject* attr = coll[attr_i];
+
+ if([(NSObject*)attr_i isEqual:@0] && self.info[coll_i][attr_i])
+ {
+ NSMutableArray* array1 = [self.info[coll_i][attr_i] mutableCopy];
+ if(!array1)
+ array1 = [@[] mutableCopy];
+ if(![array1 isKindOfClass:[NSArray class]])
+ array1 = [@[array1] mutableCopy];
+ NSArray* array2 = (NSArray*)attr;
+ if(!attr)
+ array2 = @[];
+ if(![array2 isKindOfClass:[NSArray class]])
+ array2 = @[array2];
+ self.info[coll_i][attr_i] = [array1 arrayByAddingObjectsFromArray:array2];
+ continue;
+ }
+ //if([attr isKindOfClass:[NSArray class]])
+ self.info[coll_i][attr_i] = attr;
+ //else
+ // self.info[coll_i][attr_i] = @[attr];
+ }
}
- //if([attr isKindOfClass:[NSArray class]])
- self.info[coll_i][attr_i] = attr;
- //else
- // self.info[coll_i][attr_i] = @[attr];
- }
- }
}
// perform internal expansions and inclusions
@@ -86,76 +91,76 @@ - (id)init
return [self initWithAttrTypes:nil modules:nil];
}
- /**
- * Takes a reference to an attribute associative array and performs
- * all inclusions specified by the zero index.
- * @param array &$attr Reference to attribute array
- */
+/**
+ * Takes a reference to an attribute associative array and performs
+ * all inclusions specified by the zero index.
+ * @param array &$attr Reference to attribute array
+ */
- (void)performInclusions:(NSMutableDictionary*)attr
+{
+ if (!attr[@0]) {
+ return;
+ }
+ NSMutableArray* merge = nil;
+ if([attr[@0] isKindOfClass:[NSArray class]])
+ merge = [attr[@0] mutableCopy];
+ else
+ merge = [@[attr[@0]] mutableCopy];
+ NSMutableSet* seen = [NSMutableSet new]; // recursion guard
+ // loop through all the inclusions
+ for (NSInteger i = 0; i<merge.count; i++)
{
- if (!attr[@0]) {
- return;
+ if ([seen containsObject:merge[i]])
+ {
+ continue;
}
- NSMutableArray* merge = nil;
- if([attr[@0] isKindOfClass:[NSArray class]])
- merge = [attr[@0] mutableCopy];
- else
- merge = [@[attr[@0]] mutableCopy];
- NSMutableSet* seen = [NSMutableSet new]; // recursion guard
- // loop through all the inclusions
- for (NSInteger i = 0; i<merge.count; i++)
+ [seen addObject:merge[i]];
+ // foreach attribute of the inclusion, copy it over
+ if (!self.info[merge[i]])
{
- if ([seen containsObject:merge[i]])
- {
- continue;
- }
- [seen addObject:merge[i]];
- // foreach attribute of the inclusion, copy it over
- if (!self.info[merge[i]])
+ continue;
+ }
+ for(NSString* key in self.info[merge[i]])
+ {
+ NSObject* value = self.info[merge[i]][key];
+ if (attr[key])
{
continue;
- }
- for(NSString* key in self.info[merge[i]])
- {
- NSObject* value = self.info[merge[i]][key];
- if (attr[key])
- {
- continue;
- } // also catches more inclusions
- attr[key] = value;
- }
+ } // also catches more inclusions
+ attr[key] = value;
+ }
- if ([self.info[merge[i]] isKindOfClass:[NSDictionary class]] && self.info[merge[i]][@0])
- {
- // recursion
- NSArray* array2 = (NSArray*)self.info[merge[i]][@0];
- if(!attr)
- array2 = @[];
- if(![array2 isKindOfClass:[NSArray class]])
- array2 = @[array2];
- [merge addObjectsFromArray:array2];
- attr[@0] = merge;
- }
+ if ([self.info[merge[i]] isKindOfClass:[NSDictionary class]] && self.info[merge[i]][@0])
+ {
+ // recursion
+ NSArray* array2 = (NSArray*)self.info[merge[i]][@0];
+ if(!attr)
+ array2 = @[];
+ if(![array2 isKindOfClass:[NSArray class]])
+ array2 = @[array2];
+ [merge addObjectsFromArray:array2];
+ attr[@0] = merge;
}
- [attr removeObjectForKey:@0];
}
+ [attr removeObjectForKey:@0];
+}
- /**
- * Expands all string identifiers in an attribute array by replacing
- * them with the appropriate values inside HTMLPurifier_AttrTypes
- * @param array &$attr Reference to attribute array
- * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
- */
+/**
+ * Expands all string identifiers in an attribute array by replacing
+ * them with the appropriate values inside HTMLPurifier_AttrTypes
+ * @param array &$attr Reference to attribute array
+ * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
+ */
- (void)expandIdentifiers:(NSMutableDictionary*)attr attrTypes:(HTMLPurifier_AttrTypes*)attr_types
- {
- // because foreach will process new elements we add, make sure we
- // skip duplicates
- NSMutableSet* processed = [NSMutableSet new];
+{
+ // because foreach will process new elements we add, make sure we
+ // skip duplicates
+ NSMutableSet* processed = [NSMutableSet new];
- //while there are unprocessed objects in attr
+ //while there are unprocessed objects in attr
- while(![[NSSet setWithArray:attr.allKeys] isSubsetOfSet:processed])
- {
+ while(![[NSSet setWithArray:attr.allKeys] isSubsetOfSet:processed])
+ {
NSArray* allKeys = attr.allKeys;
for(NSString* def_i in allKeys)
{
@@ -209,8 +214,8 @@ - (void)expandIdentifiers:(NSMutableDictionary*)attr attrTypes:(HTMLPurifier_Att
[attr removeObjectForKey:new_def_i];
}
}
- }
}
+}
@@ -374,6 +374,44 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type
return [self getDefinition:type raw:NO optimized:NO];
}
+
+- (HTMLPurifier_Definition*)findDefinitionForType:(NSString*)type
+{
+ if(!type)
+ {
+ NSLog(@"HTMLPurifier: Trying to find definition for nil type!!");
+ return nil;
+ }
+
+ @synchronized(@"DEFINITION_LOCK")
+ {
+ return [definitions objectForKey:type];
+ }
+}
+
+- (void)addDefinition:(HTMLPurifier_Definition*)newDefinition forType:(NSString*)type
+{
+ if(!type)
+ {
+ NSLog(@"HTMLPurifier: Trying to add definition for nil type!!");
+ return;
+ }
+
+ if(!newDefinition)
+ {
+ NSLog(@"HTMLPurifier: Trying to add nil definition!!");
+ return;
+ }
+
+ @synchronized(@"DEFINITION_LOCK")
+ {
+ if(!definitions)
+ definitions = [NSMutableDictionary new];
+
+ [definitions setObject:newDefinition forKey:type];
+ }
+}
+
/**
* Retrieves a definition
*
@@ -416,9 +454,9 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type raw:(BOOL)raw optimize
// full definition
// ---------------
// check if definition is in memory
- if (definitions[type])
+ HTMLPurifier_Definition* def = [self findDefinitionForType:type];
+ if (def)
{
- HTMLPurifier_Definition* def = definitions[type];
// check if the definition is setup
if ([def setup]) {
return def;
@@ -431,7 +469,7 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type raw:(BOOL)raw optimize
}
}
// check if definition is in cache
- HTMLPurifier_Definition* def = [cache get:self];
+ def = [cache get:self];
if (def) {
// definition in cache, save to memory and return it
[definitions setObject:def forKey:type];
@@ -453,7 +491,12 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type raw:(BOOL)raw optimize
// set it up
lock = type;
- [def setup:self];
+
+ @synchronized(type)
+ {
+ [def setup:self];
+ }
+
lock = nil;
@@ -467,7 +510,6 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type raw:(BOOL)raw optimize
// raw definition
// --------------
// check preconditions
- HTMLPurifier_Definition* def = nil;
if (optimized)
{
if (![self get:[NSString stringWithFormat:@"%@.DefinitionID", type ]])
@@ -476,9 +518,9 @@ - (HTMLPurifier_Definition*)getDefinition:(NSString*)type raw:(BOOL)raw optimize
@throw [NSException exceptionWithName:@"Config" reason:@"Cannot retrieve raw version without specifying $type.DefinitionID" userInfo:nil];
}
}
- if ([definitions[type] count]!=0)
+ HTMLPurifier_Definition* def = [self findDefinitionForType:type];
+ if (def)
{
- def = definitions[type];
if ([def setup] && !optimized)
{
NSString* extra = self.chatty ?
View
@@ -366,6 +366,12 @@ + (NSString*)cleanHTML:(NSString*)htmlString
+ (void)cleanHTML:(NSString*)htmlString withCallBack:(void(^)(NSString* cleanedHTML, NSError* error))callBack
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+
+ //Some parts of HTMLPurifier are not currently thread-safe
+ //remove this lock to allow concurrent purification at the expense of occasional crashes
+ @synchronized(@"HTMLPurifier_LOCK")
+ {
+
NSString* purifiedBody = nil;
@autoreleasepool
@@ -391,6 +397,7 @@ + (void)cleanHTML:(NSString*)htmlString withCallBack:(void(^)(NSString* cleanedH
callBack(purifiedBody, nil);
}
});
+ }
});
}
@@ -710,8 +710,6 @@
1EEE87B0188EC7B800BDA422 /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = "<group>"; };
1EEEC28E18ED769B008F1E67 /* libHTMLPurifieriOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHTMLPurifieriOS.a; sourceTree = BUILT_PRODUCTS_DIR; };
1EEEC29218ED769B008F1E67 /* HTMLPurifieriOS-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HTMLPurifieriOS-Prefix.pch"; sourceTree = "<group>"; };
- 1EEEC29318ED769B008F1E67 /* HTMLPurifieriOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLPurifieriOS.h; sourceTree = "<group>"; };
- 1EEEC29518ED769B008F1E67 /* HTMLPurifieriOS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HTMLPurifieriOS.m; sourceTree = "<group>"; };
1EEEC29B18ED769B008F1E67 /* HTMLPurifieriOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HTMLPurifieriOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
1EEEC2A418ED769B008F1E67 /* HTMLPurifieriOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HTMLPurifieriOSTests-Info.plist"; sourceTree = "<group>"; };
1EEEC2A618ED769B008F1E67 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -1193,8 +1191,6 @@
1EEEC29018ED769B008F1E67 /* HTMLPurifieriOS */ = {
isa = PBXGroup;
children = (
- 1EEEC29318ED769B008F1E67 /* HTMLPurifieriOS.h */,
- 1EEEC29518ED769B008F1E67 /* HTMLPurifieriOS.m */,
1EEEC29118ED769B008F1E67 /* Supporting Files */,
);
path = HTMLPurifieriOS;
@@ -3037,6 +3033,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DYLIB_COMPATIBILITY_VERSION = 1.01;
DYLIB_CURRENT_VERSION = 1.01;
@@ -3069,6 +3066,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DYLIB_COMPATIBILITY_VERSION = 1.01;
DYLIB_CURRENT_VERSION = 1.01;
@@ -1,13 +0,0 @@
-//
-// HTMLPurifieriOS.h
-// HTMLPurifieriOS
-//
-// Created by Roman Priebe on 03.04.14.
-// Copyright (c) 2014 Mynigma. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-
-@interface HTMLPurifieriOS : NSObject
-
-@end
Oops, something went wrong.

0 comments on commit f54830f

Please sign in to comment.