~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/object_pool.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * config_pool.c :  pool of configuration objects
 
3
 *
 
4
 * ====================================================================
 
5
 *    Licensed to the Apache Software Foundation (ASF) under one
 
6
 *    or more contributor license agreements.  See the NOTICE file
 
7
 *    distributed with this work for additional information
 
8
 *    regarding copyright ownership.  The ASF licenses this file
 
9
 *    to you under the Apache License, Version 2.0 (the
 
10
 *    "License"); you may not use this file except in compliance
 
11
 *    with the License.  You may obtain a copy of the License at
 
12
 *
 
13
 *      http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 *    Unless required by applicable law or agreed to in writing,
 
16
 *    software distributed under the License is distributed on an
 
17
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
18
 *    KIND, either express or implied.  See the License for the
 
19
 *    specific language governing permissions and limitations
 
20
 *    under the License.
 
21
 * ====================================================================
 
22
 */
 
23
 
 
24
 
 
25
 
 
26
 
 
27
#include <assert.h>
 
28
 
 
29
#include "svn_error.h"
 
30
#include "svn_hash.h"
 
31
#include "svn_pools.h"
 
32
 
 
33
#include "private/svn_atomic.h"
 
34
#include "private/svn_object_pool.h"
 
35
#include "private/svn_subr_private.h"
 
36
#include "private/svn_dep_compat.h"
 
37
 
 
38
 
 
39
 
 
40
/* A reference counting wrapper around the user-provided object.
 
41
 */
 
42
typedef struct object_ref_t
 
43
{
 
44
  /* reference to the parent container */
 
45
  svn_object_pool__t *object_pool;
 
46
 
 
47
  /* identifies the bucket in OBJECT_POOL->OBJECTS in which this entry
 
48
   * belongs. */
 
49
  svn_membuf_t key;
 
50
 
 
51
  /* User provided object. Usually a wrapper. */
 
52
  void *wrapper;
 
53
 
 
54
  /* private pool. This instance and its other members got allocated in it.
 
55
   * Will be destroyed when this instance is cleaned up. */
 
56
  apr_pool_t *pool;
 
57
 
 
58
  /* Number of references to this data struct */
 
59
  volatile svn_atomic_t ref_count;
 
60
} object_ref_t;
 
61
 
 
62
 
 
63
/* Core data structure.  All access to it must be serialized using MUTEX.
 
64
 */
 
65
struct svn_object_pool__t
 
66
{
 
67
  /* serialization object for all non-atomic data in this struct */
 
68
  svn_mutex__t *mutex;
 
69
 
 
70
  /* object_ref_t.KEY -> object_ref_t* mapping.
 
71
   *
 
72
   * In shared object mode, there is at most one such entry per key and it
 
73
   * may or may not be in use.  In exclusive mode, only unused references
 
74
   * will be put here and they form chains if there are multiple unused
 
75
   * instances for the key. */
 
76
  apr_hash_t *objects;
 
77
 
 
78
  /* same as objects->count but allows for non-sync'ed access */
 
79
  volatile svn_atomic_t object_count;
 
80
 
 
81
  /* Number of entries in OBJECTS with a reference count 0.
 
82
     Due to races, this may be *temporarily* off by one or more.
 
83
     Hence we must not strictly depend on it. */
 
84
  volatile svn_atomic_t unused_count;
 
85
 
 
86
  /* the root pool owning this structure */
 
87
  apr_pool_t *pool;
 
88
 
 
89
  /* extractor and updater for the user object wrappers */
 
90
  svn_object_pool__getter_t getter;
 
91
  svn_object_pool__setter_t setter;
 
92
};
 
93
 
 
94
 
 
95
/* Pool cleanup function for the whole object pool.
 
96
 */
 
97
static apr_status_t
 
98
object_pool_cleanup(void *baton)
 
99
{
 
100
  svn_object_pool__t *object_pool = baton;
 
101
 
 
102
  /* all entries must have been released up by now */
 
103
  SVN_ERR_ASSERT_NO_RETURN(   object_pool->object_count
 
104
                           == object_pool->unused_count);
 
105
 
 
106
  return APR_SUCCESS;
 
107
}
 
