Solved

uuencode + uudecode, interesting error (fun!?)

Posted on 2010-09-15
2
932 Views
Last Modified: 2013-12-14
Hey guys,

For once I have some code I can post, haha.  I have to use the uuencode and uudecode algorithms - I've left them unchanged at the top of this source file.  At the end of the source file I have a test.

The test creates a class, called Test (creative, huh!?).  Ive created some additional functions (Stringify and Unstringify) as simple template interfaces that hide the complexity of the actual uuencode/uudecode C calls.  

Anyway, here's my problem...  As is, a straight g++ compile of this works great and runs.  However, if you comment out the contents of my constructor for the Test class, it starts getting seg faults.  Also, if I add in a new structure and put a vector of that arbitrary structure in the Test structure, I get seg faults.

I'm guessing there's some reason I shouldn't use a vector for uuencode//uudecode or possibly my Stringify/Unstringify functions have an error?  It always seems to Stringify well even if its getting seg faults, but I guess just because its succeeding doesn't mean it necessarily made a useful string... The last line of Unstringify is where the crash actually happens (my cast from back from a byte buffer into my object type).

PS: ignore the actual uuencode/uudecode functions, they're COTS.  I just left them in so the example would compile and you could play with it & see whats going on.

So...
(1) are there errors in MY functions?
(2) why is it crashing only when I comment out the constructor contents?
(3) is there a reason I shouldn't use a vector?  I could switch to arrays.
(4) is there a better way I can accomplish this?
/****************************************************************

*                                                               * 

* Sample UUENCODE and UUDECODE routines.                        * 

* Copyright 1995, Socket Communications.                        * 

*                                                               * 

* These routines may be freely copied and distributed.          *

*                                                               * 

****************************************************************/



#if defined(HAVE_STRING_H)

#include <string.h>

#elif defined(HAVE_STRINGS_H)

#include <strings.h>

#endif



#ifdef HAVE_STDLIB_H

#include <stdlib.h>

#endif



#define SPACE 0x20   /* An ASCII space character */ 

#define LOWMASK 0x3f /* Mask for low bits of each byte */

#define HIMASK 0xc0  /* Mask for high bits of each byte */

#define SUCCESS 0    /* Successful encode/decode */ 

#define FAILURE -1   /* Failure encodeing/decoding */

#define CRYPT_KEY "yTin1.80"



/****************************************************************

 *                                                              * 

 * UUDECODE takes a string of encoded ASCII characters and      * 

 * performs the decoding function to recover the original input.*

 *                                                              * 

 * bin points to a buffer to hold the decoded output.           *

 * str points to the UUENCODED input (usually null terminated). * 

 * size is the number of characters in the input string.        *

 *                                                              * 

 * The size of the buffer needed to hold the decoded input can  * 

 * be calculated as:                                            * 

 * (size/4)*3 + (((size%4)) > 1?(size%4)-1:0) + 1            *

 *                                                              * 

 * NOTE: This UUDECODE routine places a terminating null at the * 

 * end of the decoded output, in case the original input        *

 * was a null terminated string.                                * 

 *                                                              * 

 ****************************************************************/

int uudecode (char *bin, int bsize, const char *str, int ssize)

  { 

  int triplets, remainder; 

  unsigned char composite; 

  int ntriplet, j; 

  int required; 

  triplets = ssize / 4; 

  remainder = ssize % 4; 

  /* 

   * Calculate the number of bytes needed in the binary

   * decoded buffer. 

   */ 

  required = 3 * triplets; 

  if (remainder) 

      required += remainder - 1; 

  required++; 

  if (required > bsize) 

      return (FAILURE); 

  /* 

   * Decode each of the triplets. 

   */ 

  for (ntriplet = 0; ntriplet < triplets; 

                ntriplet++, str++) 

      { 

      for (j = 2, composite = *(str + 3) - SPACE; 

           j < 7; j += 2, bin++, str++) 

          *bin = (*str - SPACE) | 

                 ((composite & (HIMASK >> j)) << j); 

      } 

  /* 

   * Decode any dangling bytes (0,1, or 2 bytes which 

   * did not form a complete triplet). 

   */ 

  if (remainder > 1) 

      { 

      remainder--; 

      for (j = 2, composite = *(str + remainder) - SPACE; 

           j <  (2 * remainder + 1); 

           j += 2, bin++, str++) 

        *bin = (*str - SPACE) | 

               ((composite & (HIMASK>>j)) << j); 

      } 

  *bin = 0; 

  return (SUCCESS); 

  }

 

/****************************************************************

 *                                                              * 

 * UUENCODE takes a pointer to any binary data and encodes it   * 

 * into printable ASCII characters.                             * 

 *                                                              * 

 * bin points to the data to be encoded.                        * 

 * str points to a buffer to hold the encoded output.           *

 * size is the number of bytes from the input to be encoded.    * 

 *                                                              * 

 * The size of the buffer needed to hold the encoded data can   * 

 * be calculated as:                                            * 

 * (size/3)*4 + ((size%3) ? (size%3)+1:0) + 1                   * 

 *                                                              * 

 * NOTE: This UUENCODE routine places a terminating null at the * 

 * end of the encoded output.                                   * 

 *                                                              * 

 ****************************************************************/

