Fixed issue when the hash length is zero (#2314)

* Fixed issue when the hash length is zero

The following is illegal, even if no elements in the pointer are accessed:

	std::vector<my_struct> my_vec(0);	// create an empty std::vector
	my_struct *ptr = &my_vec[0];

While this is a degenerate scenario, this should be fixed
This commit is contained in:
npwoods 2017-05-27 21:23:45 -04:00 committed by Vas Crabb
parent 46eb930948
commit 297bea495d
6 changed files with 63 additions and 99 deletions

View File

@ -468,15 +468,6 @@ image_init_result a78_cart_slot_device::call_load()
}
void a78_partialhash(util::hash_collection &dest, const unsigned char *data,
unsigned long length, const char *functions)
{
if (length <= 128)
return;
dest.compute(&data[128], length - 128, functions);
}
/*-------------------------------------------------
call_unload
-------------------------------------------------*/

View File

@ -81,9 +81,6 @@ protected:
};
void a78_partialhash(util::hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions);
// ======================> a78_cart_slot_device
class a78_cart_slot_device : public device_t,
@ -114,7 +111,7 @@ public:
virtual bool is_reset_on_load() const override { return 1; }
virtual const char *image_interface() const override { return "a7800_cart"; }
virtual const char *file_extensions() const override { return "bin,a78"; }
virtual device_image_partialhash_func get_partial_hash() const override { return &a78_partialhash; }
virtual u32 unhashed_header_length() const override { return 128; }
// slot interface overrides
virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;

View File

@ -1015,17 +1015,3 @@ WRITE8_MEMBER(nes_cart_slot_device::write_ex)
m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8);
}
}
//-------------------------------------------------
// partial hash function to be used by
// device_image_partialhash_func
//-------------------------------------------------
void nes_partialhash(util::hash_collection &dest, const unsigned char *data,
unsigned long length, const char *functions)
{
if (length <= 16)
return;
dest.compute(&data[16], length - 16, functions);
}

View File

@ -331,8 +331,6 @@ protected:
std::vector<uint16_t> m_prg_bank_map;
};
void nes_partialhash(util::hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions);
// ======================> nes_cart_slot_device
class nes_cart_slot_device : public device_t,
@ -364,7 +362,7 @@ public:
virtual bool is_reset_on_load() const override { return 1; }
virtual const char *image_interface() const override { return "nes_cart"; }
virtual const char *file_extensions() const override { return "nes,unf,unif"; }
virtual device_image_partialhash_func get_partial_hash() const override { return &nes_partialhash; }
virtual u32 unhashed_header_length() const override { return 16; }
// slot interface overrides
virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;

View File

