Index: src/libs/zbxmemory/memalloc.c
===================================================================
--- src/libs/zbxmemory/memalloc.c	(revision 43311)
+++ src/libs/zbxmemory/memalloc.c	(working copy)
@@ -34,7 +34,7 @@
  *                                                                            *
  *                                                                            *
  *                    +-------- size of + --------------+                     *
- *                    |       (8 bytes) |               |                     *
+ *                    |       (4 bytes) |               |                     *
  *                    |                 v               |                     *
  *                    |                                 |                     *
  *                    |    +- allocatable memory --+    |                     *
@@ -44,7 +44,7 @@
  *                |--------|----------------...----|--------|                 *
  *                                                                            *
  *                ^        ^                       ^        ^                 *
- *            8-aligned    |                       |    8-aligned             *
+ *            4-aligned    |                       |    4-aligned             *
  *                                                                            *
  *                     8-aligned               8-aligned                      *
  *                                                                            *
@@ -98,11 +98,11 @@
 static void	*ALIGN8(void *ptr);
 static void	*ALIGNPTR(void *ptr);
 
-static zbx_uint64_t	mem_proper_alloc_size(zbx_uint64_t size);
-static int	mem_bucket_by_size(zbx_uint64_t size);
+static uint32_t	mem_proper_alloc_size(uint32_t size);
+static int	mem_bucket_by_size(uint32_t size);
 
-static void	mem_set_chunk_size(void *chunk, zbx_uint64_t size);
-static void	mem_set_used_chunk_size(void *chunk, zbx_uint64_t size);
+static void	mem_set_chunk_size(void *chunk, uint32_t size);
+static void	mem_set_used_chunk_size(void *chunk, uint32_t size);
 
 static void	*mem_get_prev_chunk(void *chunk);
 static void	mem_set_prev_chunk(void *chunk, void *prev);
@@ -114,19 +114,20 @@
 static void	mem_link_chunk(zbx_mem_info_t *info, void *chunk);
 static void	mem_unlink_chunk(zbx_mem_info_t *info, void *chunk);
 
-static void	*__mem_malloc(zbx_mem_info_t *info, zbx_uint64_t size);
-static void	*__mem_realloc(zbx_mem_info_t *info, void *old, zbx_uint64_t size);
+static void	*__mem_malloc(zbx_mem_info_t *info, uint32_t size);
+static void	*__mem_realloc(zbx_mem_info_t *info, void *old, uint32_t size);
 static void	__mem_free(zbx_mem_info_t *info, void *ptr);
 
-#define MEM_SIZE_FIELD		sizeof(zbx_uint64_t)
+#define MEM_SIZE_FIELD		sizeof(uint32_t)
 
-#define MEM_FLG_USED		((__UINT64_C(1))<<63)
+#define MEM_FLG_USED		(((uint32_t)1)<<31)
 
-#define FREE_CHUNK(ptr)		(((*(zbx_uint64_t *)(ptr)) & MEM_FLG_USED) == 0)
-#define CHUNK_SIZE(ptr)		((*(zbx_uint64_t *)(ptr)) & ~MEM_FLG_USED)
+#define FREE_CHUNK(ptr)		(((*(uint32_t *)(ptr)) & MEM_FLG_USED) == 0)
+#define CHUNK_SIZE(ptr)		((*(uint32_t *)(ptr)) & ~MEM_FLG_USED)
 
-#define MEM_MIN_SIZE		__UINT64_C(128)
-#define MEM_MAX_SIZE		__UINT64_C(0x1000000000)	/* 64 GB */
+#define MEM_MIN_SIZE		128
+#define MEM_MAX_SIZE		0x7fffffff                 /* maximal size of single allocation - just below 2 GB */
+#define MEM_MAX_SIZE_TOTAL	__UINT64_C(0x1000000000)   /* maximal size of total available memory - 64 GB */
 
 #define MEM_MIN_ALLOC	24	/* should be a multiple of 8 and at least (2 * ZBX_PTR_SIZE) */
 
@@ -155,7 +156,7 @@
 	assert(0);
 }
 
