Обсуждение: Re: C set return function differences on 8.0?]]

Поиск
Список
Период
Сортировка

Re: C set return function differences on 8.0?]]

От
Tim Jackson
Дата:
Michael Fuhr wrote:

>Where did you look for a core dump?  If one was made then it'll
>probably be somewhere under $PGDATA (e.g., $PGDATA/base/XXX/core)
>unless your system is configured to put core dumps elsewhere.
>
>  
>
I was able to get the core dump by adding 'ulimit -c unlimited' to the 
start script
(thanks Tom)
It is huge (14 megs)
One interesting thing happened once the core dump is created. 
Now if I re connect to the data base and rerun the select on the view 
after it has crashed once it will select the view.

>If there isn't a core dump then you could add some debugging ereport()
>calls to your code so you can find out where the crash is happening.
>Another possibility might be to attach a debugger to the backend.
>
>  
>
If you can tell me how to do that.  I tried attaching gdb to the running 
servers pid and it seems to lock up the server.

>So your C function calls these library functions, which query some
>other data source and return strings back to you, right?  How are
>these strings returned -- as char * values?  Can you at least post
>your code?
>
>  
>
The full so code is 4000 lines and caused the news group to reject the mail
, but here is the basic format with the piece that builds the record replaced 
by hardcoded values.  


/*******************************/
//
//   Program:  call_good.c
//
//   Listing Date: 07/08/2005
//
/*******************************/

#include "server/postgres.h"
#include "server/fmgr.h"
#include "server/funcapi.h"

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>


#define TRUE    1
#define FALSE   0
#define OK      0
#define ERROR1   (-1)
#define YES     1
#define NO      0
#define DATA1    2
#define MAYBE   2
 char record[1024 * 1024];
 char buffer[256]; unsigned char * bufptr = (unsigned char *)buffer; char buffer1[256]; unsigned char * bufptr1 =
(unsignedchar *)buffer1; char buffer2[256]; unsigned char * bufptr2 = (unsigned char *)buffer2; char buffer3[256];
unsignedchar * bufptr3 = (unsigned char *)buffer3;
 
 int count, count1; long    CurrentSize; char request[8192]; char response[512];
 char typedefin[1024]; int  max_fields; int  field_lengths[256]; char field_types[256][16]; char *record_add; char
parsed[256];
 char *select_add; char *from_add; char *where_add; char *end_add; char select1[8192]; char from[512]; char
where[512];
 FILE *stream; FILE *stream1; char filein[128]; char fileout[128]; char filename_out[128];   int num_targets_work;
intnum_targets_index;   int chunk_amount = 5;   int chunk_counter;   int fileOpen;     FuncCallContext *funcctx;   int
          call_cntr;   int             max_calls;   TupleDesc       tupdesc;   TupleTableSlot  *slot;   AttInMetadata
*attinmeta;


/***********************************/
// select_more_data
/***********************************/
int tselect_more_data (void)
{   int recordFound;
   memset (record, 0, sizeof(record));
      sprintf (buffer1, "%s|%s|%s|%s|", "6","6666.01","6-6 Wide","Y");      strcat (record, buffer1);      sprintf
(buffer1,"%s|%s|%s|%s|", "7","7777.01","7-6 Wide","Y");      strcat (record, buffer1);      sprintf (buffer1,
"%s|%s|%s|%s|","8","888888.0001","8-6 Wide","Y");      strcat (record, buffer1);      sprintf (buffer1, "%s|%s|%s|%s|",
"9","9999.01","9-6Wide","Y");      strcat (record, buffer1);      sprintf (buffer1, "%s|%s|%s|%s|",
"10","1010.01","10-6Wide","Y");      strcat (record, buffer1);
 
      count = 5;
   if (count)       recordFound = DATA1;
   return (recordFound);
}

