Skip to content

Commit f114195

Browse files
committed
FT-300 Fix an issue where `free' calls on blocks created during
create_from_blockpairs would crash the replay. Also fix parsing bugs.
1 parent 4a152ec commit f114195

File tree

1 file changed

+46
-13
lines changed

1 file changed

+46
-13
lines changed

tools/ba_replay.cc

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,11 @@ static char *trim_whitespace(char *line) {
130130

131131
static int64_t parse_number(char **ptr, int line_num, int base) {
132132
*ptr = trim_whitespace(*ptr);
133+
char *line = *ptr;
133134

134135
char *new_ptr;
135-
int64_t n = strtoll(*ptr, &new_ptr, base);
136-
ba_replay_assert(n >= 0, "malformed trace", *ptr, line_num);
136+
int64_t n = strtoll(line, &new_ptr, base);
137+
ba_replay_assert(n >= 0, "malformed trace", line, line_num);
137138
*ptr = new_ptr;
138139
return n;
139140
}
@@ -147,30 +148,35 @@ static uint64_t parse_uint64(char **ptr, int line_num) {
147148
}
148149

149150
static string parse_token(char **ptr, int line_num) {
150-
char *line = trim_whitespace(*ptr);
151+
*ptr = trim_whitespace(*ptr);
152+
char *line = *ptr;
151153

152154
// parse the first token, which represents the traced function
153155
char token[64];
154-
int r = sscanf(line, "%64s", token);
156+
int r = sscanf(*ptr, "%64s", token);
155157
ba_replay_assert(r == 1, "malformed trace", line, line_num);
156158
*ptr += strlen(token);
157159
return string(token);
158160
}
159161

160162
static block_allocator::blockpair parse_blockpair(char **ptr, int line_num) {
161-
char *line = trim_whitespace(*ptr);
163+
*ptr = trim_whitespace(*ptr);
164+
char *line = *ptr;
165+
162166
uint64_t offset, size;
163167
int bytes_read;
164168
int r = sscanf(line, "[%" PRIu64 " %" PRIu64 "]%n", &offset, &size, &bytes_read);
165-
ba_replay_assert(r == 3, "malformed trace", line, line_num);
169+
ba_replay_assert(r == 2, "malformed trace", line, line_num);
166170
*ptr += bytes_read;
167171
return block_allocator::blockpair(offset, size);
168172
}
169173

170174
static char *strip_newline(char *line, bool *found) {
171175
char *ptr = strchr(line, '\n');
172176
if (ptr != nullptr) {
173-
*found = true;
177+
if (found != nullptr) {
178+
*found = true;
179+
}
174180
*ptr = '\0';
175181
}
176182
return line;
@@ -192,7 +198,7 @@ static char *read_trace_line(FILE *file) {
192198
}
193199
}
194200
std::string s = ss.str();
195-
return toku_strdup(s.c_str());
201+
return s.size() ? toku_strdup(s.c_str()) : nullptr;
196202
}
197203

198204
static vector<string> canonicalize_trace_from(FILE *file) {
@@ -209,6 +215,7 @@ static vector<string> canonicalize_trace_from(FILE *file) {
209215
// allocated offset -> allocation seq num
210216
//
211217
uint64_t allocation_seq_num = 0;
218+
static const uint64_t ASN_NONE = (uint64_t) -1;
212219
typedef map<uint64_t, uint64_t> offset_seq_map;
213220

214221
// raw allocator id -> offset_seq_map that tracks its allocations
@@ -232,6 +239,19 @@ static vector<string> canonicalize_trace_from(FILE *file) {
232239
allocator_ids[allocator_id] = allocator_id_seq_num;
233240
ss << fn << ' ' << allocator_id_seq_num << ' ' << trim_whitespace(ptr) << std::endl;
234241
allocator_id_seq_num++;
242+
243+
// For each blockpair created by this traceline, add its offset to the offset seq map
244+
// with asn ASN_NONE so that later canonicalizations of `free' know whether to write
245+
// down the asn or the raw offset.
246+
//
247+
// First, read passed the reserve / alignment values.
248+
(void) parse_uint64(&ptr, line_num);
249+
(void) parse_uint64(&ptr, line_num);
250+
offset_seq_map *map = &offset_to_seq_num_maps[allocator_id];
251+
while (*trim_whitespace(ptr) != '\0') {
252+
const block_allocator::blockpair bp = parse_blockpair(&ptr, line_num);
253+
(*map)[bp.offset] = ASN_NONE;
254+
}
235255
} else if (allocator_ids.count(allocator_id) > 0) {
236256
// this allocator is part of the canonical trace
237257
uint64_t canonical_allocator_id = allocator_ids[allocator_id];
@@ -259,8 +279,14 @@ static vector<string> canonicalize_trace_from(FILE *file) {
259279
const uint64_t asn = (*map)[offset];
260280
map->erase(offset);
261281

262-
// translate `free(offset)' to `free(asn)'
263-
ss << fn << ' ' << canonical_allocator_id << ' ' << asn << std::endl;
282+
// if there's an asn, then a corresponding ba_trace_alloc occurred and we should
283+
// write `free(asn)'. otherwise, the blockpair was initialized from create_from_blockpairs
284+
// and we write the original offset.
285+
if (asn != ASN_NONE) {
286+
ss << "ba_trace_free_asn" << ' ' << canonical_allocator_id << ' ' << asn << std::endl;
287+
} else {
288+
ss << "ba_trace_free_offset" << ' ' << canonical_allocator_id << ' ' << offset << std::endl;
289+
}
264290
} else if (fn == "ba_trace_destroy") {
265291
// Remove this allocator from both maps
266292
allocator_ids.erase(allocator_id);
@@ -293,6 +319,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
293319
line_num++;
294320

295321
char *line = toku_strdup(it->c_str());
322+
line = strip_newline(line, nullptr);
296323

297324
if (verbose) {
298325
printf("playing canonical trace line #%d: %s", line_num, line);
@@ -318,7 +345,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
318345
"corrupted canonical trace: bad create fn", line, line_num);
319346
vector<block_allocator::blockpair> pairs;
320347
while (*trim_whitespace(ptr) != '\0') {
321-
block_allocator::blockpair bp = parse_blockpair(&ptr, line_num);
348+
const block_allocator::blockpair bp = parse_blockpair(&ptr, line_num);
322349
pairs.push_back(bp);
323350
}
324351
ba->create_from_blockpairs(reserve_at_beginning, alignment, &pairs[0], pairs.size());
@@ -333,6 +360,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
333360

334361
block_allocator *ba = (*allocator_map)[allocator_id];
335362
if (fn == "ba_trace_alloc") {
363+
// replay an `alloc' whose result will be associated with a certain asn
336364
const uint64_t size = parse_uint64(&ptr, line_num);
337365
const uint64_t heat = parse_uint64(&ptr, line_num);
338366
const uint64_t asn = parse_uint64(&ptr, line_num);
@@ -342,14 +370,19 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
342370
uint64_t offset;
343371
ba->alloc_block(size, heat, &offset);
344372
seq_num_to_offset[asn] = offset;
345-
} else if (fn == "ba_trace_free") {
373+
} else if (fn == "ba_trace_free_asn") {
374+
// replay a `free' on a block whose offset is the result of an alloc with an asn
346375
const uint64_t asn = parse_uint64(&ptr, line_num);
347376
ba_replay_assert(seq_num_to_offset.count(asn) == 1,
348377
"corrupted canonical trace: double free (asn unused)", line, line_num);
349378

350-
uint64_t offset = seq_num_to_offset[asn];
379+
const uint64_t offset = seq_num_to_offset[asn];
351380
ba->free_block(offset);
352381
seq_num_to_offset.erase(asn);
382+
} else if (fn == "ba_trace_free_offset") {
383+
// replay a `free' on a block whose offset was explicitly set during a create_from_blockpairs
384+
const uint64_t offset = parse_uint64(&ptr, line_num);
385+
ba->free_block(offset);
353386
} else if (fn == "ba_trace_destroy") {
354387
// TODO: Clean this up - we won't be able to catch no such allocator errors
355388
// if we don't actually not the destroy. We only do it here so that the caller

0 commit comments

Comments
 (0)