Page 1 of 1

Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 07.04.2021, 12:34
by aehimself
Hello,

I just faced a deadlock when I was trying to connect to an Oracle database. It happened in TZOracleConnection.HandleErrorOrWarning, this cycle:

Code: Select all

          while true do begin
            NewStatus := FPlainDriver.OCIErrorGet(ErrorHandle, I, nil, ErrorCode,
              @FByteBuffer[0], SizeOf(TByteBuffer)-1, OCI_HTYPE_ERROR);
            if NewStatus = OCI_NO_DATA then
              Break;
            [...]
          end;
The only way to exit this loop is if OCIErrorGet returns OCI_NO_DATA but in my case it was continuously returning -1 (OCI_ERROR).
I'm not really familiar with what exactly is happening here, if simply adding a second value to the exit condition is fine or not... but the thing is, this cycle poses a high chance of deadlock.

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 07.04.2021, 13:14
by aehimself
Simply breaking out of the cycle is not going to help as the error message will be empty and no exception will be raised.
We can "hack" it around in the same cycle, a little bit further down:

Code: Select all

            L := StrLen(PAnsiChar(@fByteBuffer[0]));

            If L = 0 Then
            Begin
              WriterA.AddText(@AnsiString(Logmessage)[1], Length(Logmessage), {$IFNDEF UNICODE}ErrorMessage{$ELSE}ErrorMessageA{$ENDIF});
              Break;
            End;

            WriterA.AddText(@FByteBuffer[0], L, {$IFNDEF UNICODE}ErrorMessage{$ELSE}ErrorMessageA{$ENDIF});
This way a nice error message appears instead of the deadlock:

EZSQLException was raised with the message SQL Error: EnvNlsCreate failed.
Code: -1 Message: EnvNlsCreate failed.

I'm not going to create a pull request from this as though it works it feels dirty... maybe Michael knows a better solution? :)

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 07.04.2021, 13:33
by aehimself
I also managed to find out the reason: you can not open two oracle connections with different oci.dll-s, otherwise the second DLL type will fail...

I connected to an Oracle database where the driver library was set to the 12.1 version. After this I still could connect everywhere, as long as I used the same 12.1 version.
In the moment I attempted an other connection with the default, 19.x oci.dll things collapsed.

I'm not sure but I guess this is caused by the "driver caching" "feature" of Zeos, as the 12.1 connection can be freed already and the next 19.x will still fail.
I'd be really happy if this caching would be overridden... makes driver dll updates a pain :)

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 08.04.2021, 20:07
by aehimself
Well, damn it. Pull request created on GitHub. If Michael doesn't like it, he can roll it back anytime :)

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 08.04.2021, 21:24
by marsupilami
I merged it. Can you check if we have to do something similar on Zeos 7.2? My knowledge about the oracle driver isn't good enough to find this out in a reasonable time. :/

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 09.04.2021, 08:27
by aehimself
Jan,

There's no need. I checked out the 7.2-patches branch, HandleErrorOrWarning does not even exist there, only CheckOracleError in ZDbcOracleUtils. This method is handling error messages completely different, without using any cycles:

Code: Select all

    OCI_ERROR:
      begin
        if PlainDriver.ErrorGet(ErrorHandle, 1, nil, ErrorCode, @ErrorBuffer.Buf[0], SizeOf(ErrorBuffer.Buf)-1, OCI_HTYPE_ERROR) = 100
        then ErrorMessage := 'OCI_ERROR: Unkown(OCI_NO_DATA)'
        else begin
          ErrorMessage := 'OCI_ERROR: ';
          ErrorBuffer.Pos := StrLen(@ErrorBuffer.Buf[0])+1;
      end;
      end;
As far as I see an exception will be raised in any case so 7.2 is not affected by this issue.

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Posted: 09.04.2021, 08:51
by marsupilami
Ok, thank you. :)