/** * Create a memory pool. * @param size Size of each memory block. Use default value if 0. * @return A pointer to created pool, NULL on error. */ pool_t *pool_create(size_t size) { if (!_max_pool_alloc) _max_pool_alloc = sysconf(_SC_PAGESIZE); if (!size) size = _max_pool_alloc * 2; if (size <= sizeof(pool_block_t)) return NULL; pool_block_t *b = malloc(size); if (!b) return NULL; b->last = _align_ptr((uchar_t *)b + sizeof(*b)); b->end = (uchar_t *)b + size; b->next = NULL; pool_t *p = (pool_t *) b->last; b->last = (uchar_t *)p + sizeof(*p); p->head = b; p->large = NULL; return p; }
/** * Clear memory pool. * Large memories are freed. Blocks are cleared. * @param p The memory pool. */ void pool_clear(pool_t *p) { for (pool_large_t *l = p->large; l; l = l->next) { if (l->ptr) free(l->ptr); } p->large = NULL; for (pool_block_t *b = p->head->next; b; b = b->next) { b->last = (uchar_t *)b + sizeof(*b); } p->head->last = _align_ptr((uchar_t *)(p->head) + sizeof(pool_block_t)); p->head->last += sizeof(*p); }
/** * Allocate memory from pool by creating a new block. * @param p The pool to allocate from. * @param size Required memory size. * @return On success, a pointer to allocated space, NULL otherwise. */ static void *_pool_alloc_block(pool_t *p, size_t size) { size_t bsize = p->head->end - (uchar_t *)(p->head); pool_block_t *b = malloc(bsize); if (!b) return NULL; b->last = (uchar_t *)b + sizeof(*b); b->end = (uchar_t *)b + bsize; b->next = p->head->next; p->head->next = b; uchar_t *ret = _align_ptr(b->last); b->last = ret + size; return ret; }
/** * Allocate memory from pool. * @param p The pool to allocate from. * @param size Required memory size. * @return On success, a pointer to allocated space, NULL otherwise. */ void *pool_alloc(pool_t *p, size_t size) { uchar_t *ret; pool_block_t *b; if (size < _max_pool_alloc) { b = p->head; do { ret = _align_ptr(b->last); if (b->end - ret >= size) { b->last = (uchar_t *)ret + size; return ret; } b = b->next; } while (b); return _pool_alloc_block(p, size); } return _pool_alloc_large(p, size); }
/** * Parses an SPF macro string. * * Note that we cannot write data_avail bytes from data, since we * might be called with a modified data pointer. We MUST compare * data_used with data_avail. * * @param spf_server The SPF server on whose behalf the record is being compiled. * @param spf_response The SPF response in which to store errors. * @param data Output buffer pointer. * @param data_used Output parameter for amount of data written to output buffer. * @param data_avail Input parameter for size of output buffer. * @param src Input buffer pointer. * @param src_len Input buffer length. * @param big_err The error code to return on an over-length condition. * @param is_mod True if this is a modifier. */ static SPF_errcode_t SPF_c_parse_macro(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_data_t *data, size_t *data_used, size_t data_avail, const char *src, size_t src_len, SPF_errcode_t big_err, int is_mod) { SPF_errcode_t err; /* Generic parsing iterators and boundaries */ size_t idx; size_t len; /* For parsing strings. */ char *dst; size_t ds_avail; size_t ds_len; if (spf_server->debug) SPF_debugf("Parsing macro starting at %s", src); #if 0 if ((void *)data != _align_ptr((void *)data)) SPF_errorf("Data pointer %p is not aligned: Cannot compile.", data); #endif /* * Create the data blocks */ idx = 0; /* Initialise the block as a string. If ds_len == 0 later, we * will just clobber it. */ SPF_INIT_STRING_LITERAL(data_avail - *data_used); // while ( p != end ) { while (idx < src_len) { if (spf_server->debug > 3) SPF_debugf("Current data is at %p", data); /* Either the unit is terminated by a space, or we hit a %. * We should only hit a space if we run past src_len. */ len = strcspn(&src[idx], " %"); // XXX Also tab? if (len > 0) { /* An optimisation */ /* Don't over-run into the CIDR. */ if (idx + len > src_len) len = src_len - idx; if (spf_server->debug > 3) SPF_debugf("Adding string literal (%lu): '%*.*s'", (unsigned long)len, (int)len, (int)len, &src[idx]); /* XXX Bounds-check here. */ SPF_ENSURE_STRING_AVAIL(len); memcpy(dst, &src[idx], len); ds_len += len; dst += len; idx += len; /* If len == 0 then we never entered the while(). Thus * if idx == src_len, then len != 0 and we reach this test. */ } /* However, this logic is overcomplex and I am a simpleton, * so I have moved it out of the condition above. */ if (idx == src_len) break; /* Now, we must have a %-escape code, since if we hit a * space, then we are at the end. * Incrementing idx consumes the % we hit first, and then * we switch on the following character, which also * increments idx. */ idx++; switch (src[idx]) { case '%': if (spf_server->debug > 3) SPF_debugf("Adding literal %%"); SPF_ENSURE_STRING_AVAIL(1); *dst++ = '%'; ds_len++; idx++; break; case '_': if (spf_server->debug > 3) SPF_debugf("Adding literal space"); SPF_ENSURE_STRING_AVAIL(1); *dst++ = ' '; ds_len++; idx++; break; case '-': if (spf_server->debug > 3) SPF_debugf("Adding escaped space"); SPF_ENSURE_STRING_AVAIL(3); *dst++ = '%'; *dst++ = '2'; *dst++ = '0'; ds_len += 3; idx++; break; default: if (spf_server->debug > 3) SPF_debugf("Adding illegal %%-follower '%c' at %d", src[idx], idx); /* SPF spec says to treat it as a literal, not * SPF_E_INVALID_ESC */ /* FIXME issue a warning? */ SPF_ENSURE_STRING_AVAIL(1); *dst++ = '%'; ds_len++; break; case '{': /*vi:}*/ SPF_FINI_STRING_LITERAL(); if (spf_server->debug > 3) SPF_debugf("Adding macro, data is at %p", data); /* this must be a variable */ idx++; err = SPF_c_parse_var(spf_response, &data->dv, &src[idx], is_mod); if (err != SPF_E_SUCCESS) return err; idx += strcspn(&src[idx], "} "); if (src[idx] == '}') idx++; else if (src[idx] == ' ') return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_VAR, src, &src[idx], "Unterminated variable?"); len = SPF_data_len(data); SPF_ADD_LEN_TO(*data_used, len, data_avail); data = SPF_data_next( data ); if (spf_server->debug > 3) SPF_debugf("Next data is at %p", data); SPF_INIT_STRING_LITERAL(data_avail - *data_used); break; } } SPF_FINI_STRING_LITERAL(); return SPF_E_SUCCESS; }