Skip to content

Commit a41a08e

Browse files
authored
Translate socket functions in C mode (#141)
`getsockname`, and the rest of the socket functions that receive a `struct sockaddr*` (`__SOCKADDR_ARG`) parameter, are defined differently in C and C++: ```c int getsockname (int fd, __SOCKADDR_ARG addr, socklen_t *len) #if defined __cplusplus #define __SOCKADDR_ARG struct sockaddr *__restrict #else typedef union { struct sockaddr *__restrict __sockaddr__; struct sockaddr_in *__restrict __sockaddr_in__; } __SOCKADDR_ARG __attribute__ ((__transparent_union__)); #endif ``` `__transparent_union__` is an attribute that allows a function whose parameter has that union type can be called with any of the union's arm types directly, without a cast: ```c struct sockaddr_in in; // this would normally generate an error because &in has type // sockaddr_in* but the argument is declared sockaddr* getsockname(fd, &in, len); struct sockaddr_in6 in6; getsockname(fd, &in6, len); // same tension between sockaddr_in6* and sockaddr_in* ``` `__transparent_union` is only available in C. In C++, an explicit cast is required. In the Clang AST, the transparent union object is created through a `CompoundLiteralExpression(InitListExpr(struct sockaddr_in *))`. We convert the argument of CompoundLiteralExpression in order to get the correct rust code.
1 parent 2c67f24 commit a41a08e

5 files changed

Lines changed: 72 additions & 0 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,18 @@ bool Converter::VisitInitListExpr(clang::InitListExpr *expr) {
26212621
return false;
26222622
}
26232623

2624+
bool Converter::VisitCompoundLiteralExpr(clang::CompoundLiteralExpr *expr) {
2625+
auto record = expr->getType()->getAsRecordDecl();
2626+
if (!record || !record->hasAttr<clang::TransparentUnionAttr>()) {
2627+
return true;
2628+
}
2629+
auto init = clang::cast<clang::InitListExpr>(expr->getInitializer());
2630+
assert(init->getNumInits() == 1);
2631+
PushExprKind push(*this, ExprKind::RValue);
2632+
Convert(init->getInit(0));
2633+
return false;
2634+
}
2635+
26242636
bool Converter::VisitArraySubscriptExpr(clang::ArraySubscriptExpr *expr) {
26252637
auto *base = expr->getBase();
26262638
if (base->IgnoreCasts()->getType()->isPointerType()) {

cpp2rust/converter/converter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
283283

284284
virtual bool VisitInitListExpr(clang::InitListExpr *expr);
285285

286+
virtual bool VisitCompoundLiteralExpr(clang::CompoundLiteralExpr *expr);
287+
286288
virtual bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr *expr);
287289

288290
virtual bool VisitCXXNullPtrLiteralExpr(clang::CXXNullPtrLiteralExpr *expr);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#define _GNU_SOURCE
12
#include <sys/types.h>
23
#include <sys/socket.h>
34

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub fn main() {
10+
unsafe {
11+
std::process::exit(main_0() as i32);
12+
}
13+
}
14+
unsafe fn main_0() -> i32 {
15+
let mut fd: i32 = 0;
16+
let mut ssloc: sockaddr_storage = std::mem::zeroed::<sockaddr_storage>();
17+
let mut slen: u32 = (::std::mem::size_of::<sockaddr_storage>() as u64 as u32);
18+
assert!(
19+
((((libc::getsockname(
20+
fd,
21+
((&mut ssloc as *mut sockaddr_storage) as *mut sockaddr),
22+
(&mut slen as *mut u32)
23+
)) == (-1_i32)) as i32)
24+
!= 0)
25+
);
26+
let mut sin: sockaddr_in = std::mem::zeroed::<sockaddr_in>();
27+
let mut inlen: u32 = (::std::mem::size_of::<sockaddr_in>() as u64 as u32);
28+
assert!(
29+
((((libc::getsockname(
30+
fd,
31+
((&mut sin as *mut sockaddr_in) as *mut sockaddr),
32+
(&mut inlen as *mut u32)
33+
)) == (-1_i32)) as i32)
34+
!= 0)
35+
);
36+
return 0;
37+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// no-compile: refcount
2+
#define _GNU_SOURCE
3+
#include <assert.h>
4+
#include <netinet/in.h>
5+
#include <sys/socket.h>
6+
#include <sys/types.h>
7+
8+
int main(void) {
9+
int fd = 0;
10+
11+
struct sockaddr_storage ssloc;
12+
socklen_t slen = sizeof(ssloc);
13+
assert(getsockname(fd, (struct sockaddr *)&ssloc, &slen) == -1);
14+
15+
struct sockaddr_in sin;
16+
socklen_t inlen = sizeof(sin);
17+
assert(getsockname(fd, (struct sockaddr *)&sin, &inlen) == -1);
18+
19+
return 0;
20+
}

0 commit comments

Comments
 (0)