/* PFMERGE dest src1 src2 src3 ... srcN => OK */ voidpfmergeCommand(client *c){ uint8_t max[HLL_REGISTERS]; structhllhdr *hdr; int j; int use_dense = 0; /* Use dense representation as target? */
/* Compute an HLL with M[i] = MAX(M[i]_j). * We store the maximum into the max array of registers. We'll write * it to the target variable later. */ memset(max,0,sizeof(max)); for (j = 1; j < c->argc; j++) { ... /* Merge with this HLL with our 'max' HLL by setting max[i] * to MAX(max[i],hll[i]). */ if (hllMerge(max,o) == C_ERR) { // hllMerge [1] stack oob write ... } }
/* Convert the destination object to dense representation if at least * one of the inputs was dense. */ if (use_dense && hllSparseToDense(o) == C_ERR) { // hllSparseToDense [2] heap oob write ... }
/* If the representation is already the right one return ASAP. */ hdr = (struct hllhdr*) sparse; if (hdr->encoding == HLL_DENSE) return C_OK;
/* Create a string of the right size filled with zero bytes. * Note that the cached cardinality is set to 0 as a side effect * that is exactly the cardinality of an empty HLL. */ dense = sdsnewlen(NULL,HLL_DENSE_SIZE); hdr = (struct hllhdr*) dense; *hdr = *oldhdr; /* This will copy the magic and cached cardinality. */ hdr->encoding = HLL_DENSE;
/* Now read the sparse representation and set non-zero registers * accordingly. */ p += HLL_HDR_SIZE; while(p < end) { if (HLL_SPARSE_IS_ZERO(p)) { runlen = HLL_SPARSE_ZERO_LEN(p); idx += runlen; p++; } elseif (HLL_SPARSE_IS_XZERO(p)) { runlen = HLL_SPARSE_XZERO_LEN(p); idx += runlen; p += 2; } else { runlen = HLL_SPARSE_VAL_LEN(p); regval = HLL_SPARSE_VAL_VALUE(p); if ((runlen + idx) > HLL_REGISTERS) break; /* Overflow. */ while(runlen--) { HLL_DENSE_SET_REGISTER(hdr->registers,idx,regval); idx++; } p++; } }
/* If the sparse representation was valid, we expect to find idx * set to HLL_REGISTERS. */ if (idx != HLL_REGISTERS) { sdsfree(dense); return C_ERR; }
/* Free the old representation and set the new one. */ sdsfree(o->ptr); o->ptr = dense; return C_OK; }
while 循环之前是对 HLL 数据的的部分 header 解析,之后是一个转换过程。 HLL 数据是一种 SDS [2]字符串的表示。 我们可以用 set 命令来伪造一个 HLL 数据。
// 1. HLL 总体结构 structhllhdr { char magic[4]; /* "HYLL" */ uint8_t encoding; /* HLL_DENSE or HLL_SPARSE. */ uint8_t notused[3]; /* Reserved for future use, must be zero. */ uint8_t card[8]; /* Cached cardinality, little endian. */ uint8_t registers[]; /* Data bytes. */ };
#define HLL_P 14 /* The greater is P, the smaller the error. */ #define HLL_REGISTERS (1<<HLL_P) /* With P=14, 16384 registers. */ #define HLL_DENSE_SIZE (HLL_HDR_SIZE+((HLL_REGISTERS*HLL_BITS+7)/8))