1
0
mirror of https://github.com/open-simh/simh.git synced 2026-02-01 14:32:35 +00:00

ETH_MAC indirection erratum

Pervasive misuse of "ETH_MAC *" (a pointer to an ETH_MAC, aka a 6
element unsigned char array) when a simple "ETH_MAC" is correct.  The
best example of this was eth_mac_fmt() in sim_ether.c with the following
prototype:

    t_stat eth_mac_fmt (ETH_MAC* const mac, char* strmac)

The first parameter is a pointer to an array of 6 unsigned characters,
whereas it really just wants to be a pointer to the first element of the
array:

    t_stat eth_mac_scan (const ETH_MAC mac, char* strmac)

The "ETH_MAC *" indirection error also results in subtle memcpy() and
memcmp() issues, e.g.:

    void network_func(DEVICE *dev, ETH_MAC *mac)
    {
      ETH_MAC other_mac;

      /* ...code... */

      /* memcpy() bug: */
      memcpy(other_mac, mac, sizeof(ETH_MAC));

      /* or worse: */
      memcpy(mac, other_mac, sizeof(ETH_MAC));
    }

eth_copy_mac() and eth_mac_cmp() replace calls to memcpy() and memcmp()
that copy or compare Ethernet MAC addresses. These are type-enforcing
functions, i.e., the parameters are ETH_MAC-s, to avoid the subtle
memcpy() and memcmp() bugs.

This fix solves at least one Heisenbug in _eth_close() while free()-ing
write request buffers (and possibly other Heisenbugs.)
This commit is contained in:
B. Scott Michel
2025-03-03 16:26:28 -08:00
committed by Paul Koning
parent 73e5df3928
commit c20b391eea
10 changed files with 256 additions and 225 deletions

View File

@@ -341,22 +341,22 @@ t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, /* write synchronous pac
int eth_read (ETH_DEV* dev, ETH_PACK* packet, /* read single packet; */
ETH_PCALLBACK routine); /* callback when done*/
t_stat eth_filter (ETH_DEV* dev, int addr_count, /* set filter on incoming packets */
ETH_MAC* const addresses,
const ETH_MAC addresses[],
ETH_BOOL all_multicast,
ETH_BOOL promiscuous);
t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, /* set filter on incoming packets with hash */
ETH_MAC* const addresses,
const ETH_MAC addresses[],
ETH_BOOL all_multicast,
ETH_BOOL promiscuous,
ETH_MULTIHASH* const hash); /* AUTODIN II based 8 byte imperfect hash */
t_stat eth_filter_hash_ex (ETH_DEV* dev, int addr_count,/* set filter on incoming packets with hash */
ETH_MAC* const addresses,
const ETH_MAC addresses[],
ETH_BOOL all_multicast,
ETH_BOOL promiscuous,
ETH_BOOL match_broadcast,
ETH_MULTIHASH* const hash); /* AUTODIN II based 8 byte imperfect hash */
t_stat eth_check_address_conflict (ETH_DEV* dev,
ETH_MAC* const address);
const ETH_MAC address);
const char *eth_version (void); /* Version of dynamically loaded library (pcap) */
void eth_setcrc (ETH_DEV* dev, int need_crc); /* enable/disable CRC mode */
t_stat eth_set_async (ETH_DEV* dev, int latency); /* set read behavior to be async */
@@ -373,9 +373,9 @@ t_stat eth_show_devices (FILE* st, DEVICE *dptr, /* show ethernet devices
int eth_devices (int max, ETH_LIST* dev, ETH_BOOL framers); /* get ethernet devices on host */
void eth_show_dev (FILE*st, ETH_DEV* dev); /* show ethernet device state */
void eth_mac_fmt (ETH_MAC* const add, char* buffer); /* format ethernet mac address */
t_stat eth_mac_scan (ETH_MAC* mac, const char* strmac); /* scan string for mac, put in mac */
t_stat eth_mac_scan_ex (ETH_MAC* mac, /* scan string for mac, put in mac */
void eth_mac_fmt (const ETH_MAC add, char* buffer); /* format ethernet mac address */
t_stat eth_mac_scan (ETH_MAC mac, const char* strmac); /* scan string for mac, put in mac */
t_stat eth_mac_scan_ex (ETH_MAC mac, /* scan string for mac, put in mac */
const char* strmac, UNIT *uptr);/* for specified unit */
t_stat ethq_init (ETH_QUE* que, int max); /* initialize FIFO queue */
@@ -390,6 +390,44 @@ t_stat ethq_destroy(ETH_QUE* que); /* release FIFO queue */
const char *eth_capabilities(void);
t_stat sim_ether_test (DEVICE *dptr, const char *cptr); /* unit test routine */
/* Well-known Ethernet MAC addresses:
*
* eth_mac_any: All zeroes/any address
* eth_mac_bcast: All ones broadcast.
*/
extern const ETH_MAC eth_mac_any;
extern const ETH_MAC eth_mac_bcast;
/* Type-enforcing MAC address copy function.
*
* This inline helps to prevent the following situation:
*
* void network_func(DEVICE *dev, ETH_MAC *mac)
* {
* ETH_MAC other_mac;
*
* ...
* memcpy(other_mac, mac, sizeof(ETH_MAC));
* }
*
* The compiler will happily accept the memcpy() as valid because src and dst are
* converted to "void *". This is a subtle bug -- mac is a pointer to an ETH_MAC
* and memcpy will copy from somewhere other than the first byte of the source MAC
* address.
*/
static inline void eth_copy_mac(ETH_MAC dst, const ETH_MAC src)
{
memcpy(dst, src, sizeof(ETH_MAC));
}
/* Type-enforcing MAC comparison function. Helps to avoid subtle memcmp() issues
* (see above).
*/
static inline int eth_mac_cmp(const ETH_MAC a, const ETH_MAC b)
{
return memcmp(a, b, sizeof(ETH_MAC));
}
#if !defined(SIM_TEST_INIT) /* Need stubs for test APIs */
#define SIM_TEST_INIT
#define SIM_TEST(xxx)