profile
viewpoint
Konstantin Käfer kkaefer @mapbox Berlin, Germany https://kkaefer.com

audreyt/node-webworker-threads 2176

Lightweight Web Worker API implementation with native threads

developmentseed/bones 488

A client/server web application framework built on Express and Backbone

kkaefer/DEPRECATED-node-zlib 47

DEPRECATED – Simple, synchronous deflate/inflate for node.js buffers

developmentseed/gdal2mb 39

a version of gdal2tiles with MapBox support

kkaefer/chrono.js 26

Format dates in JavaScript

developmentseed/backbone-dirty 10

Use node-dirty for Model persistence with backbone.js

kkaefer/backbone-redis-es 7

Experimental Storage of Backbone Models/Collections in Redis. NOTE: Abandoned course project. Do not use in production.

kkaefer/browsemytweets 3

Browse My Tweets

kkaefer/Atrium 2

Drupal based Intranet

kkaefer/expresso 2

TDD framework for node -- high speed parallel testing!

IssuesEvent

fork kkaefer/node-pty

Fork pseudoterminals in Node.JS

fork in a month

PullRequestReviewEvent

Pull request review commentmapbox/mapbox-base

[weak] Introduce WeakPtrFactory::invalidateWeakPtrs()

 class WeakPtrSharedData {     WeakPtrSharedData() = default;      void sharedLock() {-        assert(valid());-        sharedLocks_++;+        std::size_t noLocks = sharedLocks_;+        std::size_t incremented;+        do {+            if (noLocks == kInvalidValue) return;+            incremented = noLocks + 1;+            // `compare_exchange_weak()` is invoked in a cycle to handle the case,+            // if another thread has just modified `sharedLocks_` (so that it is not+            // equal to `noLocks` any more). We early return, if `sharedLocks_` became+            // equal to `kInvalidValue`.+        } while (!sharedLocks_.compare_exchange_weak(noLocks, incremented));     }      void sharedUnlock() {-        assert(valid());-        assert(sharedLocks_ > 0u);-        sharedLocks_--;+        std::size_t noLocks = sharedLocks_;+        std::size_t decremented;+        do {+            if (noLocks == kInvalidValue) return;+            decremented = noLocks - 1;

(I realize that if used correctly, this situation will not occur, since a precondition of this function is that sharedLocks_ is > 0)

pozdnyakov

comment created time in 2 months

Pull request review commentmapbox/mapbox-base

[weak] Introduce WeakPtrFactory::invalidateWeakPtrs()

 class WeakPtrSharedData {     WeakPtrSharedData() = default;      void sharedLock() {-        assert(valid());-        sharedLocks_++;+        std::size_t noLocks = sharedLocks_;+        std::size_t incremented;+        do {+            if (noLocks == kInvalidValue) return;+            incremented = noLocks + 1;+            // `compare_exchange_weak()` is invoked in a cycle to handle the case,+            // if another thread has just modified `sharedLocks_` (so that it is not+            // equal to `noLocks` any more). We early return, if `sharedLocks_` became+            // equal to `kInvalidValue`.+        } while (!sharedLocks_.compare_exchange_weak(noLocks, incremented));     }      void sharedUnlock() {-        assert(valid());-        assert(sharedLocks_ > 0u);-        sharedLocks_--;+        std::size_t noLocks = sharedLocks_;+        std::size_t decremented;+        do {+            if (noLocks == kInvalidValue) return;+            decremented = noLocks - 1;+            assert(decremented >= 0u);

This is always true, since size_t is unsigned.

pozdnyakov

comment created time in 2 months

Pull request review commentmapbox/mapbox-base

[weak] Introduce WeakPtrFactory::invalidateWeakPtrs()

 class WeakPtrSharedData {     WeakPtrSharedData() = default;      void sharedLock() {-        assert(valid());-        sharedLocks_++;+        std::size_t noLocks = sharedLocks_;+        std::size_t incremented;+        do {+            if (noLocks == kInvalidValue) return;+            incremented = noLocks + 1;+            // `compare_exchange_weak()` is invoked in a cycle to handle the case,+            // if another thread has just modified `sharedLocks_` (so that it is not+            // equal to `noLocks` any more). We early return, if `sharedLocks_` became+            // equal to `kInvalidValue`.+        } while (!sharedLocks_.compare_exchange_weak(noLocks, incremented));     }      void sharedUnlock() {-        assert(valid());-        assert(sharedLocks_ > 0u);-        sharedLocks_--;+        std::size_t noLocks = sharedLocks_;+        std::size_t decremented;+        do {+            if (noLocks == kInvalidValue) return;+            decremented = noLocks - 1;

This will overflow if noLocks == 0.

pozdnyakov

comment created time in 2 months

Pull request review commentmapbox/mapbox-base

[weak] Introduce WeakPtrFactory::invalidateWeakPtrs()

 class WeakPtrFactory final {         };     } +    /**+     * @brief Invalidates all existing weak pointers.+     *+     * This method is particularly useful, when \c T  class has a user-defined destructor,+     * that makes the wrapped instance invalid even before entering the \c WeakPtrFactory+     * destructor.+     * In this case, clients *MUST* explicitly call \c invalidateWeakPtrs() before freeing any resources.+     *+     * Note: After \c invalidateWeakPtrs() is called, \c makeWeakPtr() returns empty weak pointers.+     */+    void invalidateWeakPtrs() {+        if (strong_) strong_->invalidate();+        strong_.reset();

This could still fail:

Thread A calls invalidateWeakPtr in WeakPtrFactory's destructor. It proceeds until after the strong_->invalidate(), but before the strong_.reset() call, and gets preempted. At this point, sharedLocks_ is set to kInvalidValue aka numeric_limits<std::size_t>::max.

Thread B has a WeakPtr. It gets scheduled to run, and calls .lock(), which acquires a std::shared_ptr of WeakPtrSharedData. This is still possible, since the object is still strongly held by the WeakPtrFactory. lock() then proceeds to call strong->sharedLock(). While there's an assert in that function that will terminate the program in debug builds, sharedLock will happily increment the sharedLocks_ atomic (which will now be 0 since it overflowed, and unsigned integer overflow is not UB). That means strong->valid() will also return true, and we'll return a valid WeakPtrGuard handle. 💥

pozdnyakov

comment created time in 2 months

starteddebauchee/barrier

started time in 3 months

more