https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88240
--- Comment #10 from Thomas De Schampheleire <patrickdepinguin at gmail dot com> --- I was able to further investigate and reduce the problem. Qemu is now out of the picture, I can reproduce the issue directly on a real CPU. All I need to do is enable the 'underflow' exception bit using feenableexcept. Note that, as you will see below in the gdb output, the denormal exception is not enabled. Toolchain is still the same: gcc 7.3.0, glibc 2.27, binutils 2.30. See details in bug description. Below is the simplified test program, based on [1] with the addition of the exception enabling code. #define _GNU_SOURCE #include <stdio.h> #include <sqlite3.h> #include <fenv.h> static int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; for(i=0; i<argc; i++){ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } int main(int argc, char **argv){ sqlite3 *db; char *zErrMsg = 0; int rc; if( argc!=4 ){ fprintf(stderr, "Usage: %s EXCEPTIONS DATABASE SQL-STATEMENT\n", argv[0]); return(1); } // <<<<<<<<<<<< This code added to allow enabling exceptions unsigned short fctrl = 0; if (argv[1][0] == '1') { printf("Enabling exception: FE_UNDERFLOW\n"); feenableexcept(FE_UNDERFLOW); } else { printf("Not enabling exceptions.\n"); } asm volatile("fstcw %0" : "=m" (fctrl) ); printf("fctrl = %04x\n", fctrl); // >>>>>>>>>>>>>>>>>>>>> end of added code rc = sqlite3_open(argv[2], &db); if( rc ){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return(1); } rc = sqlite3_exec(db, argv[3], callback, 0, &zErrMsg); if( rc!=SQLITE_OK ){ fprintf(stderr, "SQL error: %s\n", zErrMsg); sqlite3_free(zErrMsg); } sqlite3_close(db); return 0; } I compiled this code and sqlite3 (version 3210000, but I don't think the exact version matters much) with the mentioned toolchain. Compilation command used for the test program: /home/tdescham/repo/isam/buildroot-qemu/output/host/opt/ext-toolchain/bin/i686-pc-linux-gnu-gcc --sysroot /home/tdescham/repo/isam/buildroot-qemu/output/host/i686-buildroot-linux-gnu/sysroot -march=pentiumpro -o sqlite-test sqlite-test.c -lsqlite3 -lm -g -O0 To reproduce, first create a simple database, not yet enabling exceptions: $ env LD_LIBRARY_PATH=/home/tdescham/repo/isam/buildroot-qemu/output/staging/usr/lib ./sqlite-test 0 /tmp/foo.db "create table foobar (id int primary key, name text)" Not enabling exceptions. fctrl = 037f Now, we can trigger the bug by showing some SQL output, if we enable the underflow exception: $ env LD_LIBRARY_PATH=/home/tdescham/repo/isam/buildroot-qemu/output/staging/usr/lib ./sqlite-test 1 /tmp/foo.db "select sql from sqlite_master where sql not NULL;" Enabling exception: FE_UNDERFLOW fctrl = 036f fish: Job 2, 'env LD_LIBRARY_PATH=/home/tdescā¦' terminated by signal SIGFPE (Floating point exception) If we do not enable the underflow exception, everything is fine: $ env LD_LIBRARY_PATH=/home/tdescham/repo/isam/buildroot-qemu/output/staging/usr/lib ./sqlite-test 0 /tmp/foo.db "select sql from sqlite_master where sql not NULL;" Not enabling exceptions. fctrl = 037f sql = CREATE TABLE foobar (id int primary key, name text) Here is the output of a debug session using gdb: $ env LD_LIBRARY_PATH=/home/tdescham/repo/isam/buildroot-qemu/output/staging/usr/lib gdb ./sqlite-test GNU gdb (Gentoo 8.1 p1) 8.1 Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./sqlite-test...done. (gdb) display $fctrl 1: $fctrl = <error: No registers.> (gdb) display $fstat 2: $fstat = <error: No registers.> (gdb) display $ftag 3: $ftag = <error: No registers.> (gdb) display $fop 4: $fop = <error: No registers.> (gdb) display $st0 5: $st0 = <error: No registers.> (gdb) display $st1 6: $st1 = <error: No registers.> (gdb) display $st2 7: $st2 = <error: No registers.> (gdb) break sqlite3VdbeMemStringify Function "sqlite3VdbeMemStringify" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (sqlite3VdbeMemStringify) pending. (gdb) run 1 /tmp/test.db "select sql from sqlite_master where sql not NULL;" Starting program: /tmp/x86/sqlite-test 1 /tmp/test.db "select sql from sqlite_master where sql not NULL;" [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Enabling exception: FE_UNDERFLOW fctrl = 036f Breakpoint 1, sqlite3VdbeMemStringify (pMem=0x8064290, enc=0x1, bForce=0x0) at sqlite3.c:70725 70725 SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ 1: $fctrl = 0x36f 2: $fstat = 0x0 3: $ftag = 0xffff 4: $fop = 0x0 5: $st0 = 0 6: $st1 = 0 7: $st2 = 0 (gdb) break *(&sqlite3VdbeMemStringify + 68) Breakpoint 2 at 0xf7f53bd4: file sqlite3.c, line 70748. ## ## NOTE: Showing disassembly of this function for context. ## Bug will occur at offset 68, but only after passing it the second time. ## (gdb) disassemble /m Dump of assembler code for function sqlite3VdbeMemStringify: 70725 SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ => 0xf7f53b90 <+0>: push %ebp 0xf7f53b91 <+1>: mov %esp,%ebp 0xf7f53b93 <+3>: push %edi 0xf7f53b94 <+4>: push %esi 0xf7f53b95 <+5>: mov %eax,%esi 0xf7f53b97 <+7>: push %ebx 0xf7f53b98 <+8>: sub $0x1c,%esp 0xf7f53b9f <+15>: mov %dl,-0x25(%ebp) 0xf7f53ba7 <+23>: mov %cl,-0x26(%ebp) 0xf7f53baa <+26>: call 0xf7f37b10 <__x86.get_pc_thunk.bx> 0xf7f53baf <+31>: add $0x7a451,%ebx 70726 int fg = pMem->flags; 0xf7f53b9b <+11>: movzwl 0x8(%eax),%eax 0xf7f53bb5 <+37>: mov %eax,-0x24(%ebp) 70727 const int nByte = 32; 70728 70729 assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); 70730 assert( !(fg&MEM_Zero) ); 70731 assert( !(fg&(MEM_Str|MEM_Blob)) ); 70732 assert( fg&(MEM_Int|MEM_Real) ); 70733 assert( (pMem->flags&MEM_RowSet)==0 ); 70734 assert( EIGHT_BYTE_ALIGNMENT(pMem) ); 70735 70736 70737 if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ 0xf7f53ba2 <+18>: mov $0x20,%edx 0xf7f53bb8 <+40>: mov %esi,%eax 0xf7f53bba <+42>: call 0xf7f4f6d5 <sqlite3VdbeMemClearAndResize> 0xf7f53bbf <+47>: test %eax,%eax 0xf7f53bc1 <+49>: je 0xf7f53bce <sqlite3VdbeMemStringify+62> 70738 pMem->enc = 0; 0xf7f53bc3 <+51>: movb $0x0,0xa(%esi) 70739 return SQLITE_NOMEM_BKPT; 0xf7f53bc7 <+55>: mov $0x7,%edi 0xf7f53bcc <+60>: jmp 0xf7f53c3a <sqlite3VdbeMemStringify+170> 70740 } 70741 70742 /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 70743 ** string representation of the value. Then, if the required encoding 70744 ** is UTF-16le or UTF-16be do a translation. 70745 ** 70746 ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. 70747 */ 70748 if( fg & MEM_Int ){ 0xf7f53bce <+62>: testb $0x4,-0x24(%ebp) 0xf7f53bd2 <+66>: mov %eax,%edi 0xf7f53bd4 <+68>: fldl (%esi) 0xf7f53bd6 <+70>: mov 0x10(%esi),%eax 0xf7f53bd9 <+73>: fstpl -0x20(%ebp) 0xf7f53bdc <+76>: je 0xf7f53bef <sqlite3VdbeMemStringify+95> 70749 sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); 0xf7f53bde <+78>: sub $0xc,%esp 0xf7f53be1 <+81>: pushl -0x1c(%ebp) 0xf7f53be4 <+84>: lea -0x1d2b7(%ebx),%edx 0xf7f53bea <+90>: pushl -0x20(%ebp) 0xf7f53bed <+93>: jmp 0xf7f53bfe <sqlite3VdbeMemStringify+110> 70750 }else{ 70751 assert( fg & MEM_Real ); 70752 sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); 0xf7f53bef <+95>: sub $0xc,%esp 0xf7f53bf2 <+98>: pushl -0x1c(%ebp) 0xf7f53bf5 <+101>: lea -0x2164a(%ebx),%edx 0xf7f53bfb <+107>: pushl -0x20(%ebp) 0xf7f53bfe <+110>: push %edx 0xf7f53bff <+111>: push %eax 0xf7f53c00 <+112>: push $0x20 0xf7f53c02 <+114>: call 0xf7f35af0 <sqlite3_snprintf@plt> 0xf7f53c0a <+122>: add $0x20,%esp 0xf7f53c0d <+125>: movzbl -0x25(%ebp),%edx 70753 } 70754 pMem->n = sqlite3Strlen30(pMem->z); 0xf7f53c07 <+119>: mov 0x10(%esi),%eax 0xf7f53c11 <+129>: call 0xf7f3da71 <sqlite3Strlen30> 0xf7f53c1e <+142>: mov %eax,0xc(%esi) 70755 pMem->enc = SQLITE_UTF8; 0xf7f53c1a <+138>: movb $0x1,0xa(%esi) 70756 pMem->flags |= MEM_Str|MEM_Term; 0xf7f53c21 <+145>: movzwl 0x8(%esi),%eax 70757 if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); 0xf7f53c16 <+134>: cmpb $0x0,-0x26(%ebp) 0xf7f53c25 <+149>: je 0xf7f53c2a <sqlite3VdbeMemStringify+154> 0xf7f53c27 <+151>: and $0xfffffff3,%eax 0xf7f53c2a <+154>: or $0x202,%eax 0xf7f53c2f <+159>: mov %ax,0x8(%esi) 70758 sqlite3VdbeChangeEncoding(pMem, enc); 0xf7f53c33 <+163>: mov %esi,%eax 0xf7f53c35 <+165>: call 0xf7f50c73 <sqlite3VdbeChangeEncoding> 70759 return SQLITE_OK; 70760 } 0xf7f53c3a <+170>: lea -0xc(%ebp),%esp 0xf7f53c3d <+173>: mov %edi,%eax 0xf7f53c3f <+175>: pop %ebx 0xf7f53c40 <+176>: pop %esi 0xf7f53c41 <+177>: pop %edi 0xf7f53c42 <+178>: pop %ebp 0xf7f53c43 <+179>: ret End of assembler dump. (gdb) continue Continuing. Breakpoint 2, 0xf7f53bd4 in sqlite3VdbeMemStringify (pMem=0x8064290, enc=0x1, bForce=0x0) at sqlite3.c:70748 70748 if( fg & MEM_Int ){ 1: $fctrl = 0x36f 2: $fstat = 0x0 3: $ftag = 0xffff 4: $fop = 0x0 5: $st0 = 0 6: $st1 = 0 7: $st2 = 0 (gdb) info reg eax 0x0 0x0 ecx 0xf7fce000 0xf7fce000 edx 0x8065f28 0x8065f28 ebx 0xf7fce000 0xf7fce000 esp 0xffffba50 0xffffba50 ebp 0xffffba78 0xffffba78 esi 0x8064290 0x8064290 edi 0x0 0x0 eip 0xf7f53bd4 0xf7f53bd4 <sqlite3VdbeMemStringify+68> eflags 0x202 [ IF ] cs 0x23 0x23 ss 0x2b 0x2b ds 0x2b 0x2b es 0x2b 0x2b fs 0x0 0x0 gs 0x63 0x63 (gdb) x $esi 0x8064290: 0x00000002 ## ## Bug will occur at the next assembly instruction. ## but not yet this first iteration. ## (gdb) stepi 0xf7f53bd6 70748 if( fg & MEM_Int ){ 1: $fctrl = 0x36f 2: $fstat = 0x3802 3: $ftag = 0x3fff 4: $fop = 0x0 5: $st0 = 9.88131291682493088353e-324 6: $st1 = 0 7: $st2 = 0 ## ## No SIGFPE happened this first time ## ## Note that if we step two instructions further, executing "fstpl -0x20(%ebp)" ## then the 'fstat' register changes value and actually gets the underflow bit: ## (gdb) stepi (gdb) stepi 1: $fctrl = 0x36f 2: $fstat = 0xb892 3: $ftag = 0x3fff 4: $fop = 0x55d 5: $st0 = 9.88131291682493088353e-324 6: $st1 = 0 7: $st2 = 0 ## ## I think this phase is the trigger for the bug, on the next fldl instruction. ## (gdb) continue Continuing. Breakpoint 1, sqlite3VdbeMemStringify (pMem=0x8064290, enc=0x1, bForce=0x0) at sqlite3.c:70725 70725 SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ 1: $fctrl = 0x36f 2: $fstat = 0xb892 3: $ftag = 0x3fff 4: $fop = 0x55d 5: $st0 = 9.88131291682493088353e-324 6: $st1 = 0 7: $st2 = 0 (gdb) continue Continuing. ## ## NOTE: bug will occur on next instruction. ## Note that meanwhile, fstat has changed from 0x3802 to 0xb892 and ## thus the underflow is already set, even though no SIGFPE occurred until now. ## Breakpoint 2, 0xf7f53bd4 in sqlite3VdbeMemStringify (pMem=0x8064290, enc=0x1, bForce=0x0) at sqlite3.c:70748 70748 if( fg & MEM_Int ){ 1: $fctrl = 0x36f 2: $fstat = 0xb892 3: $ftag = 0x3fff 4: $fop = 0x55d 5: $st0 = 9.88131291682493088353e-324 6: $st1 = 0 7: $st2 = 0 (gdb) info reg eax 0x0 0x0 ecx 0x0 0x0 edx 0x4 0x4 ebx 0xf7fce000 0xf7fce000 esp 0xffffba50 0xffffba50 ebp 0xffffba78 0xffffba78 esi 0x8064290 0x8064290 edi 0x0 0x0 eip 0xf7f53bd4 0xf7f53bd4 <sqlite3VdbeMemStringify+68> eflags 0x202 [ IF ] cs 0x23 0x23 ss 0x2b 0x2b ds 0x2b 0x2b es 0x2b 0x2b fs 0x0 0x0 gs 0x63 0x63 (gdb) x $esi 0x8064290: 0x00000003 (gdb) stepi Program received signal SIGFPE, Arithmetic exception. 0xf7f53bd4 in sqlite3VdbeMemStringify (pMem=0x8064290, enc=0x1, bForce=0x0) at sqlite3.c:70748 70748 if( fg & MEM_Int ){ 1: $fctrl = 0x36f 2: $fstat = 0xb892 3: $ftag = 0x3fff 4: $fop = 0x55d 5: $st0 = 9.88131291682493088353e-324 6: $st1 = 0 7: $st2 = 0 [1] https://www.sqlite.org/quickstart.html