Last active
May 7, 2024 13:11
-
-
Save T-X/931258db04df2629df5b351d8c80214b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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