linux-user: Rewrite __get_user/__put_user with __builtin_choose_expr
The previous formuation with multiple assignments to __typeof(*hptr) falls down when hptr is qualified const. E.g. with const struct S *p, p->f is also qualified const. With this formulation, there's no assignment to any local variable. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
c732a52d3e
commit
658f2dc970
@ -287,36 +287,39 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
|
||||
(type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
|
||||
}
|
||||
|
||||
/* NOTE __get_user and __put_user use host pointers and don't check access. */
|
||||
/* These are usually used to access struct data members once the
|
||||
* struct has been locked - usually with lock_user_struct().
|
||||
*/
|
||||
#define __put_user(x, hptr)\
|
||||
({ __typeof(*hptr) pu_ = (x);\
|
||||
switch(sizeof(*hptr)) {\
|
||||
case 1: break;\
|
||||
case 2: pu_ = tswap16(pu_); break; \
|
||||
case 4: pu_ = tswap32(pu_); break; \
|
||||
case 8: pu_ = tswap64(pu_); break; \
|
||||
default: abort();\
|
||||
}\
|
||||
memcpy(hptr, &pu_, sizeof(pu_)); \
|
||||
0;\
|
||||
})
|
||||
/* NOTE __get_user and __put_user use host pointers and don't check access.
|
||||
These are usually used to access struct data members once the struct has
|
||||
been locked - usually with lock_user_struct. */
|
||||
|
||||
#define __get_user(x, hptr) \
|
||||
({ __typeof(*hptr) gu_; \
|
||||
memcpy(&gu_, hptr, sizeof(gu_)); \
|
||||
switch(sizeof(*hptr)) {\
|
||||
case 1: break; \
|
||||
case 2: gu_ = tswap16(gu_); break; \
|
||||
case 4: gu_ = tswap32(gu_); break; \
|
||||
case 8: gu_ = tswap64(gu_); break; \
|
||||
default: abort();\
|
||||
}\
|
||||
(x) = gu_; \
|
||||
0;\
|
||||
})
|
||||
/* Tricky points:
|
||||
- Use __builtin_choose_expr to avoid type promotion from ?:,
|
||||
- Invalid sizes result in a compile time error stemming from
|
||||
the fact that abort has no parameters.
|
||||
- It's easier to use the endian-specific unaligned load/store
|
||||
functions than host-endian unaligned load/store plus tswapN. */
|
||||
|
||||
#define __put_user_e(x, hptr, e) \
|
||||
(__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \
|
||||
((hptr), (x)), 0)
|
||||
|
||||
#define __get_user_e(x, hptr, e) \
|
||||
((x) = \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \
|
||||
__builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \
|
||||
(hptr), 0)
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
# define __put_user(x, hptr) __put_user_e(x, hptr, be)
|
||||
# define __get_user(x, hptr) __get_user_e(x, hptr, be)
|
||||
#else
|
||||
# define __put_user(x, hptr) __put_user_e(x, hptr, le)
|
||||
# define __get_user(x, hptr) __get_user_e(x, hptr, le)
|
||||
#endif
|
||||
|
||||
/* put_user()/get_user() take a guest address and check access */
|
||||
/* These are usually used to access an atomic data type, such as an int,
|
||||
|
Loading…
Reference in New Issue
Block a user