int uuencode (char *bin, int bsize, char *str, int ssize)

  { 

  int triplets, remainder; 

  unsigned char composite; 

  int ntriplet, j; 

  int required; 

  triplets = bsize / 3; 

  remainder = bsize % 3; 

  /* 

   * Calculate the number of bytes required in the 

   * ascii string buffer. 

   */ 

  required = triplets * 4; 

  if (remainder) 

      required += remainder + 1; 

  required++; 

  if (required > ssize) 

      return (FAILURE); 

  /* 

   * Encode each of the triplets. 

   */ 

  for (ntriplet = 0; ntriplet < triplets; 

        ntriplet++, str++) 

      { 

      for (j = 2, composite = 0; j < 7; j += 2, bin++, str++)

          { 

          *str = (*bin & LOWMASK) + SPACE; 

          composite |= (*bin & HIMASK) >> j; 

          } 

      *str = composite + SPACE; 

      } 

  /* 

   * Encode any dangling bytes (0,1, or 2 bytes which 

   * do not form a complete triplet). 

   */ 

  if (remainder) 

      { 

      for (j = 2, composite = 0; j < 2 * remainder + 1; 

                 j += 2, bin++, str++) 

          { 

          *str = (*bin & LOWMASK) + SPACE; 

          composite |= (*bin & HIMASK) >> j; 

          } 

      *str++ = composite + SPACE; 

      } 

  *str = 0; 

  return (SUCCESS); 

  }



//-------------------------------------------------------------------------------

//                                  Test Code

//-------------------------------------------------------------------------------



#include <iostream>

#include <vector>

#include <string>

using namespace std;



struct Test

{

    vector<int> intVector;

    vector<string> stringVector;

    int xx;



    Test()

    {

        //**** comment this whole block out ****

        intVector.push_back(1);

        intVector.push_back(2);

        intVector.push_back(9876);

        intVector.push_back(1);

        intVector.push_back(2);

        intVector.push_back(9876);

        stringVector.push_back("Hello");

        stringVector.push_back("World");

        xx = 2;

    }

};



template <typename T>

std::string Stringify(T obj)

{

    //Get the uuencode parameters based on the structure.

    int size = sizeof(obj);

    int outputSize = (size/3)*4 + ((size%3) ? (size%3)+1:0) + 1;

    char opt[outputSize];    



    //Stringify the structure using uuencode.

    uuencode(reinterpret_cast<char*>(&obj), size, opt, outputSize);    

    

    std::string converted(opt);



    return converted;

}



template <typename T>

void Unstringify(T& unpacked, std::string obj)

{

    const char* temp = obj.c_str();

    int size = strlen(temp);

   

    int bufferSize = (size/4)*3 + (((size%4)) > 1?(size%4)-1:0) + 1;

    char ipt[bufferSize];

    uudecode(ipt, bufferSize, temp, size);

    unpacked = *reinterpret_cast<T*>(ipt);

}



int main()

{

    //Create the test structure and change the value of xx.

    Test testToString;

    testToString.xx = 17;

    testToString.stringVector.push_back("and universe!");



    cout<<endl<<"Stringifying data..."<<endl<<endl;



    std::string stringified = Stringify(testToString);

    cout<<"Stringified data contents:" << endl << stringified<<endl;



    Test testFromString;

    Unstringify(testFromString, stringified);



    cout<<endl<<"Unstringification complete."<<endl<<endl;

    cout<<"Unstringified data contents:";



    //Check the output.

    cout<<endl<<endl<<testFromString.xx<<endl;

    for (vector<string>::iterator iter = testFromString.stringVector.begin(); iter != testFromString.stringVector.end(); ++iter)

        cout<<*iter<<" ";

    cout<<endl<<endl;

}

Open in new window

0
Comment
Question by:w00te
2 Comments
 
LVL 53

Accepted Solution

by:
Infinity08 earned 500 total points
ID: 33682442
>> (1) are there errors in MY functions?

Yes. uuencode transforms a block of bytes into a text string that can be sent in an email eg.

What will be encoded and decoded will be the contents of that block of memory. If that block of memory happens to contain pointers, then the literal values of those pointers are encoded, but NOT what the pointers point to.

So, you cannot uuencode any data that contains pointers.


>> (2) why is it crashing only when I comment out the constructor contents?

Difficult to say. It depends on the implementation, and on luck. It's wrong either way :)


>> (3) is there a reason I shouldn't use a vector?  I could switch to arrays.

Yes. vectors might use pointers internally.


>> (4) is there a better way I can accomplish this?

It seems you want to serialize data. If so, you need to make sure to not serialize any pointers, but serialize what they point to instead.

Maybe you want to use a serialization solution that can handle all this ? Like boost serialize ?

        http://www.boost.org/doc/libs/1_44_0/libs/serialization/doc/index.html
0
 
LVL 12

Author Comment

by:w00te
ID: 33684040
Thanks man.  

I changed my test structure to something holding arrays of other strucutres (fairly complex) and it works great with the same templates already defined.  It makes sense to avoid things like vectors with internal implementations that might use pointers like you said.  It didn't occur to me since I had used the COTS code without reading into it much.

Help much appreciated :)

-w00te
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org (http://seleniumhq.org) Go to that link and select download selenium in the right hand columnThat will then direct you to their downlo…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now