-static zbx_uint64_t	mem_proper_alloc_size(zbx_uint64_t size)
+static uint32_t	mem_proper_alloc_size(uint32_t size)
 {
 	if (size >= MEM_MIN_ALLOC)
 		return size + ((8 - (size & 7)) & 7);	/* allocate in multiples of 8... */
@@ -163,7 +164,7 @@
 		return MEM_MIN_ALLOC;			/* ...and at least MEM_MIN_ALLOC */
 }
 
-static int	mem_bucket_by_size(zbx_uint64_t size)
+static int	mem_bucket_by_size(uint32_t size)
 {
 	if (size < MEM_MIN_BUCKET_SIZE)
 		return 0;
@@ -172,16 +173,16 @@
 	return MEM_BUCKET_COUNT - 1;
 }
 
-static void	mem_set_chunk_size(void *chunk, zbx_uint64_t size)
+static void	mem_set_chunk_size(void *chunk, uint32_t size)
 {
-	*(zbx_uint64_t *)chunk = size;
-	*(zbx_uint64_t *)((char *)chunk + MEM_SIZE_FIELD + size) = size;
+	*(uint32_t *)chunk = size;
+	*(uint32_t *)((char *)chunk + MEM_SIZE_FIELD + size) = size;
 }
 
-static void	mem_set_used_chunk_size(void *chunk, zbx_uint64_t size)
+static void	mem_set_used_chunk_size(void *chunk, uint32_t size)
 {
-	*(zbx_uint64_t *)chunk = MEM_FLG_USED | size;
-	*(zbx_uint64_t *)((char *)chunk + MEM_SIZE_FIELD + size) = MEM_FLG_USED | size;
+	*(uint32_t *)chunk = MEM_FLG_USED | size;
+	*(uint32_t *)((char *)chunk + MEM_SIZE_FIELD + size) = MEM_FLG_USED | size;
 }
 
 static void	*mem_get_prev_chunk(void *chunk)
@@ -250,11 +251,11 @@
 
 /* private memory functions */
 