108
 
 
109
/* Remove entries from OBJECTS in OBJECT_POOL that have a ref-count of 0.
 
110
 *
 
111
 * Requires external serialization on OBJECT_POOL.
 
112
 */
 
113
static void
 
114
remove_unused_objects(svn_object_pool__t *object_pool)
 
115
{
 
116
  apr_pool_t *subpool = svn_pool_create(object_pool->pool);
 
117
 
 
118
  /* process all hash buckets */
 
119
  apr_hash_index_t *hi;
 
120
  for (hi = apr_hash_first(subpool, object_pool->objects);
 
121
       hi != NULL;
 
122
       hi = apr_hash_next(hi))
 
123
    {
 
124
      object_ref_t *object_ref = apr_hash_this_val(hi);
 
125
 
 
126
      /* note that we won't hand out new references while access
 
127
         to the hash is serialized */
 
128
      if (svn_atomic_read(&object_ref->ref_count) == 0)
 
129
        {
 
130
          apr_hash_set(object_pool->objects, object_ref->key.data,
 
131
                       object_ref->key.size, NULL);
 
132
          svn_atomic_dec(&object_pool->object_count);
 
133
          svn_atomic_dec(&object_pool->unused_count);
 
134
 
 
135
          svn_pool_destroy(object_ref->pool);
 
136
        }
 
137
    }
 
138
 
 
139
  svn_pool_destroy(subpool);
 
140
}
 
141
 
 
142
/* Cleanup function called when an object_ref_t gets released.
 
143
 */
 
144
static apr_status_t
 
145
object_ref_cleanup(void *baton)
 
146
{
 
147
  object_ref_t *object = baton;
 
148
  svn_object_pool__t *object_pool = object->object_pool;
 
149
 
 
150
  /* If we released the last reference to object, there is one more
 
151
     unused entry.
 
152
 
 
153
     Note that unused_count does not need to be always exact but only
 
154
     needs to become exact *eventually* (we use it to check whether we
 
155
     should remove unused objects every now and then).  I.e. it must
 
156
     never drift off / get stuck but always reflect the true value once
 
157
     all threads left the racy sections.
 
158
   */
 
159
  if (svn_atomic_dec(&object->ref_count) == 0)
 
160
    svn_atomic_inc(&object_pool->unused_count);
 
161
 
 
162
  return APR_SUCCESS;
 
163
}
 
164
 
 
165
/* Handle reference counting for the OBJECT_REF that the caller is about
 
166
 * to return.  The reference will be released when POOL gets cleaned up.
 
167
 *
 
168
 * Requires external serialization on OBJECT_REF->OBJECT_POOL.
 
169
 */
 
170
static void
 
171
add_object_ref(object_ref_t *object_ref,
 
172
              apr_pool_t *pool)
 
173
{
 
174
  /* Update ref counter.
 
175
     Note that this is racy with object_ref_cleanup; see comment there. */
 
176
  if (svn_atomic_inc(&object_ref->ref_count) == 0)
 
177
    svn_atomic_dec(&object_ref->object_pool->unused_count);
 
178
 
 
179
  /* make sure the reference gets released automatically */
 
180
  apr_pool_cleanup_register(pool, object_ref, object_ref_cleanup,
 
181
                            apr_pool_cleanup_null);
 
182
}
 
183
 
 
184
/* Actual implementation of svn_object_pool__lookup.
 
185
 *
 
186
 * Requires external serialization on OBJECT_POOL.
 
187
 */
 
188
static svn_error_t *
 
189
lookup(void **object,
 
190
       svn_object_pool__t *object_pool,
 
191
       svn_membuf_t *key,
 
192
       void *baton,
 
193
       apr_pool_t *result_pool)
 
