RE: "DECODE_BUF_NOFAIL" failure
"Colestock, Robert" <[email protected]> Fri, 15 Sep 2000 15:54:32 -0400
| Newsgroups | gmane.ietf.sfl |
|---|---|
| Message-ID | <[email protected]> |
John:
For some reason I tested the ENCODE_BUF(...), but I just re-tested the
DECODE_BUF(...). It works fine with the following code. It sounds like you
have an older include file with the reference to the original calloc buffer
pointer, instead of the current AsnBuf pointer
("free(outputBuf.BlkPtr()/*pchBuffer*/);\", since it may be modified by the
buffer load routine).
I have included our present "sm_vdasnacc.h" include file for reference.
void test_big_buffer()
{
char pchBuffer[200000];
CSM_Buffer *pM=new CSM_Buffer;
AsnOcts N;
SME_SETUP("test_big_buffer()");
memset(pchBuffer, 'A', 200000);
N.Set(pchBuffer, 200000);
ENCODE_BUF(&N, pM);
cout << "test_big_buffer: Octet STring encoded length of 200000 byte
buf=" << pM->Length();
DECODE_BUF(&N, pM);
SME_FINISH
SME_CATCH_SETUP
// local cleanup logic
SME_CATCH_FINISH
}
Bob Colestock
VDA
-----Original Message-----
From: Nord, John D Contractor/NCCIM [mailto:[email protected]]
Sent: Friday, September 15, 2000 2:15 PM
To: 'Colestock, Robert'
Cc: '[email protected]'
Subject: RE: "DECODE_BUF_NOFAIL" failure
Bob,
I checked my project configurations, and the debug multithreaded
library
is set correctly on all the projects. I did some more investigation, and I
guess I made too early an assumption without debugging far enough into the
code.
I did assume there was a memory overrun error.
I determined that the bomb I am getting is that a pointer is being
freed
that has already been freed elsewhere. In the code for the
DECODE_BUF_NOFAIL
macro below, the last line is "free(pchBuffer);". In the case that the
macro is
called with a buffer larger than 100K, the AsnBuf internal buffer is
reallocated
(with calloc) as you said to a larger size, and the buffer that was passed
in
initially to the AsnBuff::Init function (in the "outputBuf.Init(pchBuffer,
(blob)->Length());" line of the macro) gets freed (in the AsnBuf::AddBuffer
function)--this pointer is the same pointer that the macro tries to free
again
in the last line.
John
-----Original Message-----
From: Colestock, Robert [mailto:[email protected]]
Sent: Friday, September 15, 2000 8:30 AM
To: 'Nord, John D Contractor/NCCIM'; '[email protected]'
Subject: RE: "DECODE_BUF_NOFAIL" failure
John:
I investigated this error; the SNACC library handles bigger buffers, but my
test program failed in a similar manner due to a mis-alignment of the DLL
libraries. Once I fixed this, the test of 200k buffer Octet String encoding
worked fine. I authored this newer logic to handle larger buffers, the
SNACC encode operations were updated to re-alloc the memory from the macro
(I need to add some comments to the "sm_vdasnacc.h" include file around
these macros indicating that the 100k buffer is not the actual limit).
Soon, I will be updating the logic again to improve performance (hopefully
to use the actual application memory, avoiding the copy operations).
For your immediate problem, I suggest that you check that the application
and SNACC library builds both use the Project Settings, C/C++ Tab, Category:
Code Generation, Use run-time library: Multithreaded DLL (OR Debug
Multithreaded DLL). Sorry, but this is a part of the Microsoft world, the
actual error is not always obvious.
Bob Colestock
VDA
-----Original Message-----
From: Nord, John D Contractor/NCCIM [mailto:[email protected]]
Sent: Tuesday, September 12, 2000 4:03 PM
To: '[email protected]'
Subject: "DECODE_BUF_NOFAIL" failure
All,
I am using the SFL/SNACC libraries to parse a P7M format file. I
was
having a problem opening a somewhat large P7M file (the file I was parsing
was
208K). The call stack to where I got an error is:
- CSM_MsgToVerify::PreProc(CSMIME *, CSM_Buffer *,
CSM_ListC<CSM_RecipientIdentifier> *)
- CSM_MsgToVerify::PreProc(CSM_Buffer *)
- CSM_DataToVerify::PreProc(CSM_Buffer *)
- SME(DECODE_BUF_NOFAIL(m_pSnaccSignedData, pEncodedBlob, status))
The last line, the call to the macro "DECODE_BUF_NOFAIL", created an
exception
when the free() was called at the end of the macro. It looks like this
macro
will not handle a buffer that is bigger than VDASNACC_ENCDEC_BUFSIZE
(100000).
It would be nice if inside the macro (in "sm_vdasnacc.h"), the
constant
VDASNACC_ENCDEC_BUFSIZE could be changed to (blob)->Length(), such that the
new
macro looks like:
#define DECODE_BUF_NOFAIL(decodeData, blob, status)\
{\
char *pchBuffer = (char *)calloc(1, \
(blob)->Length());\
size_t encodedLen;\
AsnBuf outputBuf;\
int nDecStatus = 0;\
\
outputBuf.Init(pchBuffer, (blob)->Length());\
outputBuf.ResetInWriteRvsMode();\
SM_WriteToAsnBuf((blob), outputBuf);\
outputBuf.ResetInReadMode();\
if ((nDecStatus = (decodeData)->BDecPdu(outputBuf, encodedLen)) ==
false)\
status = 1;\
else\
status = 0;\
free(pchBuffer);\
}
However, this doesn't work, because the macro is called with both a
CSM_Buffer
pointer and a CSM_Buffer reference in various places.
In order to make this macro work for CSM_Buffer's that are bigger
than
VDASNACC_ENCDEC_BUFSIZE, one of a few things is going to have to happen:
(1) - the macro could be split into 2 macros, one that works for
CSM_Buffer pointers [(blob)->Length()] and one that works for CSM_Buffer
references [(blob).Length()].
(2) - the change could be made to the macro as shown above, and all
calls to the macro in the SFL that currently call it with a CSM_Buffer
reference
could be changed to call the macro with a CSM_Buffer pointer.
(3) - an argument could be added to the macro that specifies the
length
of the data in 'blob', and that length could take the place of
VDASNACC_ENCDEC_BUFSIZE in the macro definition.
I'm not sure how I'm going to handle this. Any of these proposed
changes would cause a lot of small changes all over the SFL. Does anyone
have a
different/better idea?
Thanks,
John Nord
sm_vdasnacc.h
(application/octet-stream, 12.4 KB)
/* @(#) sm_vdasnacc.h 1.33 12/17/99 15:05:58 */
// vdasnacc.h
//
#ifndef _SM_VDASNACC_H_
#define _SM_VDASNACC_H_
// PIERCE: void recursive include
// #include "asn-incl.h"
#include <stdio.h>
#include "sm_buffer.h" // buffer classes
#include "sm_error.h" // exception handling
#include "asn-usefulVDA.h"
// VDASNACC_ENCDEC_BUFSIZE is the number of bytes in the global
// buffer used for encoding and decoding
#define VDASNACC_ENCDEC_BUFSIZE 100000
// SNACC related prototypes
//
long SNACCDLL_API vdasnacc_sortSet(CSM_Buffer *pEncBuf[], int icount);
long SNACCDLL_API vdasnacc_sortSetOf(CSM_Buffer **&pEncBuf, int icount);
long SNACCDLL_API SM_WriteToAsnBuf(CSM_Buffer *&pCBuf, AsnBuf &SNACCinputBuf);
long SNACCDLL_API SM_WriteToAsnBuf(CSM_Buffer &CBuf, AsnBuf &SNACCoutputBuf);
long SNACCDLL_API SM_ReadFromAsnBuf(CSM_Buffer *&pCBuf, // OUT,copied data.
AsnBuf &SNACCinputBuf, // IN, input SNACC buffer
long length, // IN, length of data to read.
CSM_Buffer *preLoad); // IN, optional data to be pre-loaded;
// (for SNACC support)
// no alloc version of SM_ReadFromAsnBuf
long SNACCDLL_API SM_ReadFromAsnBuf(
AsnBuf &SNACCinputBuf, // IN, input SNACC buffer
CSM_Buffer *pCBuf, // OUT,copied data.
long length, // IN, length of data to read.
CSM_Buffer *preLoad); // IN, optional data to be pre-loaded;
// (for SNACC support)
// function to convert an AsnBits to a CSM_Buffer
long SNACCDLL_API SM_AsnBits2Buffer(AsnBits *pBits, CSM_Buffer *pBuffer);
long SNACCDLL_API SM_Buffer2AsnBits(CSM_Buffer *pBuffer, AsnBits *pBits, size_t lBits);
long SNACCDLL_API SM_BufferReverseBits(CSM_Buffer *pBuffer);
class BigIntegerStr;
// prototypes for converting to and from BigIntegerStr and CSM_Buffer.
long SNACCDLL_API SM_Buffer2BigIntegerStr( CSM_Buffer *asn1Data,
BigIntegerStr &pSnaccBigIntStr,
bool unsignedFlag);
long SNACCDLL_API SM_Buffer2BigIntegerStr( CSM_Buffer *asn1Data,
BigIntegerStr *&pSnaccBigIntStr,
bool unsignedFlag);
/////////////////////////////////////////////////////////////////////
// MACROS
//
// MACRO: ENCODE_ANY()
// PURPOSE: If VDA enchanced ANY processing is being used
// then the SNACC AsnAny class stores ANYs in a
// CSM_Buffer. This macro will encode the
// SNACC object "encodedData" into a CSM_Buffer
// object and then stuff it in the AsnAny's value
// member.
//
#define ENCODE_ANY(encodedData,asnAny)\
{\
CSM_Buffer *blob=NULL;\
\
if ((encodedData) && (asnAny))\
{\
ENCODE_BUF((encodedData), blob)\
(asnAny)->value = (AsnType *)blob;\
}\
}
//
// MACRO: DECODE_ANY()
// PURPOSE: If VDA enchanced ANY processing is being used
// then the SNACC AsnAny class stores ANYs in a
// a CSM_Buffer. This macro will decode the the
// contents of the asnAny object into the SNACC
// object decodeData.
//
#define DECODE_ANY(decodeData,asnAny)\
{\
CSM_Buffer *blob;\
if ((asnAny))\
blob=(CSM_Buffer *)(asnAny)->value;\
\
if (blob)\
DECODE_BUF((decodeData), blob)\
}
// This macro is usually only necessary if a SNACC AsnBuf is used
// immediately after being loaded by an application (e.g. consecutive
// encode decode operations).
#define SNACC_BUFRESET_READ(pSnaccBuf) (pSnaccBuf)->ResetInReadMode();
#define SNACC_BUFRESET_WRITE(pSnaccBuf) (pSnaccBuf)->ResetInWriteRvsMode();
#define ENCODE_BUF_NO_ALLOC(encodeData, blob)\
{\
char *pchBuffer = (char *)calloc(1, \
VDASNACC_ENCDEC_BUFSIZE);\
size_t encodedLen;\
AsnBuf outputBuf;\
int status=0;\
\
outputBuf.Init(pchBuffer, VDASNACC_ENCDEC_BUFSIZE);\
outputBuf.ResetInWriteRvsMode();\
status = (encodeData)->BEncPdu (outputBuf, encodedLen);\
outputBuf.ResetInReadMode();\
SM_ReadFromAsnBuf(outputBuf, (blob), outputBuf.DataLen(),NULL);\
free(outputBuf.BlkPtr()/*pchBuffer*/);\
}
#define ENCODE_BUF(encodeData, blob)\
{\
char *pchBuffer = (char *)calloc(1, \
VDASNACC_ENCDEC_BUFSIZE);\
size_t encodedLen;\
AsnBuf outputBuf;\
int status=0;\
\
outputBuf.Init(pchBuffer, VDASNACC_ENCDEC_BUFSIZE);\
outputBuf.ResetInWriteRvsMode();\
if((status = (encodeData)->BEncPdu (outputBuf, encodedLen))==false)\
SME_THROW(33, "BAD SNACC Encode", NULL);\
outputBuf.ResetInReadMode();\
SM_ReadFromAsnBuf((blob), outputBuf, outputBuf.DataLen(),NULL);\
free(outputBuf.BlkPtr()/*pchBuffer*/);\
}
// RWC; the "vdacerr" referenced in this macro is defined in the asn-config.h
// RWC; for SNACC error handling. It is global; it is only used on error;
// RWC; it is cleared after the data is extracted.
#define DECODE_BUF(decodeData, blob)\
{\
char *pchBuffer = (char *)calloc(1, \
VDASNACC_ENCDEC_BUFSIZE);\
size_t encodedLen;\
AsnBuf outputBuf;\
int nDecStatus = 0;\
\
outputBuf.Init(pchBuffer, VDASNACC_ENCDEC_BUFSIZE);\
outputBuf.ResetInWriteRvsMode();\
SM_WriteToAsnBuf((blob), outputBuf);\
outputBuf.ResetInReadMode();\
if ((nDecStatus = (decodeData)->BDecPdu(outputBuf, encodedLen)) == false)\
{\
free(outputBuf.BlkPtr()/*pchBuffer*/);\
vdacerr << '\0';\
SME_THROW(34, vdacerr.str(), NULL);\
vdacerr.rdbuf()->sgetn(outputBuf.BlkPtr(), strlen(vdacerr.str())+1);\
}\
free(outputBuf.BlkPtr()/*pchBuffer*/);\
}
#define DECODE_BUF_NOFAIL(decodeData, blob, status)\
{\
char *pchBuffer = (char *)calloc(1, \
VDASNACC_ENCDEC_BUFSIZE);\
size_t encodedLen;\
AsnBuf outputBuf;\
int nDecStatus = 0;\
\
outputBuf.Init(pchBuffer, VDASNACC_ENCDEC_BUFSIZE);\
outputBuf.ResetInWriteRvsMode();\
SM_WriteToAsnBuf((blob), outputBuf);\
outputBuf.ResetInReadMode();\
if ((nDecStatus = (decodeData)->BDecPdu(outputBuf, encodedLen)) == false)\
status = 1;\
else\
status = 0;\
free(pchBuffer);\
}
#define SM_ASSIGN_ANYBUF(lpBuf, asnAny)\
{\
(asnAny)->value = (AsnType *)new CSM_Buffer(*(lpBuf));\
}
/* don't know if this actually works... dave */
#define SM_EXTRACT_ANYBUF(pSS, asnAny)\
{\
(pSS) = new CSM_Buffer(*(CSM_Buffer *)(asnAny)->value);\
}
#define ENCODE_BUF1(encodeContent, encodeLen)\
{\
AsnBuf outputBuf;\
char *lpszBuf;\
\
lpszBuf = (char *)calloc(1, VDASNACC_ENCDEC_BUFSIZE/2);\
outputBuf.Init(lpszBuf, VDASNACC_ENCDEC_BUFSIZE/2);\
outputBuf.ResetInWriteRvsMode();\
(encodeLen) = encodeContent(outputBuf);
#define ENCODE_BUF2(blob)\
outputBuf.ResetInReadMode();\
SM_ReadFromAsnBuf((blob), outputBuf, outputBuf.DataLen(),NULL);\
free(lpszBuf);\
}
// RWC; The following macro defines the ASN ANY load for "BEnc...()"
// RWC; operations into the final output buffers. NO ERROR checking
// RWC; is performed to be sure the buffer is ASN decodable.
// RWC; this convention for loading ANY results is only valid for
// RWC; the SMIME/MSP library loads, where previous logic has
// RWC; loaded the "AsnType *value" element with a "CSM_Buffer *"
// RWC; containing the encoded ANY result.
// RWC; The "Str_struct *" needs to be freed when class destroyed.
// RWC; Place encoded ASN directly into buffer.
#define ENC_LOAD_ANYBUF(asnType, Bbuf, l) \
if ((CSM_Buffer *)(asnType)->value != NULL)\
{\
SM_WriteToAsnBuf(((CSM_Buffer *&)(asnType)->value), Bbuf);\
l = ((CSM_Buffer *)(asnType)->value)->Length();\
}
// RWC; The following macro decodes the ANY buffer tag and length to
// RWC; allocate a "CSM_Buffer", then copies the unencoded results.
// RWC; The assumption is that the "readloc" buffer will still be intact
// RWC; even after the decode of the tag and length. (HOPEFULLY!)
// RWC; Once the data for this ANY is copied, unencoded into the CSM_Buffer
// RWC; then we set the buffer "readloc" pointer to after this element.
// RWC; "bBuf.GetSeg(elmtLen)"
#define DEC_LOAD_ANYBUF(asnType, Bbuf, l, env) \
{\
size_t len = (size_t) 0; \
AsnLen bytesDecodedXX = 0L; \
size_t elmtLen = (size_t) 0; \
int tag = 0 ; \
char *readloc = NULL; \
CSM_Buffer *blob; \
CSM_Buffer *preLoad;\
\
readloc = Bbuf.GetSeg (&len);\
tag = BDecTag (Bbuf, bytesDecodedXX, env);\
elmtLen = BDecLen (Bbuf, bytesDecodedXX, env);\
len = bytesDecodedXX;\
preLoad = new CSM_Buffer(readloc, len);\
elmtLen = SM_ReadFromAsnBuf(blob, (Bbuf), elmtLen,preLoad);\
(asnType)->value = (AsnType *)blob;\
delete preLoad;\
l += len + elmtLen;\
}
// RWC; Correctly process our OID values, the "char *" "asnOid->Set()" function
// directly loads the "->oid" private variable, no processing!!!
//int SM_STR_TO_OID(char *lpStrOid, AsnOid *asnOid);
//int SM_OID_TO_STR(char *lpStrOid, AsnOid *asnOid);
#ifdef BOB
#define SNACC_OID_FIX(asnOid, long_arr4) \
{\
unsigned long int a[11];\
int i;\
for (i=0; i < (long_arr4)->lgth; i++) a[i] = (long_arr4)->int_arr[i];\
for (i=(long_arr4)->lgth; i < 11; i++) a[i] = -1;\
(asnOid)->Set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9],\
a[10]);\
}
#endif
// DEFINE some extra functionality to the "*String" classes using similar names
// RWC;
class SNACCDLL_API VDAGeneralString
{
private:
public:
VDAGeneralString() { };
int cvt_LDAPtoStr (char *in_string, char **char_ptr);
int cvt_StrtoLDAP (wchar_t *in_string, char **char_ptr);
char *GetChar(AsnOcts &Octs); // Gets the NULL terminated string representation
// of the class (there is a default).
char *GetChar(wchar_t *p_wchar);
};
class SNACCDLL_API BMPString: public BMPStringSNACC, public VDAGeneralString
{
public:
BMPString() {};
BMPString(const char *a): BMPStringSNACC(a) {};
BMPString(const char *a, int len): BMPStringSNACC(a, len) {};
operator wchar_t * ();
};
class SNACCDLL_API IA5String: public IA5StringSNACC, public VDAGeneralString
{
public:
IA5String() {};
IA5String(const char *a): IA5StringSNACC(a) {};
IA5String(const char *a, int len): IA5StringSNACC(a, len) {};
char *GetChar();
};
class SNACCDLL_API PrintableString: public PrintableStringSNACC, public VDAGeneralString
{
public:
PrintableString() {};
PrintableString(const char *a): PrintableStringSNACC(a) {};
PrintableString(const char *a, int len): PrintableStringSNACC(a, len) {};
char *GetChar();
};
class SNACCDLL_API NumericString: public NumericStringSNACC, public VDAGeneralString
{
public:
NumericString() {};
NumericString(const char *a): NumericStringSNACC(a) {};
NumericString(const char *a, int len): NumericStringSNACC(a, len) {};
};
class SNACCDLL_API T61String: public T61StringSNACC, public VDAGeneralString
{
public:
T61String() {};
T61String(const char *a): T61StringSNACC(a) {};
T61String(const char *a, int len): T61StringSNACC(a, len) {};
};
// Multi-byte character based definitions... BMP, Universal, UTF8.
class SNACCDLL_API UniversalString: public UniversalStringSNACC, public VDAGeneralString
{
private:
void ConvertSingleByteCharsToMulti(const AsnOcts &B);
public:
UniversalString() {};
UniversalString(const char *a): UniversalStringSNACC(a) {};
UniversalString(const char *a, int len): UniversalStringSNACC(a, len) {};
char *GetChar();
operator wchar_t * ();
char *GetLDAPStr ();
UniversalString &operator = (const wchar_t * D);
UniversalString &operator = (const IA5String &C);
UniversalString &operator = (const PrintableString &C);
};
class SNACCDLL_API UTF8String: public UTF8StringSNACC, public VDAGeneralString
{
private:
void ConvertSingleByteCharsToMulti(const AsnOcts &B);
public:
UTF8String() {};
UTF8String(const char *a): UTF8StringSNACC(a) {};
UTF8String(const char *a, int len): UTF8StringSNACC(a, len) {};
char *GetChar(); //for tex eg:printf
wchar_t *GetWChar();
operator wchar_t * ();
operator char * ();
UTF8String &operator = (const wchar_t * D);
UTF8String &operator = (const PrintableString &C);
enum {
FOUR_BYTE_ENCODING = 0xf0,
THREE_BYTE_ENCODING = 0xe0,
TWO_BYTE_ENCODING = 0xc0};
int SM_UTFDecodeStr (AsnOcts &utf_string, wchar_t **char_ptr);
int SM_UTFEncodeStr (AsnOcts &inputstr, wchar_t **char_ptr);
};
#endif // _SM_VDASNACC_H_
// EOF vdasnacc.h