如何修复psqlodbc驱动程序中的缓冲区溢出

时间:2015-09-18 11:13:42

标签: visual-studio postgresql visual-foxpro buffer-overrun psqlodbc

Visual FoxPro应用程序调用Postgres psqlodbc驱动程序9.3.0400 两者都是在Windows 7 x64中运行的32位应用程序

此调用导致psqlodbc35w.dll中的Buffer Ovverrun异常,其下面是堆栈跟踪。 如何解决这个问题? psqlodbc是用C语言编写的开源应用程序,可能是由Visual Studio编译的。也许有可能在某些情况下对其进行处理,以便不会发生exceptino? 已安装Visual Studio 2015 Community Edition。

崩溃后,将调用Visual Studio 2015 Community Edition调试程序。 它显示了堆栈跟踪:

>    psqlodbc35w.dll!__crt_debugger_hook()     Unknown
     psqlodbc35w.dll!__report_gsfailure()  Line 315 + 0x7 bytes    C
     psqlodbc35w.dll!SC_create_errorinfo(const StatementClass_ * self)  Line 1423 + 0xa bytes    C
     psqlodbc35w.dll!PGAPI_StmtError(void * hstmt, short RecNumber, unsigned char * szSqlState, long * pfNativeError, unsigned char * szErrorMsg, short cbErrorMsgMax, short * pcbErrorMsg, unsigned short flag)  Line 1612    C
     psqlodbc35w.dll!PGAPI_GetDiagField(short HandleType, void * Handle, short RecNumber, short DiagIdentifier, void * DiagInfoPtr, short BufferLength, short * StringLengthPtr)  Line 280    C
     psqlodbc35w.dll!SQLGetDiagFieldW(short fHandleType, void * handle, short iRecord, short fDiagField, void * rgbDiagInfo, short cbDiagInfoMax, short * pcbDiagInfo)  Line 374 + 0x16 bytes    C
     odbc32(dot)dll!_VFreeErrors(at)4()  + 0x401f bytes    
     odbc32(dot)dll!_SearchStatusCode(at)8()  + 0x25 bytes    
     odbc32(dot)dll!_IsStmtPositioned(at)4()  + 0x14 bytes    
     odbc32(dot)dll!_SQLExecute(at)4()  - 0xfd3e bytes    
     odbc32(dot)dll!_SQLExecDirect(at)12()  + 0x77 bytes    
     vfp9r.dll!0c3904c6()     
...

调试窗口显示大量已加载模块且结尾处:

...
The thread 'Win32 Thread' (0x2778) has exited with code 0 (0x0).
A buffer overrun has occurred in alguss.EXE which has corrupted the program's internal state. Press Break to debug the program or Continue to terminate the program.
For more details please see Help topic 'How to debug Buffer Overrun Issues'.

也在http://www.postgresql.org/message-id/1B88854920C942948F943E26B452E3A4@dell2

中发布

更新

这是导致崩溃的FoxPro代码。 在将查询发送到Postgres之前,odbc驱动程序中发生崩溃。 查询中的表不需要存在于数据库中。只需使用postgres odbc官方驱动程序运行查询。也许在查询中使用$字符会导致odbc崩溃。

SET TEXTMERGE ON
SET TEXTMERGE TO (sys(2015))
TEXT TEXTMERGE NOSHOW

CREATE or replace FUNCTION public.f_infA()
  RETURNS TABLE (
kuupaev date,
nimi text, 
tasudok text,

regnr text, 
kmprotsent text, 
neto numeric, 
myyk numeric, 
erisus01 bool, 
erisus02 bool, 
erisus03 bool
) AS $f_InfA$