194
{
 
195
  object_ref_t *object_ref
 
196
    = apr_hash_get(object_pool->objects, key->data, key->size);
 
197
 
 
198
  if (object_ref)
 
199
    {
 
200
      *object = object_pool->getter(object_ref->wrapper, baton, result_pool);
 
201
      add_object_ref(object_ref, result_pool);
 
202
    }
 
203
  else
 
204
    {
 
205
      *object = NULL;
 
206
    }
 
207
 
 
208
  return SVN_NO_ERROR;
 
209
}
 
210
 
 
211
/* Actual implementation of svn_object_pool__insert.
 
212
 *
 
213
 * Requires external serialization on OBJECT_POOL.
 
214
 */
 
215
static svn_error_t *
 
216
insert(void **object,
 
217
       svn_object_pool__t *object_pool,
 
218
       const svn_membuf_t *key,
 
219
       void *wrapper,
 
220
       void *baton,
 
221
       apr_pool_t *wrapper_pool,
 
222
       apr_pool_t *result_pool)
 
223
{
 
224
  object_ref_t *object_ref
 
225
    = apr_hash_get(object_pool->objects, key->data, key->size);
 
226
  if (object_ref)
 
227
    {
 
228
      /* entry already exists (e.g. race condition) */
 
229
      svn_error_t *err = object_pool->setter(&object_ref->wrapper,
 
230
                                             wrapper, baton,
 
231
                                             object_ref->pool);
 
232
      if (err)
 
233
        {
 
234
          /* if we had an issue in the setter, then OBJECT_REF is in an
 
235
           * unknown state now.  Keep it around for the current users
 
236
           * (i.e. don't clean the pool) but remove it from the list of
 
237
           * available ones.
 
238
           */
 
239
          apr_hash_set(object_pool->objects, key->data, key->size, NULL);
 
240
          svn_atomic_dec(&object_pool->object_count);
 
241
 
 
242
          /* for the unlikely case that the object got created _and_
 
243
           * already released since we last checked: */
 
244
          if (svn_atomic_read(&object_ref->ref_count) == 0)
 
245
            svn_atomic_dec(&object_pool->unused_count);
 
246
 
 
247
          /* cleanup the new data as well because it's not safe to use
 
248
           * either.
 
249
           */
 
250
          svn_pool_destroy(wrapper_pool);
 
251
 
 
252
          /* propagate error */
 
253
          return svn_error_trace(err);
 
254
        }
 
255
 
 
256
      /* Destroy the new one and return a reference to the existing one
 
257
       * because the existing one may already have references on it.
 
258
       */
 
259
      svn_pool_destroy(wrapper_pool);
 
260
    }
 
261
  else
 
262
    {
 
263
      /* add new index entry */
 
264
      object_ref = apr_pcalloc(wrapper_pool, sizeof(*object_ref));
 
265
      object_ref->object_pool = object_pool;
 
266
      object_ref->wrapper = wrapper;
 
267
      object_ref->pool = wrapper_pool;
 
268
 
 
269
      svn_membuf__create(&object_ref->key, key->size, wrapper_pool);
 
270
      object_ref->key.size = key->size;
 
271
      memcpy(object_ref->key.data, key->data, key->size);
 
272
 
 
273
      apr_hash_set(object_pool->objects, object_ref->key.data,
 
274
                   object_ref->key.size, object_ref);
 
275
      svn_atomic_inc(&object_pool->object_count);
 
276
 
 
277
      /* the new entry is *not* in use yet.
 
278
       * add_object_ref will update counters again.
 
279
       */
 
280
      svn_atomic_inc(&object_ref->object_pool->unused_count);
 
281
    }
 
282
 
 
283
  /* return a reference to the object we just added */
 
284
  *object = object_pool->getter(object_ref->wrapper, baton, result_pool);
 
285
  add_object_ref(object_ref, result_pool);
 
286
 
 
287
  /* limit memory usage */
 
288
  if (svn_atomic_read(&object_pool->unused_count) * 2
 
289
      > apr_hash_count(object_pool->objects) + 2)
 
290
    remove_unused_objects(object_pool);
 
291
 
 
292
  return SVN_NO_ERROR;
 
293
}
 
294
 
 
295
/* Implement svn_object_pool__getter_t as no-op.
 
296
 */
 
297
static void *
 