/***********************************/
// select_data
/***********************************/
int tselect_data (void)
{   int recordFound;
   memset (record, 0, sizeof(record));        sprintf (buffer1, "%s|%s|%s|%s|", "1","1111.01","1-6 Wide","Y");
strcat(record, buffer1);      sprintf (buffer1, "%s|%s|%s|%s|", "2","2222.01","2-6 Wide","Y");      strcat (record,
buffer1);     sprintf (buffer1, "%s|%s|%s|%s|", "3","3333.01","3-6 Wide","Y");      strcat (record, buffer1);
sprintf(buffer1, "%s|%s|%s|%s|", "4","  4444.01","4-6 Wide","Y");      strcat (record, buffer1);      sprintf (buffer1,
"%s|%s|%s|%s|","5","5555.01","5-8 Wide","Y");      strcat (record, buffer1);
 
      count = 5;
   if (count)       recordFound = DATA1;
   return (recordFound);
}

/***********************************/
// select_field_lengths
/***********************************/
int tselect_field_lengths (void)
{   int recordFound;   int len;
     CurrentSize = 10;           len = 3;         field_lengths[0] = len * 2 + 1;         strcpy (field_types[0],
"numeric");
       len = 4;         field_lengths[1] = len * 2 + 1;         strcpy (field_types[1], "numeric");           len = 30;
       field_lengths[2] = len;         strcpy (field_types[2], "string");           len = 1;         field_lengths[3] =
len;        strcpy (field_types[3], "string");       max_fields = 4;     recordFound = DATA1;   return (recordFound);
 
}

/***********************************/
// parse_record
/***********************************/
void tparse_record (void)
{   char    *ptr;   char    *ptr1;
   ptr = record_add;     ptr1 = strchr (ptr, '|');   if (ptr1)   {       *ptr1 = 0;       strcpy (parsed,ptr);   }
record_add= ++ptr1;
 
}

/***********************************/
//  parse_sql
/***********************************/
int tparse_sql (char * request)
{   int func;
   select_add    =   from_add      =   where_add     =   end_add       = 0L;
   memset ( select1,   0, sizeof(select1));   memset ( from,      0, sizeof(from));   memset ( where,     0,
sizeof(where));
   select_add    = strstr(request, "SELECT ");   if (select_add == 0)       select_add    = strstr(request, "select ");
   if (select_add != 0)   {       from_add      = strstr(request, "FROM ");       if (from_add == 0)           from_add
    = strstr(request, "from ");   }
 
   where_add     = strstr(request, "WHERE ");   if (where_add == 0)       where_add     = strstr(request, "where ");
   if (select_add != 0)   {       end_add       = select_add+strlen(request);       func = 40;   }   else   {
func= 999;       return func;   }
 
   if (select_add != 0)   {       memcpy ( select1, select_add, from_add-select_add);       if (where_add == 0)       {
         memcpy ( from, from_add, end_add-from_add);       }       else if (where_add)       {           memcpy ( from,
from_add,where_add-from_add);           memcpy ( where, where_add, end_add-where_add);       }   }   return func;
 
}

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

PG_FUNCTION_INFO_V1 (call_good);

