diff options
| author | The6P4C <watsonjcampbell@gmail.com> | 2019-12-08 23:27:46 +1000 | 
|---|---|---|
| committer | The6P4C <watsonjcampbell@gmail.com> | 2019-12-08 23:52:05 +1000 | 
| commit | 578037dedf557806a5a39ab40a22b9cceade9a07 (patch) | |
| tree | a177c3f1c5c04279ec19968c7d74e49b6de61205 | |
| parent | 0ec00d892a91cc68e45479b46161f649caea2933 (diff) | |
| download | icestorm-578037dedf557806a5a39ab40a22b9cceade9a07.tar.gz icestorm-578037dedf557806a5a39ab40a22b9cceade9a07.tar.bz2 icestorm-578037dedf557806a5a39ab40a22b9cceade9a07.zip  | |
icepack: Fix Windows-only stack overflow in CRAM pbm generation (fixes #241)
On Windows, attempting to generate a netpbm image of the CRAM with
`icepack -b` causes the tool to crash after writing only the netpbm
header due to a stack overflow. The bug did not appear on Linux.
This was traced to a large stack-allocated variable length array
(`tile_type`) inside `FpgaConfig::write_cram_pbm`. For an 8k ice40 with
4 banks, `cram_width = 872` and `cram_height = 272` the `tile_type`
array ends up at `4 * 872 * 272 * sizeof(uint32_t) =` 3794944 bytes, or
about 3.6 MiB.
The fix replaces the large stack VLA with an array of 4 (bank) 2D C++
vectors, moving the large amount of data to the heap. Even though the
fix is not in a Windows-specific code path (and hence applies to all
platforms), I think it's wise to eliminate such a large stack allocation
entirely.
The fix has been tested working on both Windows and an Ubuntu WSL
install.
| -rw-r--r-- | icepack/icepack.cc | 20 | 
1 files changed, 19 insertions, 1 deletions
diff --git a/icepack/icepack.cc b/icepack/icepack.cc index 9b38ab5..2eec7ed 100644 --- a/icepack/icepack.cc +++ b/icepack/icepack.cc @@ -968,7 +968,25 @@ void FpgaConfig::write_cram_pbm(std::ostream &ofs, int bank_num) const  	ofs << "P3\n";  	ofs << stringf("%d %d\n", 2*this->cram_width, 2*this->cram_height);  	ofs << "255\n"; -	uint32_t tile_type[4][this->cram_width][this->cram_height]; + +	vector<vector<uint32_t>> tile_type[4]; + +	// We require random access to tile_type, so ensure that each column of each +	// bank is initialised so that all possible indices are valid +	for (int bank = 0; bank < 4; bank++) { +		tile_type[bank].reserve(this->cram_width); + +		for (int x = 0; x < this->cram_width; x++) { +			tile_type[bank].push_back(vector<uint32_t>(this->cram_height)); + +			for (int y = 0; y < this->cram_height; y++) { +				// Initialisation value unimportant - will be overwritten during +				// image generation +				tile_type[bank][x].push_back(0); +			} +		} +	} +  	for (int y = 0; y <= this->chip_height()+1; y++)  	for (int x = 0; x <= this->chip_width()+1; x++)  	{  | 