298
default_getter(void *object,
 
299
               void *baton,
 
300
               apr_pool_t *pool)
 
301
{
 
302
  return object;
 
303
}
 
304
 
 
305
/* Implement svn_object_pool__setter_t as no-op.
 
306
 */
 
307
static svn_error_t *
 
308
default_setter(void **target,
 
309
               void *source,
 
310
               void *baton,
 
311
               apr_pool_t *pool)
 
312
{
 
313
  return SVN_NO_ERROR;
 
314
}
 
315
 
 
316
 
 
317
/* API implementation */
 
318
 
 
319
svn_error_t *
 
320
svn_object_pool__create(svn_object_pool__t **object_pool,
 
321
                        svn_object_pool__getter_t getter,
 
322
                        svn_object_pool__setter_t setter,
 
323
                        svn_boolean_t thread_safe,
 
324
                        apr_pool_t *pool)
 
325
{
 
326
  svn_object_pool__t *result;
 
327
 
 
328
  /* construct the object pool in our private ROOT_POOL to survive POOL
 
329
   * cleanup and to prevent threading issues with the allocator
 
330
   */
 
331
  result = apr_pcalloc(pool, sizeof(*result));
 
332
  SVN_ERR(svn_mutex__init(&result->mutex, thread_safe, pool));
 
333
 
 
334
  result->pool = pool;
 
335
  result->objects = svn_hash__make(result->pool);
 
336
  result->getter = getter ? getter : default_getter;
 
337
  result->setter = setter ? setter : default_setter;
 
338
 
 
339
  /* make sure we clean up nicely.
 
340
   * We need two cleanup functions of which exactly one will be run
 
341
   * (disabling the respective other as the first step).  If the owning
 
342
   * pool does not cleaned up / destroyed explicitly, it may live longer
 
343
   * than our allocator.  So, we need do act upon cleanup requests from
 
344
   * either side - owning_pool and root_pool.
 
345
   */
 
346
  apr_pool_cleanup_register(pool, result, object_pool_cleanup,
 
347
                            apr_pool_cleanup_null);
 
348
 
 
349
  *object_pool = result;
 
350
  return SVN_NO_ERROR;
 
351
}
 
352
 
 
353
apr_pool_t *
 
354
svn_object_pool__new_wrapper_pool(svn_object_pool__t *object_pool)
 
355
{
 
356
  return svn_pool_create(object_pool->pool);
 
357
}
 
358
 
 
359
svn_mutex__t *
 
360
svn_object_pool__mutex(svn_object_pool__t *object_pool)
 
361
{
 
362
  return object_pool->mutex;
 
363
}
 
364
 
 
365
unsigned
 
366
svn_object_pool__count(svn_object_pool__t *object_pool)
 
367
{
 
368
  return svn_atomic_read(&object_pool->object_count);
 
369
}
 
370
 
 
371
svn_error_t *
 
372
svn_object_pool__lookup(void **object,
 
373
                        svn_object_pool__t *object_pool,
 
374
                        svn_membuf_t *key,
 
375
                        void *baton,
 
376
                        apr_pool_t *result_pool)
 
377
{
 
378
  *object = NULL;
 
379
  SVN_MUTEX__WITH_LOCK(object_pool->mutex,
 
380
                       lookup(object, object_pool, key, baton, result_pool));
 
381
  return SVN_NO_ERROR;
 
382
}
 
383
 
 
384
svn_error_t *
 
385
svn_object_pool__insert(void **object,
 
386
                        svn_object_pool__t *object_pool,
 
387
                        const svn_membuf_t *key,
 
388
                        void *wrapper,
 
389
                        void *baton,
 
390
                        apr_pool_t *wrapper_pool,
 
391
                        apr_pool_t *result_pool)
 
392
{
 
393
  *object = NULL;
 
394
  SVN_MUTEX__WITH_LOCK(object_pool->mutex,
 
395
                       insert(object, object_pool, key, wrapper, baton,
 
396
                              wrapper_pool, result_pool));
 
397
  return SVN_NO_ERROR;
 
398
}