WITH 
myyk as (

SELECT 
  dok.kuupaev, 
  dok.tasudok, 
  klient.regnr,
  CASE when klient.regnr is null OR klient.regnr='' then klient.nimi else '' end::char(80) as nimi,
  20 as kmprotsent, 
  k01+k011+k01erik as myyk20, 
  0 as myyk9, 

  MAX(klient.nimi)::char(80) as maxnimi,
  bool_or(k01erik<>0) as erisus01,
  bool_or(d09<>0) as erisus02, 

  SUM(  ROUND( rid.hind * case when rid.kogus<>0 then rid.kogus else 1 end*
    CASE when rid.kogpak<>0 then rid.kogpak else 1 end 
    /case when dok.doktyyp<>'Y' then 1 else 1+myygikoo.kmprotsent/100 end *  
    CASE when dok.raha=prpalk.pohiraha then 1 
       when dok.exchrate<>0 then dok.Exchrate else kurss.kurss end,2) 
     ) as neto 

FROM prpalk, tehing 
JOIN dok ON tehing.dokumnr=dok.dokumnr
JOIN rid ON dok.dokumnr=rid.dokumnr
JOIN klient ON dok.klient=klient.kood 
LEFT JOIN myygikoo ON rid.myygikood=myygikoo.myygikood or ( rid.myygikood is null and myygikoo.myygikood ='' )
LEFT JOIN kurss ON dok.raha=kurss.raha AND dok.kuupaev=kurss.kuupaev 
LEFT JOIN toode ON rid.toode=toode.toode 
WHERE (rid.toode is null or toode.grupp<>'S' OR rid.toode='LE' or (toode.klass like '%T%' AND toode.klass not like '%E%'
     AND toode.klass not like '%M%')) and
   tehing.alusdok='LG' AND ( (k01+k011+k01erik)<>0  )
AND klient.nimi not ilike '%AUDIITORBÜROO%'
AND klient.nimi not ilike '%ADVOKAADIBÜROO%'
AND klient.nimi not ilike 'Notar %'
AND klient.nimi not ilike '% Notar'
AND rid.hind <> 0     -- Et ei tekiks arvetel taara 0 hinnaga väljastamisel erisuse koodi 03
AND klient.nimi not ilike 'Eraisik'
AND klient.nimi not ilike 'Jaeostja'
and not klient.kmdkeeld

GROUP BY 1,2,3,4,5,6,7
union all
SELECT 
  dok.kuupaev, 
  dok.tasudok, 
  klient.regnr,
  CASE when klient.regnr is null OR klient.regnr='' then klient.nimi else '' end::char(80) as nimi,
  9, 
  0 as myyk20, 
  k02+k021 as myyk9, 

  MAX(klient.nimi)::char(80) as maxnimi,
  bool_or(k01erik<>0) as erisus01,
  bool_or(d09<>0) as erisus02, 

  SUM(  ROUND( rid.hind * case when rid.kogus<>0 then rid.kogus else 1 end*
    CASE when rid.kogpak<>0 then rid.kogpak else 1 end 
    /case when dok.doktyyp<>'Y' then 1 else 1+myygikoo.kmprotsent/100 end *  
    CASE when dok.raha=prpalk.pohiraha then 1 
       when dok.exchrate<>0 then dok.Exchrate else kurss.kurss end,2) 
     ) as neto 

FROM prpalk, tehing 
JOIN dok ON tehing.dokumnr=dok.dokumnr
JOIN rid ON dok.dokumnr=rid.dokumnr
JOIN klient ON dok.klient=klient.kood 
LEFT JOIN myygikoo ON rid.myygikood=myygikoo.myygikood or ( rid.myygikood is null and myygikoo.myygikood ='' )
LEFT JOIN kurss ON dok.raha=kurss.raha AND dok.kuupaev=kurss.kuupaev 
LEFT JOIN toode ON rid.toode=toode.toode 
WHERE (rid.toode is null or toode.grupp<>'S' OR rid.toode='LE' or (toode.klass like '%T%' AND toode.klass not like '%E%'
     AND toode.klass not like '%M%')) and
   tehing.alusdok='LG' AND (k02+k021)<>0
AND klient.nimi not ilike '%AUDIITORBÜROO%'
AND klient.nimi not ilike '%ADVOKAADIBÜROO%'
AND klient.nimi not ilike 'Notar %'
AND klient.nimi not ilike '% Notar'
AND rid.hind <> 0     -- Et ei tekiks arvetel taara 0 hinnaga väljastamisel erisuse koodi 03
AND klient.nimi not ilike 'Eraisik'
AND klient.nimi not ilike 'Jaeostja'
and not klient.kmdkeeld
GROUP BY 1,2,3,4,5,6,7
union all
SELECT 
  omrid.adkuupaev, 
  omrid.ettemarve, 
  klient.regnr, 
  CASE when klient.regnr is null OR klient.regnr='' then klient.nimi else '' end::char(80) as nimi,

  CASE when  sum(k01+k011+k01erik)<>0 then 20 else 9 end, 

  CASE when  sum(k01+k01erik+k011)<>0 then 

  sum( ROUND( 
   case when omrid.hinnalis='LM' then -omrid.tasusumma else omrid.tasusumma end *
     case when omrid.kogus<>0 then omrid.kogus else 1 end * 
     case when omrid.raha=prpalk.pohiraha then 1 else
      case when omrid.exchrate<>0 then omrid.Exchrate else kurss.kurss end END,2))

  else 0 end as myyk20, 


  CASE when  sum(k02+k021)<>0 then 

sum(  ROUND( 
   case when omrid.hinnalis='LM' then -omrid.tasusumma else omrid.tasusumma end *
     case when omrid.kogus<>0 then omrid.kogus else 1 end * 
     case when omrid.raha=prpalk.pohiraha then 1 else
      case when omrid.exchrate<>0 then omrid.Exchrate else kurss.kurss end END,2))

  else 0 end as myyk9, 

  MAX(klient.nimi)::char(80) as maxnimi,
  bool_or(k01erik<>0) as erisus01,
  bool_or(d09<>0) as erisus02, 

  SUM( ROUND( 
   case when omrid.hinnalis='LM' then -omrid.tasusumma else omrid.tasusumma end *
     case when omrid.kogus<>0 then omrid.kogus else 1 end * 
     case when omrid.raha=prpalk.pohiraha then 1 else
      case when omrid.exchrate<>0 then omrid.Exchrate else kurss.kurss end END,2)) as neto 
FROM prpalk, tehing 
join omdok on tehing.dokumnr=omdok.dokumnr
JOIN omrid ON omrid.dokumnr=tehing.dokumnr -- AND tehing.doknr=omrid.ettemarve 
JOIN klient ON omdok.klient=klient.kood 
LEFT JOIN kurss ON omrid.raha=kurss.raha AND omrid.adkuupaev=kurss.kuupaev 

WHERE tehing.alusdok in ('DT', 'DI')  AND  ( (k01+k01erik+ k011)>0 )
    and omrid.ettemarve is not null and omrid.ettemarve is distinct from ''
    AND klient.nimi not ilike '%AUDIITORBÜROO%'
    AND klient.nimi not ilike '%ADVOKAADIBÜROO%'
    AND klient.nimi not ilike 'Notar %'
    AND klient.nimi not ilike '% Notar'
    and not klient.kmdkeeld
GROUP BY 1,2,3,4

),