Datum
call_good (PG_FUNCTION_ARGS)
{   int  i, func, retval;
   // stuff done only on the first call of the function   if (SRF_IS_FIRSTCALL())   {       MemoryContext
oldcontext;
       text *t  = PG_GETARG_TEXT_P(0);       text *t1 = PG_GETARG_TEXT_P(1);
       memset (request, 0, sizeof(request));       strncpy (request, t->vl_dat, t->vl_len- VARHDRSZ);
       memset (typedefin, 0, sizeof(typedefin));       strncpy (typedefin, t1->vl_dat, t1->vl_len- VARHDRSZ);
       // create a function context for cross-call persistence       funcctx = SRF_FIRSTCALL_INIT();
       // switch to memory context appropriate for multiple function calls       oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
       // Build a tuple description for a incoming type tuple       tupdesc = RelationNameGetTupleDesc(typedefin);
       // allocate a slot for a tulpe with this tupdesc       slot = TupleDescGetSlot(tupdesc);
       // assign slot to function context       funcctx->slot = slot;
       // Generate attribute metadata needed later to produce       // tupples from raw C strings       attinmeta =
TupleDescGetAttInMetadata(tupdesc);      funcctx->attinmeta = attinmeta;
 
       MemoryContextSwitchTo(oldcontext);         strcpy (fileout, "pfxG");       sprintf (filename_out, "/tmp/%s.rsp",
fileout);    // rf
 
       if ((stream1 = fopen (filename_out, "wb")) == NULL)       {           return 1;       }             if ((stream
=fopen ("/tmp/call_good.log", "a+")) == NULL)       {           return 1;       }       fprintf
(stream1,"Call_Good\n");         fprintf (stream1,"request>%s<\n",request);          fprintf (stream1,"file:
%s\n",typedefin);
 
       func = tparse_sql (request);
       record_add = 0;
       tselect_field_lengths();       fprintf (stream,"NumRecs = %ld NumFields = %d\n",               CurrentSize,
max_fields);         for (i=0; i < max_fields; i++)       {           fprintf (stream1,"Field: %3d Type: %-8s Length:
%d\n",                  i,field_types[i],field_lengths[i]);       }
 
       switch (func)       {           case 40:               if (select_add)               {                   fprintf
(stream1,"select: %s\n",select1);                   fprintf (stream1, "from: %s\n",from);                   if
(where_add)                  {                       fprintf (stream1, "where: %s\n",where);                   }
      }               funcctx->max_calls = CurrentSize;
 
               // Go get first chunk of records from file               retval = tselect_data();
               if (retval != DATA1)               {                   strcpy (record, "Not Found\n");
fwrite(record, strlen(record), 1, stream1);               }               break;           case 999:
strcpy(record, "Invalid Statement");               fwrite (record, strlen(record), 1, stream1);               break;
 
           default:               strcpy (record, "Invalid");               fwrite (record, strlen(record), 1,
stream1);              retval = NO;               break;       }       fprintf (stream,"Count = %ld Data =
%.50s\n",CurrentSize,record);       fprintf (stream,"File: %s Type: %s\n",filein,typedefin);        record_add =
record;      chunk_counter = chunk_amount;       fflush (stream);   }     // stuff done on every call of the function
funcctx= SRF_PERCALL_SETUP();
 
   call_cntr = funcctx->call_cntr;   max_calls = funcctx->max_calls;   slot = funcctx->slot;   attinmeta =
funcctx->attinmeta;
   if (call_cntr < max_calls)   {       char        **values;       HeapTuple   tuple;       Datum       result;
       if (call_cntr == chunk_counter)       {           // Go get next chunk of records from file           retval =
tselect_more_data();          record_add = record;           chunk_counter += chunk_amount;       }
 
       // Prepare a values array for storage in our slot.       // This should be an array of C strings which will
// be processed later by the appropriate "in" functions.             values = (char **) palloc(max_fields * sizeof(char
*));      for (i=0; i < max_fields; i++)       {           values[i] = (char *) palloc(field_lengths[i] *
sizeof(char));      }
 
       for (i=0; i < max_fields; i++)       {           tparse_record();
           if (strlen(parsed) == 0 && strcmp(field_types[i],"date") == 0)           {               strcpy (values[i],
"01/01/1980");          }           else           {               strcpy (values[i], parsed);           }       }
 
       // build a tuple       tuple = BuildTupleFromCStrings(attinmeta, values);       // make the tuple into a datum
   result = TupleGetDatum(slot,tuple);      // result = HeapTupleGetDatum(tuple);
 
       // Clean up (this is not actually necessary)       for (i=0; i < max_fields; i++)       {
pfree(values[i]);      }       pfree(values);
 
       fflush (stream);       SRF_RETURN_NEXT(funcctx, result);   }   else    // do when there is no more left   {
if (fileOpen)       {           fprintf (stream, "EOD Set5\n");           fileOpen = 0;       }       fprintf
(stream1,"DONE:call_cntr= %d max_calls= %d\n",               call_cntr,max_calls);        fclose (stream1);
fclose(stream);       SRF_RETURN_DONE(funcctx);   }
 
}






Re: C set return function differences on 8.0?]]

От
Tom Lane
Дата:
Tim Jackson <tim.jackson@ints.com> writes:
> The full so code is 4000 lines and caused the news group to reject the mail
> , but here is the basic format with the piece that builds the record replaced 
> by hardcoded values.  

With all those unchecked strcat's and strcpy's going on, it seems like
an excellent bet that you're overrunning one or another buffer and
clobbering memory that doesn't belong to you.  Compiling the backend
with --enable-cassert might help in localizing the problem.
        regards, tom lane