Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

segfault on Linux / unixODBC when calling "use" statement, master only; 4.0.30 is fine #858

Closed
zzzeek opened this issue Jan 29, 2021 · 18 comments

Comments

@zzzeek
Copy link

zzzeek commented Jan 29, 2021

Environment

  • Python: Python 3.8.3 (default, May 23 2020, 16:34:37)
    [GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux

  • pyodbc: 4.0.31b51 from 7c7b1b1

  • ODBC headers / devel libs (Fedora 33):

    unixODBC-2.3.9-1.fc33.x86_64
    unixODBC-devel-2.3.9-1.fc33.x86_64

  • OS:
    uname -a
    Linux photon3 5.10.8-200.fc33.x86_64 unicode parameters on pyodbc -> unixodbc -> freetds #1 SMP Sun Jan 17 19:53:01 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

  • DB:

    Centos packages:

    mssql-server-14.0.3356.20-23.x86_64
    mssql-tools-17.6.1.1-1.x86_64
    mssql-server-fts-14.0.3356.20-23.x86_64

  • driver: msodbcsql 13.1.9.2

Issue

SQLAlchemy's test suite needs to use the "use" statement during a setup process in order to create a schema in a certain database. Building with latest master produces a segfault with the program below. I can do a source build against the 4.0.30 tag and that one is fine.

import pyodbc
print("Using pyodbc version: %s" % pyodbc.version)

conn = pyodbc.connect(
    "DRIVER={ODBC Driver 13 for SQL Server};Server=mssql2017,1433;Database=test;UID=scott;PWD=tiger^5HHH"
)
cursor = conn.cursor()

cursor.execute("select db_name()")
db_name = cursor.fetchone()[0]

cursor.execute("use %s" % db_name)
cursor.close()
conn.close()

print("OK!")

output:

Using pyodbc version: 4.0.31b51
Segmentation fault (core dumped)

@v-chojas
Copy link
Contributor

Please provide an ODBC trace. That will better show exactly where it faults.

Also note that latest version of msodbcsql is 17.7 , which has fixed several bugs since 13.x.

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

right, forgot about those.

When the trace is turned on, the output includes an additional message:

Using pyodbc version: 4.0.31b51
*** buffer overflow detected ***: terminated
Aborted (core dumped)

file is attached, seems like it just generally has more logging turned on.

odbctrace.txt

@keitherskine
Copy link
Collaborator

I ran a quick test on Travis, but I was unable to reproduce the segfault. Calling self.cursor.execute("use test") there (on Ubuntu 18.04) worked fine for me. The only difference I can think of (apart from RedHat vs Ubuntu) is I'm using {ODBC Driver 17 for SQL Server} rather than {ODBC Driver 13 for SQL Server}.

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

crashes w/ 17 me also. tracefile attached

odbctrace.txt

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

here's the good tracefile with 4.0.30, it seems quite different

non_crashing_trace_w_4.0.30.txt

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

diffing the two files it looks like the error one is calling into SQLGetDiagRecW, which I'd assume it does when it wants to get an error code, then the "DIAG" message says, "DIAG [01000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Changed database context to 'test'.", then that's the end of transmission. the "good" one doesn't call this and goes into SQLRowCount etc. and does normal cursor close / transaction end stuff.

-[ODBC][1911305][1611978199.268275][SQLExecDirectW.c][456]
+[ODBC][1910737][1611978093.975701][SQLExecDirectW.c][456]
 		Exit:[SQL_SUCCESS_WITH_INFO]
-[ODBC][1911305][1611978199.268319][SQLGetDiagRecW.c][535]
+[ODBC][1910737][1611978093.975791][SQLRowCount.c][173]
 		Entry:
-			Statement = 0x1656d80
-			Rec Number = 1
-			SQLState = 0x7fff9eb831f4
-			Native = 0x7fff9eb831e8
-			Message Text = 0x7fff9eb83200
-			Buffer Length = 10239
-			Text Len Ptr = 0x7fff9eb831e6
-		DIAG [01000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Changed database context to 'test'.
-
+			Statement = 0x17fa530
+			Row Count = 0x7fff99f48140

left side ends here, right side continues on with normal transaction close things

@gordthompson
Copy link
Collaborator

gordthompson commented Jan 30, 2021

I am able to reproduce this issue on Oracle Linux Server 8.3.

[gord@localhost ~]$ python3 zzzeek.py 
Using pyodbc version: 4.0.30
OK!
[gord@localhost ~]$ pip3 install --user git+https://github.com/mkleehammer/pyodbc
Collecting git+https://github.com/mkleehammer/pyodbc
  Cloning https://github.com/mkleehammer/pyodbc to /tmp/pip-uvqznmpu-build
Installing collected packages: pyodbc
  Found existing installation: pyodbc 4.0.30
    Uninstalling pyodbc-4.0.30:
      Successfully uninstalled pyodbc-4.0.30
  Running setup.py install for pyodbc ... done
Successfully installed pyodbc-4.0.31b51
[gord@localhost ~]$ python3 zzzeek.py 
Using pyodbc version: 4.0.31b51
Segmentation fault (core dumped)

When it fails, the tail end of the ODBC trace is:

[ODBC][7393][1612034957.234900][SQLExecDirectW.c][177]
        Entry:
            Statement = 0x564c82cf3b00
            SQL = [use test][length = 8]
[ODBC][7393][1612034957.238365][SQLExecDirectW.c][456]
        Exit:[SQL_SUCCESS_WITH_INFO]
[ODBC][7393][1612034957.238437][SQLGetDiagRecW.c][535]
        Entry:
            Statement = 0x564c82cf3b00
            Rec Number = 1
            SQLState = 0x7ffd37cd28b4
            Native = 0x7ffd37cd28b0
            Message Text = 0x7ffd37cd28c0
            Buffer Length = 10239
            Text Len Ptr = 0x7ffd37cd28ae
        DIAG [01000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Changed database context to 'test'.

[ODBC][7393][1612034957.238479][SQLGetDiagRecW.c][596]
        Exit:[SQL_SUCCESS]
            SQLState = [01000]
            Native = 0x7ffd37cd28b0 -> 5701
            Message Text = [[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Changed database context to 'test'.]
[ODBC][7393][1612034957.238541][SQLGetDiagRecW.c][535]
        Entry:
            Statement = 0x564c82cf3b00
            Rec Number = 2
            SQLState = 0x7ffd37cd28b4
            Native = 0x7ffd37cd28b0
            Message Text = 0x7ffd37cd28c0
            Buffer Length = 10239
            Text Len Ptr = 0x7ffd37cd28ae
[ODBC][7393][1612034957.238551][SQLGetDiagRecW.c][596]
        Exit:[SQL_NO_DATA]

@keitherskine
Copy link
Collaborator

I too am able to reproduce this segmentation fault on CentOS 8.3. As part of the new "messages" attribute functionality I introduced recently, there are more calls to SQLGetDiagRecW after each SQL execution. Although this appears to work on Windows and Ubuntu, it clearly does not work on other Linux distributions. I'm going to see if I can figure out why this is happening (although to be honest I'm no C++ guru). If I can't find a fix, and nobody else can, then I think I'm going to have to disable this "messages" functionality on all Unix platforms. Sorry about this @zzzeek , bear with me.

FYI, it looks like Kleehammer might have had issues in the past with SQLGetDiagRecW on Fedora. Here's a comment in the code about it:
https://github.com/mkleehammer/pyodbc/blob/master/src/errors.cpp#L238-L239

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

@keitherskine we're great! I run DBAPI git masters/main on my Jenkins server so we can catch these things before the DBAPIs are released. No rush here as long as you don't release with the bug :)

@zzzeek
Copy link
Author

zzzeek commented Jan 30, 2021

Well Fedora 8 is eons ago, but if we want to call this a bug in Fedora itself I can raise this within Red Hat (where I happen to work!) if we want to raise this with the unixODBC package and we can get a good self-contained reproducer I can shop it around internally.

@keitherskine
Copy link
Collaborator

keitherskine commented Jan 31, 2021

A fix should be on the way, @zzzeek . PR 859 has been raised. The issue was nothing to do with Fedora in the end, it was just my code. Nevertheless, many thanks indeed for checking this build and raising the issue.

@gordthompson
Copy link
Collaborator

#859 works for me on Oracle Linux Server 8.3:

[gord@localhost ~]$ pip3 install --user git+https://github.com/keitherskine/pyodbc@issue-858-fix-segfault
Collecting git+https://github.com/keitherskine/pyodbc@issue-858-fix-segfault
  Cloning https://github.com/keitherskine/pyodbc (to issue-858-fix-segfault) to /tmp/pip-215bq8_o-build
Installing collected packages: pyodbc
  Found existing installation: pyodbc 3.0.8b181
    Uninstalling pyodbc-3.0.8b181:
      Successfully uninstalled pyodbc-3.0.8b181
  Running setup.py install for pyodbc ... done
Successfully installed pyodbc-3.0.8b242+commit38747ac
[gord@localhost ~]$ python3 zzzeek.py 
Using pyodbc version: 3.0.8b242+commit38747ac
OK!

☺️

@keitherskine
Copy link
Collaborator

Many thanks for testing this on Oracle Linux, Gord!

@zzzeek
Copy link
Author

zzzeek commented Feb 19, 2021

bump ?

@v-chojas
Copy link
Contributor

You can try the fix here: #859

@zzzeek
Copy link
Author

zzzeek commented Feb 19, 2021

I'm fine with the fix I just am waiting for it to be merged to master. our CI runs against DBAPI git masters.

@keitherskine
Copy link
Collaborator

FYI @zzzeek , the fix for this issue has been merged to master. Feel free to run your CI against the latest pyodbc.

@gordthompson
Copy link
Collaborator

Fixed in #859

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants