SIGFPE with gcc 7.3.0 in sqlite3: fldl instruction underflow
Thomas De Schampheleire
patrickdepinguin@gmail.com
Wed Nov 21 14:44:00 GMT 2018
Hello,
I have a problem with a program that links with sqlite3 and executes
an SQL statement. The program is executed under Qemu, with an 32-bit
x86 emulated machine, and Qemu is running on a 64-bit x86 host.
Originally, the program worked fine, when it was compiled with a
toolchain composed out of gcc 4.9.2, glibc 2.21, binutils 2.24.
Now I am rebuilding the system with a toolchain composed out of gcc
7.3, glibc 2.27, binutils 2.30. In this case, the program receives a
SIGFPE (Arithmetic Error) in Sqlite code. Analysis of the coredump
reveals that the error occurs on an 'fldl' instruction (Floating-point
Load Long) and that the exact cause of the error is an underflow.
The problem does not appear when Qemu is started without KVM support.
In this case, floating point handling is covered by Qemu itself. The
problem does occur when passing '-enable-kvm' which causes the host
machine to execute most instructions.
However, it is unclear to me why gcc is emitting an 'fldl' instruction
here (which wasn't present with the old toolchain) and why it is
causing an underflow. The part of the code being executed is not
handling a floating-point value.
There is a print of a real a bit further down, which is conditional on
a flag indicating that the union indeed holds a real value. Could this
'fldl' instruction be part of that code, moved upwards? In that case,
who is at fault here? Because the loading of the real should only
happen when we know that it is indeed a real, and not an integer.
I tried reproducing the problem with a simple program from the Sqlite
'Getting started' guide, running the same SQL query, and linking to
the exact same binary copy of the sqlite shared library file, but this
worked fine.
The source code in question is:
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
int fg = pMem->flags;
const int nByte = 32;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( !(fg&MEM_ZerAny help is much appreciated.uio) );
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
pMem->enc = 0;
return SQLITE_NOMEM_BKPT;
}
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
** string representation of the value. Then, if the required encoding
** is UTF-16le or UTF-16be do a translation.
**
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Int ){
sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
}else{
assert( fg & MEM_Real );
sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
}
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real);
sqlite3VdbeChangeEncoding(pMem, enc);
return SQLITE_OK;
}
The disassembly with the new toolchain (gcc 7.3.0) is below.
I marked with leading # signs the part of the disassembly I do not
understand and where the problem occurs.
When the problem occurs, the value pointed to in %esi is '3'.
0001c1cb <sqlite3VdbeMemStringify>:
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
1c1cb: 55 push %ebp
1c1cc: 89 e5 mov %esp,%ebp
1c1ce: 57 push %edi
1c1cf: 56 push %esi
1c1d0: 53 push %ebx
1c1d1: 83 ec 2c sub $0x2c,%esp
1c1d4: e8 fc ff ff ff call 1c1d5 <sqlite3VdbeMemStringify+0xa>
1c1d9: 81 c3 02 00 00 00 add $0x2,%ebx
1c1df: 89 c6 mov %eax,%esi
1c1e1: 89 55 d8 mov %edx,-0x28(%ebp)
1c1e4: 89 4d d4 mov %ecx,-0x2c(%ebp)
int fg = pMem->flags;
1c1e7: 8b 40 08 mov 0x8(%eax),%eax
1c1ea: 66 89 45 de mov %ax,-0x22(%ebp)
if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
1c1ee: ba 20 00 00 00 mov $0x20,%edx
1c1f3: 89 f0 mov %esi,%eax
1c1f5: e8 5d bb ff ff call 17d57
<sqlite3VdbeMemClearAndResize>
1c1fa: 85 c0 test %eax,%eax
1c1fc: 74 0b je 1c209
<sqlite3VdbeMemStringify+0x3e>
pMem->enc = 0;
1c1fe: c6 46 0a 00 movb $0x0,0xa(%esi)
return SQLITE_NOMEM_BKPT;
1c202: bf 07 00 00 00 mov $0x7,%edi
1c207: eb 72 jmp 1c27b
<sqlite3VdbeMemStringify+0xb0> --> exit
# 1c209: 89 c7 mov %eax,%edi
# 1c20b: dd 06 fldl (%esi)
# 1c20d: dd 5d e0 fstpl -0x20(%ebp)
# 1c210: 8b 46 10 mov 0x10(%esi),%eax
if( fg & MEM_Int ){
1c213: f6 45 de 04 testb $0x4,-0x22(%ebp)
1c217: 74 11 je 1c22a
<sqlite3VdbeMemStringify+0x5f>
sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
1c219: 83 ec 0c sub $0xc,%esp
1c21c: ff 75 e4 pushl -0x1c(%ebp)
1c21f: ff 75 e0 pushl -0x20(%ebp)
1c222: 8d 93 00 00 00 00 lea 0x0(%ebx),%edx
1c228: eb 0f jmp 1c239
<sqlite3VdbeMemStringify+0x6e>
sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
1c22a: 83 ec 0c sub $0xc,%esp
1c22d: ff 75 e4 pushl -0x1c(%ebp)
1c230: ff 75 e0 pushl -0x20(%ebp)
1c233: 8d 93 00 00 00 00 lea 0x0(%ebx),%edx
1c239: 52 push %edx
1c23a: 50 push %eax
1c23b: 6a 20 push $0x20
1c23d: e8 fc ff ff ff call 1c23e
<sqlite3VdbeMemStringify+0x73>
1c242: 83 c4 20 add $0x20,%esp
1c245: 0f b6 55 d8 movzbl -0x28(%ebp),%edx
pMem->n = sqlite3Strlen30(pMem->z);
1c249: 8b 46 10 mov 0x10(%esi),%eax
1c24c: e8 a8 9d fe ff call 5ff9 <sqlite3Strlen30>
1c251: 89 46 0c mov %eax,0xc(%esi)
pMem->enc = SQLITE_UTF8;
1c254: c6 46 0a 01 movb $0x1,0xa(%esi)
pMem->flags |= MEM_Str|MEM_Term;
1c258: 8b 46 08 mov 0x8(%esi),%eax
1c25b: 89 c1 mov %eax,%ecx
1c25d: 83 e1 f3 and $0xfffffff3,%ecx
1c260: 66 81 c9 02 02 or $0x202,%cx
1c265: 66 0d 02 02 or $0x202,%ax
1c269: 80 7d d4 00 cmpb $0x0,-0x2c(%ebp)
1c26d: 0f 45 c1 cmovne %ecx,%eax
1c270: 66 89 46 08 mov %ax,0x8(%esi)
sqlite3VdbeChangeEncoding(pMem, enc);
1c274: 89 f0 mov %esi,%eax
1c276: e8 5f d0 ff ff call 192da <sqlite3VdbeChangeEncoding>
}
1c27b: 89 f8 mov %edi,%eax
1c27d: 8d 65 f4 lea -0xc(%ebp),%esp
1c280: 5b pop %ebx
1c281: 5e pop %esi
1c282: 5f pop %edi
1c283: 5d pop %ebp
1c284: c3 ret
while the disassembly with the old toolchain is:
0001cdff <sqlite3VdbeMemStringify>:
1cdff: 55 push %ebp
1ce00: 89 e5 mov %esp,%ebp
1ce02: 57 push %edi
1ce03: 56 push %esi
1ce04: 53 push %ebx
1ce05: 83 ec 1c sub $0x1c,%esp
1ce08: e8 fc ff ff ff call 1ce09 <sqlite3VdbeMemStringify+0xa>
1ce0d: 81 c3 02 00 00 00 add $0x2,%ebx
1ce13: 89 c7 mov %eax,%edi
1ce15: 89 55 e0 mov %edx,-0x20(%ebp)
1ce18: 8b 45 08 mov 0x8(%ebp),%eax
1ce1b: 89 45 dc mov %eax,-0x24(%ebp)
1ce1e: 8b 47 08 mov 0x8(%edi),%eax
1ce21: 66 89 45 e6 mov %ax,-0x1a(%ebp)
1ce25: ba 20 00 00 00 mov $0x20,%edx
1ce2a: 89 f8 mov %edi,%eax
1ce2c: e8 be b8 ff ff call 186ef
<sqlite3VdbeMemClearAndResize>
1ce31: 89 c6 mov %eax,%esi
1ce33: 85 c0 test %eax,%eax
1ce35: 74 0b je 1ce42
<sqlite3VdbeMemStringify+0x43>
1ce37: c6 47 0a 00 movb $0x0,0xa(%edi)
1ce3b: be 07 00 00 00 mov $0x7,%esi
1ce40: eb 60 jmp 1cea2
<sqlite3VdbeMemStringify+0xa3>
1ce42: f6 45 e6 04 testb $0x4,-0x1a(%ebp)
(+0x43)
1ce46: 74 10 je 1ce58
<sqlite3VdbeMemStringify+0x59>
1ce48: 83 ec 0c sub $0xc,%esp
1ce4b: ff 77 04 pushl 0x4(%edi)
1ce4e: ff 37 pushl (%edi)
1ce50: 8d 83 00 00 00 00 lea 0x0(%ebx),%eax
1ce56: eb 0e jmp 1ce66
<sqlite3VdbeMemStringify+0x67>
1ce58: 83 ec 0c sub $0xc,%esp
1ce5b: ff 77 04 pushl 0x4(%edi)
1ce5e: ff 37 pushl (%edi)
1ce60: 8d 83 00 00 00 00 lea 0x0(%ebx),%eax
1ce66: 50 push %eax
1ce67: ff 77 10 pushl 0x10(%edi)
1ce6a: 6a 20 push $0x20
1ce6c: e8 fc ff ff ff call 1ce6d
<sqlite3VdbeMemStringify+0x6e>
1ce71: 83 c4 20 add $0x20,%esp
1ce74: 8b 47 10 mov 0x10(%edi),%eax
1ce77: e8 e3 a2 fe ff call 715f <sqlite3Strlen30>
1ce7c: 89 47 0c mov %eax,0xc(%edi)
1ce7f: c6 47 0a 01 movb $0x1,0xa(%edi)
1ce83: 8b 47 08 mov 0x8(%edi),%eax
1ce86: 80 7d dc 00 cmpb $0x0,-0x24(%ebp)
1ce8a: 74 03 je 1ce8f
<sqlite3VdbeMemStringify+0x90>
1ce8c: 83 e0 f3 and $0xfffffff3,%eax
1ce8f: 66 0d 02 02 or $0x202,%ax
1ce93: 66 89 47 08 mov %ax,0x8(%edi)
1ce97: 0f b6 55 e0 movzbl -0x20(%ebp),%edx
1ce9b: 89 f8 mov %edi,%eax
1ce9d: e8 eb ce ff ff call 19d8d <sqlite3VdbeChangeEncoding>
1cea2: 89 f0 mov %esi,%eax
+ 0xa3
1cea4: 8d 65 f4 lea -0xc(%ebp),%esp
1cea7: 5b pop %ebx
1cea8: 5e pop %esi
1cea9: 5f pop %edi
1ceaa: 5d pop %ebp
1ceab: c3 ret
The backtrace from the coredump analysis is:
(gdb) bt
#0 0xb7513e3d in sqlite3VdbeMemStringify (pMem=0xb6b1a900,
enc=<optimized out>, bForce=<optimized out>) at sqlite3.c:70739
#1 0xb7513f36 in valueToText (pVal=0xb6b1a900, enc=enc@entry=0x1) at
sqlite3.c:71501
#2 0xb751405e in sqlite3ValueText (pVal=pVal@entry=0xb6b1a900,
enc=enc@entry=0x1) at sqlite3.c:71534
#3 0xb7514074 in sqlite3_value_text (pVal=0xb6b1a900) at sqlite3.c:77123
#4 0xb75143dd in sqlite3_column_text (pStmt=0xb6b1a978, i=0x1) at
sqlite3.c:77989
#5 0xb754a6a0 in sqlite3_exec (db=0xb6b02f78, zSql=<optimized out>,
xCallback=0xb7558033 <sqlite3InitCallback>, pArg=0xb6c74c28,
pzErrMsg=0x0) at sqlite3.c:112209
#6 0xb754697d in sqlite3VdbeExec (p=p@entry=0xb6b23508) at sqlite3.c:84727
#7 0xb7549bd4 in sqlite3Step (p=0xb6b23508) at sqlite3.c:77535
#8 sqlite3_step (pStmt=0xb6b23508) at sqlite3.c:12062
#9 0xb754a606 in sqlite3_exec (db=0xb6b02f78, zSql=<optimized out>,
zSql@entry=0xb6b23200 "CREATE TABLE
InterfaceTable(gem_port_obj_index_list varchar ,obj_index unsigned int
,ont_and_slot unsigned smallint ,pbit_tc_mapping unsigned int ,port
unsigned tinyint ,sub_itf_obj_index_list varchar ,uni unsigned tinyint
,CONSTRAINT KEY_InterfaceTable PRIMARY KEY (obj_index))",
xCallback=xCallback@entry=0x0, pArg=pArg@entry=0x0,
pzErrMsg=pzErrMsg@entry=0xb6c74e6c) at sqlite3.c:112187
[...]
#17 0xb76275eb in start_thread (arg=0xb6c75b40) at pthread_create.c:463
#18 0xb6fb6e96 in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:108
Any help is much appreciated.
Best regards,
Thomas
More information about the Gcc-help
mailing list