Hello Nathan, 21.08.2024 00:21, Nathan Bossart wrote:
I've combined all the current proposed changes into one patch. I've also introduced signed versions of the negation functions into int.h to avoid relying on multiplication.
Thank you for taking care of this! I'd like to add some info to show how big the iceberg is. Beside other trap-triggered places in date/time conversion functions, I also discovered: 1) CREATE TABLE jt(j jsonb); INSERT INTO jt VALUES('[]'::jsonb); UPDATE jt SET j[0][-2147483648] = '0'; #4 0x00007f15ab00d7f3 in __GI_abort () at ./stdlib/abort.c:79 #5 0x00005570113b2591 in __addvsi3 () #6 0x00005570111d55a0 in push_null_elements (ps=0x7fff37385fb8, num=-2147483648) at jsonfuncs.c:1707 #7 0x00005570111d5749 in push_path (st=0x7fff37385fb8, level=0, path_elems=0x55701300c880, path_nulls=0x55701300d520, path_len=2, newval=0x7fff37386030) at jsonfuncs.c:1770 The "problematic" code: while (num-- > 0) *ps = 0; looks innocent to me, but is not for good enough for -ftrapv. I think there could be other similar places and this raises two questions: can they be reached with INT_MIN and what to do if so? By the way, the same can be seen with CC=clang CPPFLAGS="-ftrapv". Please look at the code produced by both compilers for x86_64: https://godbolt.org/z/vjszjf4b3 (clang generates ud1, while gcc uses call __addvsi3) The aside question is: should jsonb subscripting accept negative indexes when the target array is not initialized yet? Compare: CREATE TABLE jt(j jsonb); INSERT INTO jt VALUES('[]'::jsonb); UPDATE jt SET j[0][-1] = '0'; SELECT * FROM jt; j ------- [[0]] with CREATE TABLE jt(j jsonb); INSERT INTO jt VALUES('[[]]'::jsonb); UPDATE jt SET j[0][-1] = '0'; ERROR: path element at position 2 is out of range: -1 2) SELECT x, lag(x, -2147483648) OVER (ORDER BY x) FROM (SELECT 1) x; #4 0x00007fa7d00f47f3 in __GI_abort () at ./stdlib/abort.c:79 #5 0x00005623a7336851 in __negvsi2 () #6 0x00005623a726ae35 in leadlag_common (fcinfo=0x7ffd59cca950, forward=false, withoffset=true, withdefault=false) at windowfuncs.c:551 #7 0x00005623a726af19 in window_lag_with_offset (fcinfo=0x7ffd59cca950) at windowfuncs.c:594 As to 32-bit Debian, I wrote about before, I use gcc (Debian 12.2.0-14). Please look at the demo code (and it's assembly, produced with gcc -S -ftrapv t.c) attached: gcc -Wall -Wextra -fsanitize=signed-integer-overflow -Wstrict-overflow=5 \ -O0 -ftrapv t.c -o t && ./t Aborted (core dumped) #4 0xb762226a in __GI_abort () at ./stdlib/abort.c:79 #5 0x00495077 in __mulvdi3.cold () #6 0x00495347 in pg_mul_s64_overflow () (It looks like -Wstrict-overflow can't help with the static analysis desired in such cases.) Moreover, I got `make check` failed with -ftrapv on aarch64 (using gcc 8.3) as follows: #1 0x0000007e1edc48e8 in __GI_abort () at abort.c:79 #2 0x0000005ee66b71cc in __subvdi3 () #3 0x0000005ee6560e24 in int8gcd_internal (arg1=-9223372036854775808, arg2=1) at int8.c:623 #4 0x0000005ee62f576c in ExecInterpExpr (state=0x5eeaba9d18, econtext=0x5eeaba95f0, isnull=<optimized out>) at execExprInterp.c:770 ... #13 0x0000005ee64e5d84 in exec_simple_query (query_string=query_string@entry=0x5eeaac7500 "SELECT a, b, gcd(a, b), gcd(a, -b), gcd(b, a), gcd(-b, a)\nFROM (VALUES (0::int8, 0::int8),\n", ' ' <repeats 13 times>, "(0::int8, 29893644334::int8),\n", ' ' <repeats 13 times>, "(288484263558::int8, 29893644334::int8),\n", ' ' <repeats 12 times>...) at postgres.c:1284
So I wonder whether enabling -ftrapv can really help us prepare the code for -fno-wrapv? Best regards, Alexander
#include <stdio.h> typedef char bool; typedef long long int int64; static inline bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result) { return __builtin_mul_overflow(a, b, result); } int main() { int64 a = 9223372036854775807L; int64 b = 2L; int64 c = 0; bool r; r = pg_mul_s64_overflow(a, b, &c); printf("r: %d, c: %lld\n", r, c); }
.file "t.c" .text .globl __mulvdi3 .type pg_mul_s64_overflow, @function pg_mul_s64_overflow: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 pushl %edi pushl %esi pushl %ebx subl $76, %esp .cfi_offset 7, -12 .cfi_offset 6, -16 .cfi_offset 3, -20 call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax movl %eax, -52(%ebp) movl 8(%ebp), %eax movl %eax, -32(%ebp) movl 12(%ebp), %eax movl %eax, -28(%ebp) movl 16(%ebp), %eax movl %eax, -40(%ebp) movl 20(%ebp), %eax movl %eax, -36(%ebp) movl $0, -64(%ebp) movl $0, -60(%ebp) movl -32(%ebp), %eax movl -28(%ebp), %edx movl %edx, %eax movl %eax, %edx sarl $31, %edx movl %eax, -48(%ebp) movl %edx, -44(%ebp) movl -32(%ebp), %eax movl %eax, %ecx sarl $31, %ecx movl -40(%ebp), %eax movl -36(%ebp), %edx movl %eax, %esi movl %edx, %edi movl %edi, %esi movl %esi, %edi sarl $31, %edi movl -40(%ebp), %eax sarl $31, %eax movl -48(%ebp), %ebx cmpl %ebx, %ecx jne .L4 cmpl %esi, %eax jne .L5 movl -40(%ebp), %eax imull -32(%ebp) jmp .L2 .L5: movl -40(%ebp), %eax movl -36(%ebp), %edx movl %eax, -72(%ebp) movl %edx, -68(%ebp) movl -32(%ebp), %eax movl %eax, -48(%ebp) jmp .L6 .L4: cmpl %esi, %eax jne .L7 movl -32(%ebp), %eax movl -28(%ebp), %edx movl %eax, -72(%ebp) movl %edx, -68(%ebp) movl -48(%ebp), %esi movl -40(%ebp), %eax movl %eax, -48(%ebp) .L6: movl -40(%ebp), %edi movl %edi, %eax mull -32(%ebp) movl %eax, -80(%ebp) movl %edx, -76(%ebp) movl -48(%ebp), %edi movl %edi, %eax mull %esi movl %eax, %ecx movl %edx, %ebx testl %esi, %esi jns .L8 movl %edi, %eax movl $0, %edx movl %eax, %edx movl $0, %eax movl %eax, %esi movl %edx, %edi movl %ecx, %eax movl %ebx, %edx subl %esi, %eax sbbl %edi, %edx movl %eax, %ecx movl %edx, %ebx .L8: cmpl $0, -48(%ebp) jns .L9 movl %ecx, %eax movl %ebx, %edx subl -72(%ebp), %eax sbbl -68(%ebp), %edx movl %eax, %ecx movl %edx, %ebx .L9: movl -80(%ebp), %eax movl -76(%ebp), %edx movl %edx, %eax xorl %edx, %edx addl %ecx, %eax adcl %ebx, %edx movl %eax, %ecx movl %edx, %ebx movl %ecx, %eax movl %ebx, %edx movl %edx, %eax movl %eax, %edx sarl $31, %edx movl %ecx, %esi sarl $31, %esi cmpl %eax, %esi jne .L10 movl %ecx, %ebx movl $0, %ecx movl %ecx, %eax movl %ebx, %edx movl -80(%ebp), %ecx movl $0, %ebx orl %ecx, %eax orl %ebx, %edx jmp .L2 .L7: pushl -36(%ebp) pushl -40(%ebp) pushl -28(%ebp) pushl -32(%ebp) movl -52(%ebp), %ebx call __mulvdi3@PLT addl $16, %esp movl -48(%ebp), %ebx leal 1(%ebx), %ecx cmpl $1, %ecx ja .L3 leal 1(%esi), %ecx cmpl $1, %ecx ja .L3 cmpl %esi, -48(%ebp) jne .L11 movl $0, %ebx movl $0, %ecx cmpl %eax, %ebx sbbl %edx, %ecx jge .L3 jmp .L2 .L11: testl %edx, %edx jns .L3 jmp .L2 .L10: pushl -36(%ebp) pushl -40(%ebp) pushl -28(%ebp) pushl -32(%ebp) movl -52(%ebp), %ebx call __mulvdi3@PLT addl $16, %esp .L3: movl $1, -64(%ebp) movl $0, -60(%ebp) .L2: movl 24(%ebp), %ecx movl %eax, (%ecx) movl %edx, 4(%ecx) movl -64(%ebp), %eax movl -60(%ebp), %edx andl $1, %eax leal -12(%ebp), %esp popl %ebx .cfi_restore 3 popl %esi .cfi_restore 6 popl %edi .cfi_restore 7 popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size pg_mul_s64_overflow, .-pg_mul_s64_overflow .section .rodata .LC0: .string "r: %d, c: %lld\n" .text .globl main .type main, @function main: .LFB1: .cfi_startproc leal 4(%esp), %ecx .cfi_def_cfa 1, 0 andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp .cfi_escape 0x10,0x5,0x2,0x75,0 pushl %ebx pushl %ecx .cfi_escape 0xf,0x3,0x75,0x78,0x6 .cfi_escape 0x10,0x3,0x2,0x75,0x7c subl $32, %esp call __x86.get_pc_thunk.bx addl $_GLOBAL_OFFSET_TABLE_, %ebx movl $-1, -16(%ebp) movl $2147483647, -12(%ebp) movl $2, -24(%ebp) movl $0, -20(%ebp) movl $0, -40(%ebp) movl $0, -36(%ebp) subl $12, %esp leal -40(%ebp), %eax pushl %eax pushl -20(%ebp) pushl -24(%ebp) pushl -12(%ebp) pushl -16(%ebp) call pg_mul_s64_overflow addl $32, %esp movb %al, -25(%ebp) movl -40(%ebp), %eax movl -36(%ebp), %edx movsbl -25(%ebp), %ecx pushl %edx pushl %eax pushl %ecx leal .LC0@GOTOFF(%ebx), %eax pushl %eax call printf@PLT addl $16, %esp movl $0, %eax leal -8(%ebp), %esp popl %ecx .cfi_restore 1 .cfi_def_cfa 1, 0 popl %ebx .cfi_restore 3 popl %ebp .cfi_restore 5 leal -4(%ecx), %esp .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE1: .size main, .-main .section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat .globl __x86.get_pc_thunk.ax .hidden __x86.get_pc_thunk.ax .type __x86.get_pc_thunk.ax, @function __x86.get_pc_thunk.ax: .LFB2: .cfi_startproc movl (%esp), %eax ret .cfi_endproc .LFE2: .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat .globl __x86.get_pc_thunk.bx .hidden __x86.get_pc_thunk.bx .type __x86.get_pc_thunk.bx, @function __x86.get_pc_thunk.bx: .LFB3: .cfi_startproc movl (%esp), %ebx ret .cfi_endproc .LFE3: .ident "GCC: (Debian 12.2.0-14) 12.2.0" .section .note.GNU-stack,"",@progbits