| ... | @@ -413,8 +413,7 @@ const Msf = struct { | ... | @@ -413,8 +413,7 @@ const Msf = struct { |
| 413 | return error.InvalidDebugInfo; | 413 | return error.InvalidDebugInfo; |
| 414 | if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2) | 414 | if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2) |
| 415 | return error.InvalidDebugInfo; | 415 | return error.InvalidDebugInfo; |
| 416 | const file_len = try file_reader.getSize(); | 416 | if (superblock.num_blocks * superblock.block_size != try file_reader.getSize()) |
| 417 | if (superblock.num_blocks * superblock.block_size != file_len) | | |
| 418 | return error.InvalidDebugInfo; | 417 | return error.InvalidDebugInfo; |
| 419 | switch (superblock.block_size) { | 418 | switch (superblock.block_size) { |
| 420 | // llvm only supports 4096 but we can handle any of these values | 419 | // llvm only supports 4096 but we can handle any of these values |
| ... | @@ -428,6 +427,7 @@ const Msf = struct { | ... | @@ -428,6 +427,7 @@ const Msf = struct { |
| 428 | | 427 | |
| 429 | try file_reader.seekTo(superblock.block_size * superblock.block_map_addr); | 428 | try file_reader.seekTo(superblock.block_size * superblock.block_map_addr); |
| 430 | const dir_blocks = try gpa.alloc(u32, dir_block_count); | 429 | const dir_blocks = try gpa.alloc(u32, dir_block_count); |
| | 430 | errdefer gpa.free(dir_blocks); |
| 431 | for (dir_blocks) |*b| { | 431 | for (dir_blocks) |*b| { |
| 432 | b.* = try file_reader.interface.takeInt(u32, .little); | 432 | b.* = try file_reader.interface.takeInt(u32, .little); |
| 433 | } | 433 | } |
| ... | @@ -451,25 +451,25 @@ const Msf = struct { | ... | @@ -451,25 +451,25 @@ const Msf = struct { |
| 451 | const streams = try gpa.alloc(MsfStream, stream_count); | 451 | const streams = try gpa.alloc(MsfStream, stream_count); |
| 452 | errdefer gpa.free(streams); | 452 | errdefer gpa.free(streams); |
| 453 | | 453 | |
| 454 | for (streams, 0..) |*stream, i| { | 454 | for (streams, stream_sizes) |*stream, size| { |
| 455 | const size = stream_sizes[i]; | | |
| 456 | if (size == 0) { | 455 | if (size == 0) { |
| 457 | stream.* = .empty; | 456 | stream.* = .empty; |
| 458 | } else { | 457 | continue; |
| 459 | const blocks = try gpa.alloc(u32, size); | 458 | } |
| 460 | errdefer gpa.free(blocks); | 459 | const blocks = try gpa.alloc(u32, size); |
| 461 | for (blocks) |*block| { | 460 | errdefer gpa.free(blocks); |
| 462 | const block_id = try directory.interface.takeInt(u32, .little); | 461 | for (blocks) |*block| { |
| 463 | const n = (block_id % superblock.block_size); | 462 | const block_id = try directory.interface.takeInt(u32, .little); |
| 464 | // 0 is for pdb.SuperBlock, 1 and 2 for FPMs. | 463 | // Index 0 is reserved for the superblock. |
| 465 | if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len) | 464 | // In theory, every page which is `n * block_size + 1` or `n * block_size + 2` |
| 466 | return error.InvalidBlockIndex; | 465 | // is also reserved, for one of the FPMs. However, LLVM has been observed to map |
| 467 | block.* = block_id; | 466 | // these into actual streams, so allow it for compatibility. |
| 468 | } | 467 | if (block_id == 0 or block_id >= superblock.num_blocks) return error.InvalidBlockIndex; |
| 469 | const buffer = try gpa.alloc(u8, 64); | 468 | block.* = block_id; |
| 470 | errdefer gpa.free(buffer); | | |
| 471 | stream.* = .init(superblock.block_size, file_reader, blocks, buffer); | | |
| 472 | } | 469 | } |
| | 470 | const buffer = try gpa.alloc(u8, 64); |
| | 471 | errdefer gpa.free(buffer); |
| | 472 | stream.* = .init(superblock.block_size, file_reader, blocks, buffer); |
| 473 | } | 473 | } |
| 474 | | 474 | |
| 475 | const end = directory.logicalPos(); | 475 | const end = directory.logicalPos(); |