Skip to content

Instantly share code, notes, and snippets.

@T-X
Last active May 7, 2024 13:11
Show Gist options
  • Save T-X/931258db04df2629df5b351d8c80214b to your computer and use it in GitHub Desktop.
Save T-X/931258db04df2629df5b351d8c80214b to your computer and use it in GitHub Desktop.
/*
* Compile with:
* $ gcc test.c -o /tmp/test -g -O2
*
* $ gcc --version
* gcc (Debian 13.2.0-24) 13.2.0
*
* Expected output:
*
* $ /tmp/test
* Before: input.sa_family: 10, output.ss_family: 0
* After: input.sa_family: 10, output.ss_family: 10
*
* Actual Output:
*
* $ /tmp/test
* Before: input.sa_family: 10, output.ss_family: 0
* After: input.sa_family: 10, output.ss_family: 0
* Error: address family was not copied? 10 vs. 0
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
static int copy_family_v4(const struct sockaddr_in *input, struct sockaddr_in *output)
{
in_addr_t pdst = ntohl(input->sin_addr.s_addr);
/* this breaks it, even for AF_INET6 case? */
if (((pdst) & 0xffffff00) != 0xe0000000)
return -1;
output->sin_family = input->sin_family;
return 0;
}
static int copy_family_v6(const struct sockaddr_in6 *input, struct sockaddr_in6 *output)
{
output->sin6_family = input->sin6_family;
return 0;
}
static int copy_family(struct sockaddr *input, struct sockaddr_storage *output)
{
switch (input->sa_family) {
case AF_INET:
return copy_family_v4((struct sockaddr_in *)input,
(struct sockaddr_in *)output);
case AF_INET6:
return copy_family_v6((struct sockaddr_in6 *)input,
(struct sockaddr_in6 *)output);
}
return -1;
}
static void sap_create_socket(void)
{
struct sockaddr_storage output = { 0 };
struct sockaddr input = { 0 };
int ret;
input.sa_family = AF_INET6;
printf("Before:\tinput.sa_family: %i, output.ss_family: %i\n", input.sa_family, output.ss_family);
ret = copy_family(&input, &output);
if (ret < 0)
return;
printf("After:\tinput.sa_family: %i, output.ss_family: %i\n", input.sa_family, output.ss_family);
if (input.sa_family != output.ss_family)
fprintf(stderr, "Error: address family was not copied? %i vs. %i\n", input.sa_family, output.ss_family);
return;
}
int main(int argc, char *argv[])
{
sap_create_socket();
return 0;
}
/*
* Compile with:
* $ gcc test.c -o /tmp/test -g -O2
*
* $ gcc --version
* gcc (Debian 13.2.0-24) 13.2.0
*
* Output:
*
* $ /tmp/test
* Before: input.sa_family: 10, output.ss_family: 0
* After: input.sa_family: 10, output.ss_family: 10
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
union sockaddr_union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr s;
};
static int copy_family_v4(const struct sockaddr_in *input, struct sockaddr_in *output)
{
/* now this is not undefined behaviour anymore: */
in_addr_t pdst = ntohl(input->sin_addr.s_addr);
if (((pdst) & 0xffffff00) != 0xe0000000)
return -1;
output->sin_family = input->sin_family;
return 0;
}
static int copy_family_v6(const struct sockaddr_in6 *input, struct sockaddr_in6 *output)
{
output->sin6_family = input->sin6_family;
return 0;
}
static int copy_family(union sockaddr_union *input, union sockaddr_union *output)
{
switch (input->s.sa_family) {
case AF_INET:
return copy_family_v4(&input->in,
&output->in);
case AF_INET6:
return copy_family_v6(&input->in6,
&output->in6);
}
return -1;
}
static void sap_create_socket(void)
{
union sockaddr_union output = { 0 };
union sockaddr_union input = { 0 };
int ret;
input.s.sa_family = AF_INET6;
printf("Before:\tinput.sa_family: %i, output.ss_family: %i\n", input.s.sa_family, output.s.sa_family);
ret = copy_family(&input, &output);
if (ret < 0)
return;
printf("After:\tinput.sa_family: %i, output.ss_family: %i\n", input.s.sa_family, output.s.sa_family);
if (input.s.sa_family != output.s.sa_family)
fprintf(stderr, "Error: address family was not copied? %i vs. %i\n", input.s.sa_family, output.s.sa_family);
return;
}
int main(int argc, char *argv[])
{
sap_create_socket();
return 0;
}
--- test-broken.c 2024-05-06 22:21:38.353799962 +0200
+++ test-fixed.c 2024-05-07 15:07:54.020057525 +0200
@@ -9,8 +9,7 @@
*
* $ /tmp/test
* Before: input.sa_family: 10, output.ss_family: 0
- * After: input.sa_family: 10, output.ss_family: 0
- * Error: address family was not copied? 10 vs. 0
+ * After: input.sa_family: 10, output.ss_family: 10
*/
#include <sys/types.h>
@@ -21,11 +20,16 @@
#include <string.h>
#include <netdb.h>
+union sockaddr_union {
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ struct sockaddr s;
+};
+
static int copy_family_v4(const struct sockaddr_in *input, struct sockaddr_in *output)
{
+ /* now this is not undefined behaviour anymore: */
in_addr_t pdst = ntohl(input->sin_addr.s_addr);
-
- /* this breaks it, even for AF_INET6 case? */
if (((pdst) & 0xffffff00) != 0xe0000000)
return -1;
@@ -39,15 +43,15 @@
return 0;
}
-static int copy_family(struct sockaddr *input, struct sockaddr_storage *output)
+static int copy_family(union sockaddr_union *input, union sockaddr_union *output)
{
- switch (input->sa_family) {
+ switch (input->s.sa_family) {
case AF_INET:
- return copy_family_v4((struct sockaddr_in *)input,
- (struct sockaddr_in *)output);
+ return copy_family_v4(&input->in,
+ &output->in);
case AF_INET6:
- return copy_family_v6((struct sockaddr_in6 *)input,
- (struct sockaddr_in6 *)output);
+ return copy_family_v6(&input->in6,
+ &output->in6);
}
return -1;
@@ -55,22 +59,22 @@
static void sap_create_socket(void)
{
- struct sockaddr_storage output = { 0 };
- struct sockaddr input = { 0 };
+ union sockaddr_union output = { 0 };
+ union sockaddr_union input = { 0 };
int ret;
- input.sa_family = AF_INET6;
+ input.s.sa_family = AF_INET6;
- printf("Before:\tinput.sa_family: %i, output.ss_family: %i\n", input.sa_family, output.ss_family);
+ printf("Before:\tinput.sa_family: %i, output.ss_family: %i\n", input.s.sa_family, output.s.sa_family);
ret = copy_family(&input, &output);
if (ret < 0)
return;
- printf("After:\tinput.sa_family: %i, output.ss_family: %i\n", input.sa_family, output.ss_family);
+ printf("After:\tinput.sa_family: %i, output.ss_family: %i\n", input.s.sa_family, output.s.sa_family);
- if (input.sa_family != output.ss_family)
- fprintf(stderr, "Error: address family was not copied? %i vs. %i\n", input.sa_family, output.ss_family);
+ if (input.s.sa_family != output.s.sa_family)
+ fprintf(stderr, "Error: address family was not copied? %i vs. %i\n", input.s.sa_family, output.s.sa_family);
return;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment