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

Reply via email to