talloc & threads in rlm_eap

Arran Cudbard-Bell a.cudbardb at freeradius.org
Fri Jun 20 12:17:12 CEST 2014


On 20 Jun 2014, at 10:56, Phil Mayers <p.mayers at imperial.ac.uk> wrote:

> Hmm assuming nothing else is talloc'ed off the parent of handler that is, or freeing handler itself is racey...

That's now fixed too. I think. The memory associated with the handler is now freed within the destructor for the handler, which synchronises the frees using the same mutex. Hopefully that's OK.

https://github.com/FreeRADIUS/freeradius-server/commit/f74b0fe85f171faf5c1445240d23a28eb73f20c1

If it explodes I guess we'll need to figure out another solution.

> I'm assuming talloc lets you alloc and free below a context in one thread whilst alloc and freeing off a sibling, ancestor or descendant context in another?

Looks like that's safe. There's nothing that modifies anything above the context of the chunk.


/*
   Allocate a bit of memory as a child of an existing pointer
*/
static inline void *__talloc_with_prefix(const void *context, size_t size,
					size_t prefix_len)
{
	struct talloc_chunk *tc = NULL;
	struct talloc_memlimit *limit = NULL;
	size_t total_len = TC_HDR_SIZE + size + prefix_len;

	if (unlikely(context == NULL)) {
		context = null_context;
	}

	if (unlikely(size >= MAX_TALLOC_SIZE)) {
		return NULL;
	}

	if (unlikely(total_len < TC_HDR_SIZE)) {
		return NULL;
	}

	if (context != NULL) {
		struct talloc_chunk *ptc = talloc_chunk_from_ptr(context);

		if (ptc->limit != NULL) {
			limit = ptc->limit;
		}

		tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size, prefix_len);
	}

	if (tc == NULL) {
		char *ptr;

		/*
		 * Only do the memlimit check/update on actual allocation.
		 */
		if (!talloc_memlimit_check(limit, total_len)) {
			errno = ENOMEM;
			return NULL;
		}

		ptr = malloc(total_len);
		if (unlikely(ptr == NULL)) {
			return NULL;
		}
		tc = (struct talloc_chunk *)(ptr + prefix_len);
		tc->flags = TALLOC_MAGIC;
		tc->pool  = NULL;

		talloc_memlimit_grow(limit, total_len);
	}

	tc->limit = limit;
	tc->size = size;
	tc->destructor = NULL;
	tc->child = NULL;
	tc->name = NULL;
	tc->refs = NULL;

	if (likely(context)) {
		struct talloc_chunk *parent = talloc_chunk_from_ptr(context);

		if (parent->child) {
			parent->child->parent = NULL;
			tc->next = parent->child;
			tc->next->prev = tc;
		} else {
			tc->next = NULL;
		}
		tc->parent = parent;
		tc->prev = NULL;
		parent->child = tc;
	} else {
		tc->next = tc->prev = tc->parent = NULL;
	}

	return TC_PTR_FROM_CHUNK(tc);
}

static inline void *__talloc(const void *context, size_t size)
{
	return __talloc_with_prefix(context, size, 0);
}

Arran Cudbard-Bell <a.cudbardb at freeradius.org>
FreeRADIUS Development Team

FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 881 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://lists.freeradius.org/pipermail/freeradius-devel/attachments/20140620/8e9f502f/attachment.pgp>


More information about the Freeradius-Devel mailing list