myyk1000 as (
SELECT 
  regnr, 
  nimi
FROM myyk 
WHERE neto>0 
GROUP BY 1,2 
HAVING SUM(neto)>1000
)

SELECT 
  myyk.kuupaev,
  myyk.maxnimi as nimi, 
  myyk.tasudok,

  myyk.regnr, 
  '20' as kmprotsent, 
  round( SUM(myyk.neto),2)  as neto, 
  round( SUM(myyk.myyk20),2) as myyk, 
  bool_or(erisus01) as erisus01, 
  bool_or(erisus02) as erisus02, 
  bool_or(myyk.kmprotsent=0) as erisus03 

FROM myyk1000 
JOIN myyk ON myyk1000.regnr=myyk.regnr AND myyk1000.nimi=myyk.nimi 
GROUP BY 1,2,3,4 
HAVING SUM(myyk.myyk20)<>0 

UNION ALL 

SELECT 
  myyk.kuupaev,
  myyk.maxnimi as nimi, 
  myyk.tasudok,
  myyk.regnr, 
  '9', 
  round( SUM(myyk.neto),2) , 
  round( SUM(myyk.myyk9),2), 
  false, 
  bool_or(erisus02) as erisus02, 
  bool_or(myyk.kmprotsent=0) as erisus03 

FROM myyk1000 
JOIN myyk ON myyk1000.regnr=myyk.regnr AND myyk1000.nimi=myyk.nimi 
GROUP BY 1,2,3,4 
HAVING SUM(myyk.myyk9)<>0  

UNION ALL 

SELECT 
  myyk.kuupaev,
  myyk.maxnimi as nimi, 
  myyk.tasudok,

  myyk.regnr, 
  'erisus20', 
  round( SUM(myyk.neto),2) , 
  round( SUM(myyk.myyk9),2), 
  false, 
  bool_or(erisus02) as erisus02, 
  false as erisus03 

FROM myyk1000 
JOIN myyk ON myyk1000.regnr=myyk.regnr AND myyk1000.nimi=myyk.nimi 
GROUP BY 1,2,3,4 
HAVING bool_or(erisus02)
ORDER BY nimi, kuupaev, tasudok

$f_infa$ LANGUAGE sql STABLE;

RESET ROLE;

ENDTEXT

cSqlFail = SET('textmerge',2)
SET TEXTMERGE TO 
SQLEXEC(m.g_server.nConnhandle, FILETOSTR(m.cSqlFail) )

使用的连接字符串:

cConnString = "DRIVER={PostgreSQL Unicode};"+ ;
     "DATABASE=test";"+ ;
     "SERVER=localhost;" + ;
     "PORT=5432;" + ;
     "UID=user;" + ;
     "Protocol=-0;" + ;
     "B9=0"+ ;
     ";SSLMODE=allow"

1 个答案:

答案 0 :(得分:3)

(我在这里写作,因为我可以在评论中对其进行格式化,结果却很混乱)

是的,您的代码会导致崩溃。看起来它是驱动程序中的一个错误,我希望它会返回错误但不会导致VFP停止执行。

您的代码既不是从pgsl也不是SQL控制台运行。我得到的错误是:

227: ERROR:  unterminated dollar-quoted string at or near "$f_InfA$

它也指出:

"ESET ROLE;
LINE 14: ) AS $f_InfA$

如果您的美元引用字符串未终止,那么您的报价中已经出现错误。如果它不是你在这里给出的代码中的拼写错误,那么你有:

... bool
) AS $f_InfA$

...

$f_infa$ LANGUAGE sql STABLE;

RESET ROLE;
你的代码中的

。由于美元引用的字符串与XML一样区分大小写,因此它未被终止。第二个应该是&#34; $ f_InfA $&#34;太。

只需使用$$或$ f_InfA $,它应该有效。

但是,驱动程序不应该导致崩溃。 HTH