Skip to Main Content

DevOps, CI/CD and Automation

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

ODBC Instant Client install writes registry values with extraneous bytes on Windows

user3199775Aug 26 2016 — edited Aug 26 2016

There are 2 ways to add registry string values. One with a null terminated string, and the other with a buffer and length.

The Oracle Instant Client ODBC "odbc_install.exe" must be using the second method, and providing the full length of the buffer.

I know this because I am reading the ODBC registry using the C# language which doesn't use null terminators for its strings, and when I get the "Driver" value for the "Oracle in instantclient_11_2" ODBC driver and then attempt to use the path, I get an exception stating the path contains illegal values.

The value looked fine in RegEdit, but when I viewed it in Visual Studio it was ~512 characters long, and viewing it showed it full of lots of escaped control characters.

I wrote the little windows console app below in C# to dump all the "BAD" string values in the ODBC registry.

It finds the problem on another system with the newest 12_1 Instant Client as well.

Note, it finds nothing wrong on a system with the full Oracle Client installed with the Universal Installer.

Console App Source Code:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;

namespace CheckODBCRegistry
{
class Program
{
  static void Main( string[] args )
  {
   Console.WriteLine( "Check ODBC Registry for invalid values" );

   var odbcBases = new List<string>();
   odbcBases.Add( @"Software\ODBC\ODBCINST.INI\" );
   if( Environment.Is64BitOperatingSystem )    // Check ODBC registry for both bitness's on x64 OS
    odbcBases.Add( @"Software\Wow6432Node\ODBC\ODBCINST.INI\" );
   foreach( var odbcBase in odbcBases )
   {
    // Get the ODBC Driver names
    string[] odbcDrivers = null;
    using( var drivers = Registry.LocalMachine.OpenSubKey( odbcBase + "ODBC Drivers" ) )
     odbcDrivers = drivers.GetValueNames();
    if( odbcDrivers != null )
    {
     foreach( var odbcDriver in odbcDrivers )
     {
      if( string.IsNullOrWhiteSpace( odbcDriver ) )
       Console.WriteLine( "\tInvalid 'empty' ODBC Driver name" );
      else
      {
       try
       {
        using( var odbcDriverKey = Registry.LocalMachine.OpenSubKey( odbcBase + odbcDriver ) )
        {
         try
         {
          var valueNames = odbcDriverKey.GetValueNames();
          if( valueNames == null || valueNames.Length < 1 )
           Console.WriteLine( $"\tDriver '{odbcDriver}' has no registry values" );
          else
          {
           bool firstBadValueForDriver = true;
           ValidateString( odbcDriver, "Name", odbcDriver, ref firstBadValueForDriver );
           foreach( var valueName in valueNames )
           {
            var kind = odbcDriverKey.GetValueKind( valueName );
            if( kind != RegistryValueKind.String && kind != RegistryValueKind.ExpandString )
             continue;
            var value = odbcDriverKey.GetValue( valueName ).ToString();
            ValidateString( odbcDriver, valueName, value, ref firstBadValueForDriver );
           }
          }
         }
         catch( Exception ex )
         {
          Console.WriteLine( $"\tDriver '{odbcDriver}' access caused exception '{ex.Message}'" );
         }
        }
       }
       catch( System.Security.SecurityException ex )
       {
        Console.WriteLine( $"\tDriver '{odbcDriver}' has an ACL blocking the current user from reading it" );
       }
      }
     }
    }
   }

   Console.WriteLine();
   Console.WriteLine( "Press any key to exit" );
   Console.ReadKey();
  }

  private static bool BadString( string text )
  { return ( text != null && text.IndexOf( '\0' ) >= 0 ); }

  private static string ClipString( string text )
  {
   var nullPos = text.IndexOf( '\0' );
   if( nullPos == 0 )
    return ( string.Empty );
   if( nullPos > 0 )
    return ( text.Substring( 0, nullPos ) );
   return ( text );
  }

  private static string EscapeString( string text )
  {
   var sb = new StringBuilder();
   foreach( char c in text )
   {
    if( Char.IsControl( c ) )
    {
     sb.Append( @"\x" );
     sb.Append( ( (int)c ).ToString( "x" ) );
    }
    else
     sb.Append( c );
   }
   return ( sb.ToString() );
  }

  private static void ValidateString( string odbcDriver, string name,
   string value, ref bool firstBadValueForDriver )
  {
   if( BadString( value ) )
   {
    if( firstBadValueForDriver )
    {
     Console.Write( "\tDriver '" );
     Console.Write( ClipString( odbcDriver ) );
     Console.WriteLine( "'" );
     firstBadValueForDriver = false;
    }
    Console.Write( $"\t\tHas a BAD {name}: " );
    Console.WriteLine( EscapeString( value ) );
   }
  }
}
}

Output from my system:

Check ODBC Registry for invalid values
        Driver 'Oracle in instantclient_11_2'
                Has a BAD APILevel: 1\x0\x0\x0\x0\x0\x0\x0\x9-
                Has a BAD ConnectionFunctions: YYY\x0¢\x0£\x0 \x0¥\x0▌\x0 \x0"\x0c\x0ª\x0«\x0¬\x0-\x0r\x0_\x0°\x0±\x0²\x03\x0'\x0µ\x0 \x0·\x0,\x01\x0º\x0»\x0¼\x0½\x0_\x0¿\x0A\x0A\x0A\x0A\x0Ä\x0Å\x0Æ\x0Ç\x0E\x0É\x0E\x0E\x0I\x0I\x0I\x0I\x0D\x0Ñ\x0O\x0O\x0O\x0O\x0Ö\x0x\x0O\x0U\x0U\x0U\x0Ü\x0Y\x0_\x0ß\x0A\x0A\x0A\x0A\x0Ä\x0Å\x0Æ\x0Ç\x0E\x0É\x0E\x0E\x0I\x0I\x0I\x0I\x0D\x0Ñ\x0O\x0O\x0O\x0O\x0Ö\x0÷\x0O\x0U\x0U\x0U\x0Ü\x0Y\x0_\x0x\x1II\x0\x0\x0\x0\x0\x0\x0\x0A\x0\x0\x0\x0\x0 \x0\x1\x0\x2\x0\x3\x0\x4\x0\x5\x0\x6\x0\x7\x0\x8\x0\x9\x0\xa\x0\xb\x0\xc\x0\xd\x0\xe\x0\xf\x0\x10\x0\x11\x0\x12\x0\x13\x0\x14\x0\x15\x0\x16\x0\x17
                Has a BAD CPTimeout: 60\x0\x0,O\x0@\x1
                Has a BAD Driver: C:\Oracle\SQORA32.dll\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x8\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x3\x0\x0\x0\x0\x0\x0\x0_\r_y\x7f\x0\x0\x0\x0E\x0\x0\x0\x0\x0\x2\x0(\x0\x0\x0\x0\x0 \x0\x0\x0\x0\x0\x0\x00\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0ÅKq_y\x7f\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0è[\x3\x0\x0\x0\x0\x0pä\x14\x0\x0\x0\x0\x0îôZ»pD\x0\x0\x12\x0\x0\x0\x0\x0\x0\x0PHE\x0\x0\x0\x0\x0@rE\x0\x0\x0\x0\x0PFE\x0\x0\x0\x0\x0(é\x14\x0\x0\x0\x0\x0\x17\x0\x0\x0\x0\x0\x0\x0\xfKq_y\x7f\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0d-E\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x00GE\x0\x0\x0\x0\x0 qE\x0\x0\x0\x0\x0\x90ö\x14\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0_\x0\x2\x0\x0\x1\x1\x1\x0\x0\x0\x0\x0\x0\x2E\x0\x0\x0\x0\x0F\x0\x0\x0y\x7f\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0Ä_5\x20æ\x14\x0\x0\x0\x0\x01\x0ÿÿ\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0@rE\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x16\x0\x0\x0\x0\x0\x0\x0PFE\x0\x0\x0\x0\x0\x1c\x0\x1c\x0\x0\x0\x0\x0OaTYë6\x0\x0*\x0\x0\x0\x0\x0\x0\x0Pê\x14\x0\x0\x0\x0\x0\x15-+\y\x7f\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0Aä\x14\x0\x0\x0\x0\x0DÉ+\y\x7f\x0\x0\x14\x2\x0\x0\x0\x0\x0\x0^ä\x14\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0Pê\x14\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0
                Has a BAD DriverODBCVer: 03.51\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1dq_y\x7f\x0\x0 \x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x0!"#$%&'\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0234567O\x2\x0\x0\x0\x0\x0\x00_E\x0\x0\x0\x0\x0\x1\x0\x0\x0LMN\x1PQRSTUVW\x90\x12\x0\x0\x0\x0\x0\x0`abcde\x1g\x0\x0\x0\x0lmno _E\x0\x0\x0\x0\x0s\x2\x0\x0|}~\x7f _E\x0\x0\x0\x0\x0\x1\x0\x0\x0O\x8dZ\x8f?\x4\x0\x0\x0\x0\x0\x0H\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0 ¥▌ O\x2\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0?\x0\x0\x0\x0\x0\x0\x0ÿ\x3\x0\x0\x0\x0\x0\x0\x0\x0A\x0\x0\x0\x0\x0\x0\x0A\x0\x0\x0\x0\x0T\x0\x0T\x0\x0\x0
                Has a BAD Setup: C:\Oracle\SQORAS32.DLL\x0\x0\x2\x0,\x0\x0\x0\x0\x0p\x4\x0\x0\x0\x0\x0\x0?\x4\x0\x0\x0\x0\x0\x0H\x5E\x0\x0\x0\x0\x0@ü\x14\x0\x0\x0\x0\x0\x0\x0\x0@\x1\x0\x0\x0?\x0\x0\x0\x0\x0\x0\x1\x0`\x1\x0\x0\x0\x0\x0 Éu_y\x7f\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x2\x0\x0\x0\x0\x0\x0\x0\x2\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x6\x0\x0\x0\x0\x0\x0\x0z\x0\x0\x0\x0.gí:r%\y\x7f\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0-3v=\x0\x0\x0\x0\x8d\x0\x0\x8d\x1\x3\x1\x3ú\x2\x0\x0\x0\xeEí\x0\x0\x0@\x1\x0\x0\x0\x0`\x1\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0^\x0`\x0\x0\x0\x0\x0^ü\x14\x0\x0\x0\x0\x0\\x0D\x0e\x0v\x0i\x0c\x0e\x0\\x0H\x0a\x0r\x0d
                Has a BAD SQLLevel: 1\x0\x0\x0\x0\x0\x0\x0,O

Press any key to exit

Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Sep 23 2016
Added on Aug 26 2016
0 comments
609 views