-static void	*__mem_malloc(zbx_mem_info_t *info, zbx_uint64_t size)
+static void	*__mem_malloc(zbx_mem_info_t *info, uint32_t size)
 {
 	int		index;
 	void		*chunk;
-	zbx_uint64_t	chunk_size;
+	uint32_t	chunk_size;
 
 	size = mem_proper_alloc_size(size);
 
@@ -272,7 +273,7 @@
 		/* otherwise, find a chunk big enough according to first-fit strategy */
 
 		int		counter = 0;
-		zbx_uint64_t	skip_min = __UINT64_C(0xffffffffffffffff), skip_max = __UINT64_C(0);
+		uint32_t	skip_min = 0xffffffff, skip_max = 0;
 
 		while (NULL != chunk && CHUNK_SIZE(chunk) < size)
 		{
@@ -333,10 +334,10 @@
 	return chunk;
 }
 
-static void	*__mem_realloc(zbx_mem_info_t *info, void *old, zbx_uint64_t size)
+static void	*__mem_realloc(zbx_mem_info_t *info, void *old, uint32_t size)
 {
 	void		*chunk, *new_chunk, *next_chunk;
-	zbx_uint64_t	chunk_size, new_chunk_size;
+	uint32_t	chunk_size, new_chunk_size;
 	int		next_free;
 
 	size = mem_proper_alloc_size(size);
@@ -477,7 +478,7 @@
 {
 	void		*chunk;
 	void		*prev_chunk, *next_chunk;
-	zbx_uint64_t	chunk_size;
+	uint32_t	chunk_size;
 	int		prev_free, next_free;
 
 	chunk = (void *)((char *)ptr - MEM_SIZE_FIELD);
@@ -489,17 +490,18 @@
 	/* see if we can merge with previous and next chunks */
 
 	next_chunk = (void *)((char *)chunk + MEM_SIZE_FIELD + chunk_size + MEM_SIZE_FIELD);
+	prev_chunk = (char *)chunk - MEM_SIZE_FIELD - CHUNK_SIZE((char *)chunk - MEM_SIZE_FIELD) -
+			MEM_SIZE_FIELD;
+
 
 	prev_free = (info->lo_bound < chunk && FREE_CHUNK((char *)chunk - MEM_SIZE_FIELD));
 	next_free = (next_chunk < info->hi_bound && FREE_CHUNK(next_chunk));
 
-	if (prev_free && next_free)
+	if (prev_free && next_free && MEM_MAX_SIZE < chunk_size + 4 * MEM_SIZE_FIELD +
+			CHUNK_SIZE(prev_chunk) + CHUNK_SIZE(next_chunk))
 	{
 		info->free_size += 4 * MEM_SIZE_FIELD;
 
-		prev_chunk = (char *)chunk - MEM_SIZE_FIELD - CHUNK_SIZE((char *)chunk - MEM_SIZE_FIELD) -
-				MEM_SIZE_FIELD;
-
 		chunk_size += 4 * MEM_SIZE_FIELD + CHUNK_SIZE(prev_chunk) + CHUNK_SIZE(next_chunk);
 
 		mem_unlink_chunk(info, prev_chunk);
@@ -509,13 +511,10 @@
 		mem_set_chunk_size(chunk, chunk_size);
 		mem_link_chunk(info, chunk);
 	}
-	else if (prev_free)
+	else if (prev_free && MEM_MAX_SIZE < chunk_size + 2 * MEM_SIZE_FIELD + CHUNK_SIZE(prev_chunk))
 	{
 		info->free_size += 2 * MEM_SIZE_FIELD;
 
-		prev_chunk = (void *)((char *)chunk - MEM_SIZE_FIELD - CHUNK_SIZE((char *)chunk - MEM_SIZE_FIELD) -
-				MEM_SIZE_FIELD);
-
 		chunk_size += 2 * MEM_SIZE_FIELD + CHUNK_SIZE(prev_chunk);
 
 		mem_unlink_chunk(info, prev_chunk);
@@ -524,7 +523,7 @@
 		mem_set_chunk_size(chunk, chunk_size);
 		mem_link_chunk(info, chunk);
 	}
-	else if (next_free)
+	else if (next_free && MEM_MAX_SIZE < chunk_size + 2 * MEM_SIZE_FIELD + CHUNK_SIZE(next_chunk))
 	{
 		info->free_size += 2 * MEM_SIZE_FIELD;
 
@@ -542,6 +541,39 @@
 	}
 }
 
+static void	zbx_mem_reset(zbx_mem_info_t *info)
+{
+	zbx_uint64_t	size;
+	void		*chunk;
+	int		chunk_size;
+
+	memset(info->buckets, 0, MEM_BUCKET_COUNT * ZBX_PTR_SIZE);
+
+	info->total_size = (zbx_uint64_t)((char *)(info->hi_bound) - (char *)(info->lo_bound));
+	info->total_size -= 2 * MEM_SIZE_FIELD;
+
+	info->used_size = 0;
+	info->free_size = 0;
+
+	size = info->total_size;
+	chunk = info->lo_bound;
+
+	while (MEM_MIN_ALLOC + 2 * MEM_SIZE_FIELD < size)
+	{
+		chunk_size = MEM_MAX_SIZE < size ? MEM_MAX_SIZE : size - MEM_MIN_ALLOC + 2;
+
+		mem_set_chunk_size(chunk, chunk_size);
+		mem_link_chunk(info, chunk);
+
+		info->free_size += chunk_size;
+
+		chunk = (char *)chunk + chunk_size + 2 * MEM_SIZE_FIELD;
+		size -= chunk_size + 2 * MEM_SIZE_FIELD;
+	}
+
+	info->total_size -= size;
+}
+
 /* public memory interface */
 
 void	zbx_mem_create(zbx_mem_info_t **info, key_t shm_key, int lock_name, zbx_uint64_t size,
@@ -549,7 +581,7 @@
 {
 	const char	*__function_name = "zbx_mem_create";
 
-	int		shm_id, index;
+	int		shm_id;
 	void		*base;
 
 	descr = ZBX_NULL2STR(descr);
@@ -567,10 +599,10 @@
 		exit(FAIL);
 	}
 
-	if (!(MEM_MIN_SIZE <= size && size <= MEM_MAX_SIZE))
+	if (!(MEM_MIN_SIZE <= size && size <= MEM_MAX_SIZE_TOTAL))
 	{
-		zabbix_log(LOG_LEVEL_CRIT, "requested size " ZBX_FS_SIZE_T " not within bounds [" ZBX_FS_UI64
-				" <= size <= " ZBX_FS_UI64 "]", (zbx_fs_size_t)size, MEM_MIN_SIZE, MEM_MAX_SIZE);
+		zabbix_log(LOG_LEVEL_CRIT, "requested size " ZBX_FS_SIZE_T " not within bounds [%d <= size <= "
+				ZBX_FS_UI64 "]", (zbx_fs_size_t)size, MEM_MIN_SIZE, MEM_MAX_SIZE_TOTAL);
 		exit(FAIL);
 	}
 
@@ -596,7 +628,6 @@
 	base = (void *)(*info + 1);
 
 	(*info)->buckets = ALIGNPTR(base);
-	memset((*info)->buckets, 0, MEM_BUCKET_COUNT * ZBX_PTR_SIZE);
 	size -= (char *)((*info)->buckets + MEM_BUCKET_COUNT) - (char *)base;
 	base = (void *)((*info)->buckets + MEM_BUCKET_COUNT);
 
@@ -628,20 +659,16 @@
 		(*info)->use_lock = 0;
 
 	/* prepare shared memory for further allocation by creating one big chunk */
-	(*info)->lo_bound = ALIGN8(base);
-	(*info)->hi_bound = ALIGN8((char *)base + size - 8);
+	(*info)->lo_bound = (char*)ALIGN8(base) - MEM_SIZE_FIELD;
+	if ((*info)->lo_bound < base)
+		(*info)->lo_bound = (char*)(*info)->lo_bound + 8;
 
-	(*info)->total_size = (zbx_uint64_t)((char *)((*info)->hi_bound) - (char *)((*info)->lo_bound) -
-			2 * MEM_SIZE_FIELD);
+	(*info)->hi_bound = ALIGN8((char *)base + size - 8);
+	if ((char*)(*info)->hi_bound + MEM_SIZE_FIELD > (char*)base + size)
+		(*info)->hi_bound = (char *)(*info)->hi_bound - 8;
 
-	index = mem_bucket_by_size((*info)->total_size);
-	(*info)->buckets[index] = (*info)->lo_bound;
-	mem_set_chunk_size((*info)->buckets[index], (*info)->total_size);
-	mem_set_prev_chunk((*info)->buckets[index], NULL);
-	mem_set_next_chunk((*info)->buckets[index], NULL);
 
-	(*info)->used_size = 0;
-	(*info)->free_size = (*info)->total_size;
+	zbx_mem_reset(*info);
 
 	zabbix_log(LOG_LEVEL_DEBUG, "valid user addresses: [%p, %p] total size: " ZBX_FS_SIZE_T,
 			(char *)(*info)->lo_bound + MEM_SIZE_FIELD,
@@ -769,20 +796,11 @@
 {
 	const char	*__function_name = "zbx_mem_clear";
 
-	int		index;
-
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
 
 	LOCK_INFO;
 
-	memset(info->buckets, 0, MEM_BUCKET_COUNT * ZBX_PTR_SIZE);
-	index = mem_bucket_by_size(info->total_size);
-	info->buckets[index] = info->lo_bound;
-	mem_set_chunk_size(info->buckets[index], info->total_size);
-	mem_set_prev_chunk(info->buckets[index], NULL);
-	mem_set_next_chunk(info->buckets[index], NULL);
-	info->used_size = 0;
-	info->free_size = info->total_size;
+	zbx_mem_reset(info);
 
 	UNLOCK_INFO;
 
@@ -825,7 +843,7 @@
 	zabbix_log(LOG_LEVEL_DEBUG, "min chunk size: %10u bytes", min_size);
 	zabbix_log(LOG_LEVEL_DEBUG, "max chunk size: %10u bytes", max_size);
 
-	total = (info->total_size - info->used_size - info->free_size) / (2 * MEM_SIZE_FIELD) + 1;
+	total = (info->total_size - info->used_size - info->free_size) / (2 * MEM_SIZE_FIELD);
 	zabbix_log(LOG_LEVEL_DEBUG, "memory of total size %u bytes fragmented into %d chunks", info->total_size, total);
 	zabbix_log(LOG_LEVEL_DEBUG, "of those, %10u bytes are in %8d free chunks", info->free_size, total_free);
 	zabbix_log(LOG_LEVEL_DEBUG, "of those, %10u bytes are in %8d used chunks", info->used_size, total - total_free);
