{"push_id":1961032853,"size":1,"distinct_size":1,"ref":"refs/heads/feature/fix-set-value-crash","head":"f9b42b504908f47b443db9c74d30f0a070ced710","before":"7d0be2f668c0196dc01e02bf56b0b9e6fdae9e73","commits":[{"sha":"f9b42b504908f47b443db9c74d30f0a070ced710","author":{"name":"Neria Saada","email":"27cdbfb3c8921f816352b0cd3e41b4566c3615d1@lightricks.com"},"message":"AFURLRequestSerialization: Dispatch the right serializer queue on copy.\n\n## Summary\n\nSuggested fix for a crash that occurs when copying an\n`AFHTTPRequestSerializer`. The crash is caused by dispatching a block\nthat modifies the request headers dictionary of the **new** serializer\ninstance on the wrong queue - the queue of the serializer being copied\ninstead of the queue of the new serializer. Due to this error it happens\nthat this block may replace the request headers dictionary (i.e. assign\na brand new dictionary and release the existing one) while\nsimultaneously another block, dispatched by the initializer of the new\nserializer on the correct queue, adds a new header field to the existing\ndictionary.\n\nTypically the stack trace looks like this:\nCrashed: requestHeaderModificationQueue\nException: message sent to deallocated instance <address>\n```\n0  libobjc.A.dylib   0x18ceb01a0 objc_retain + 16\n1  AFNetworking      0x1019d3fa0 __55-[AFHTTPRequestSerializer\n                         setValue:forHTTPHeaderField:]_block_invoke + 40\n2  libdispatch.dylib 0x18d2ea9e0 _dispatch_call_block_and_release + 24\n```\n\nThe crash occurs with a chance of about `1/10000` and it can be\nreproduced by running `[serializer copy]` in a simple `for` loop with\nmore than `10000` iterations.\n\n## Details\n\nAn `AFHTTPRequestSerializer` instance provides an interface for getting\nand setting the HTTP headers for all requests serialized by that\ninstance. The headers are saved in a mutable dictionary. Every access to\nthat mutable dictionary is done via `requestHeaderModificationQueue`,\nwhich is a concurrent queue, while mutations are performed with a\nbarrier. This way the queue acts as a Single-Writer-Multiple-Reader lock\nthat also promises that writes will execute alone and that any\nreads/writes that were queued after a certain write will only start\nexecuting after that write completes and get the updated data.\n\nThe scenario that leads to the crash:\n- `serializerA` is allocated and initialized. A new mutable headers\ndictionary and designated queue are created for it - `headersA` and\n`queueA`.\n- `[serializerA copy]` is invoked which in turn invokes `copyWithZone:`.\n- Inside `copyWithZone:` a new serializer is created and initialized -\n`serializerB`.\n- Within the initializer of `serializerB` a new headers dictionary is\nallocated along with a designated queue - `headersB` and `queueB`.\n- Also within the initializer `setValue:forHTTPHeaderField:` is called\nwhich queues a block to run  asynchronously on `queueB`.\n- After initializing `serializerB` the `copyWithZone:` method continues\nto copy `headersA` and overwrite `headersB` with that copy.\n*Before the fix* this copying and overwriting is done by dispatching a\nblock on `queueA` (and not `queueB`).\n- Since the header-setting block was queued on `queueB` and the copy\nblock was queued on `queueA` it is possible that they will will be\nscheduled to run simultaneously. If this happens the copy block will\ncause the existing headers dictionary to be released while the\nheader-setting block is still using that dictionary causing the block\nto crash.","distinct":true,"url":"https://api.github.com/repos/Ner1Co/AFNetworking/commits/f9b42b504908f47b443db9c74d30f0a070ced710"}]}
{"actor":{"display_login":"Ner1Co"}}