@ -175,23 +175,6 @@ iodevice_t device_image_interface::device_typeid(const char *name)
return (iodevice_t)-1;
}
/*-------------------------------------------------
device_compute_hash - compute a hash,
using this device's partial hash if appropriate
-------------------------------------------------*/
void device_image_interface::device_compute_hash(util::hash_collection &hashes, const void *data, size_t length, const char *types) const
{
/* retrieve the partial hash func */
device_image_partialhash_func partialhash = get_partial_hash();
/* compute the hash */
if (partialhash)
partialhash(hashes, (const unsigned char*)data, length, types);
else
hashes.compute(reinterpret_cast<const u8 *>(data), length, types);
}
//-------------------------------------------------
// set_image_filename - specifies the filename of
// an image
@ -513,37 +496,46 @@ bool device_image_interface::load_software_region(const char *tag, optional_shar
// to be loaded
// ****************************************************************************
void device_image_interface::run_hash(util::core_file &file, void (*partialhash)(util::hash_collection &, const unsigned char *, unsigned long, const char *),
util::hash_collection &hashes, const char *types)
bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
{
u32 size;
std::vector<u8> buf;
// reset the hash; we want to override existing data
hashes.reset();
size = (u32) file.size();
buf.resize(size);
memset(&buf[0], 0, size);
// figure out the size, and "cap" the skip bytes
u64 size = file.size();
skip_bytes = (u32) std::min((u64) skip_bytes, size);
// read the file
file.seek(0, SEEK_SET);
file.read(&buf[0], size);
// seek to the beginning
file.seek(skip_bytes, SEEK_SET);
u64 position = skip_bytes;
if (partialhash)
partialhash(hashes, &buf[0], size, types);
else
hashes.compute(&buf[0], size, types);
// keep on reading hashes
hashes.begin(types);
while (position < size)
{
uint8_t buffer[8192];
// read bytes
const u32 count = (u32) std::min(size - position, (u64) sizeof(buffer));
const u32 actual_count = file.read(buffer, count);
if (actual_count == 0)
return false;
position += actual_count;
// and compute the hashes
hashes.buffer(buffer, actual_count);
}
hashes.end();
// cleanup
file.seek(0, SEEK_SET);
return true;
}
void device_image_interface::image_checkhash()
bool device_image_interface::image_checkhash()
{
device_image_partialhash_func partialhash;
// only calculate CRC if it hasn't been calculated, and the open_mode is read only
u32 crcval;
if (!m_hash.crc(crcval) && is_readonly() && !m_created)
@ -551,29 +543,26 @@ void device_image_interface::image_checkhash()
// do not cause a linear read of 600 megs please
// TODO: use SHA1 in the CHD header as the hash
if (image_type() == IO_CDROM)
return;
return true;
// Skip calculating the hash when we have an image mounted through a software list
if (loaded_through_softlist())
return;
return true;
// retrieve the partial hash func
partialhash = get_partial_hash();
run_hash(*m_file, partialhash, m_hash, util::hash_collection::HASH_TYPES_ALL);
// run the hash
if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL))
return false;
}
return;
return true;
}
util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const
{
// retrieve the partial hash func
device_image_partialhash_func partialhash = get_partial_hash();
// and calculate the hash
// calculate the hash
util::hash_collection hash;
run_hash(file, partialhash, hash, util::hash_collection::HASH_TYPES_ALL);
if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
hash.reset();
return hash;
}
@ -1150,25 +1139,32 @@ image_init_result device_image_interface::finish_load()
if (m_is_loading)
{
image_checkhash();
if (m_created)
if (!image_checkhash())
{
err = call_create(m_create_format, m_create_args);
if (err != image_init_result::PASS)
{
if (!m_err)
m_err = IMAGE_ERROR_UNSPECIFIED;
}
m_err = IMAGE_ERROR_INVALIDIMAGE;
err = image_init_result::FAIL;
}
else
if (err == image_init_result::PASS)
{
// using device load
err = call_load();
if (err != image_init_result::PASS)
if (m_created)
{
if (!m_err)
m_err = IMAGE_ERROR_UNSPECIFIED;
err = call_create(m_create_format, m_create_args);
if (err != image_init_result::PASS)
{
if (!m_err)
m_err = IMAGE_ERROR_UNSPECIFIED;
}
}
else
{
// using device load
err = call_load();
if (err != image_init_result::PASS)
{
if (!m_err)
m_err = IMAGE_ERROR_UNSPECIFIED;
}
}
}
}

View File

@ -97,8 +97,6 @@ enum class image_verify_result { PASS, FAIL };
// device image interface function types
typedef delegate<image_init_result (device_image_interface &)> device_image_load_delegate;
typedef delegate<void (device_image_interface &)> device_image_func_delegate;
// legacy
typedef void (*device_image_partialhash_func)(util::hash_collection &, const unsigned char *, unsigned long, const char *);
//**************************************************************************
// MACROS
@ -136,13 +134,11 @@ public:
static const char *device_brieftypename(iodevice_t type);
static iodevice_t device_typeid(const char *name);
virtual void device_compute_hash(util::hash_collection &hashes, const void *data, size_t length, const char *types) const;
virtual image_init_result call_load() { return image_init_result::PASS; }
virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; }
virtual void call_unload() { }
virtual std::string call_display() { return std::string(); }
virtual device_image_partialhash_func get_partial_hash() const { return nullptr; }
virtual u32 unhashed_header_length() const { return 0; }
virtual bool core_opens_image_file() const { return true; }
virtual iodevice_t image_type() const = 0;
virtual bool is_readable() const = 0;
@ -267,7 +263,7 @@ protected:
void make_readonly() { m_readonly = true; }
void image_checkhash();
bool image_checkhash();
const software_part *find_software_item(const std::string &identifier, bool restrict_to_interface, software_list_device **device = nullptr) const;
std::string software_get_default_slot(const char *default_card_slot) const;
@ -305,7 +301,7 @@ private:
bool load_software_part(const std::string &identifier);
bool init_phase() const;
static void run_hash(util::core_file &file, void(*partialhash)(util::hash_collection &, const unsigned char *, unsigned long, const char *), util::hash_collection &hashes, const char *types);
static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types);
// loads an image or software items and resets - called internally when we
// load an is_reset_on_load() item