0

Good morning, Is it possible to fix Sun Solaris OS 5.8 segmention fault related to int * cast with gcc version 3.3? The gdb variable values are shown below. The cOrderedList class member variables are shown below. The uname -a and gcc -v outputa are shown below.
This code works fine on Windows Visual Studio C++ 9.0 .Thank you.

[New LWP 1]

Program received signal SIGSEGV, Segmentation fault.
0xff064b04 in cOrderedList::LoadDatabaseRecords(cSQLite*, char const*) (
    this=0x68f10, Database_=0xa4ba8,
    Command_=0xffbed468 "SELECT * FROM LeftPattern")
    at ../Source/cOrderedList.cpp:272
272      *((int*) (Records+RecordCount*RecordSize+FieldOffsets[i]))=Database_->ColumnInt(i);
(gdb) print i
$3 = 3
(gdb) print Records
$4 = 0xa0800 ""
(gdb) print RecordCount
$5 = 0
(gdb) print RecordSize
$6 = 50
(gdb) print FieldOffsets[i]
$7 = 46
class cOrderedList {
private:
    enum eFieldTypes {
        Character,
        Integer
    };

    bool CopyConstructed;

    int RecordCount;
    int FieldCount;
    int RecordSize;

    char *Records;
    int *FieldSizes,*FieldOffsets;
    eFieldTypes *FieldTypes;

    char *CurrentPos;
$ uname -a
SunOS 5.8 Generic_108528-22 sun4u sparc SUNW,Sun-Fire-V210

$ gcc -v
Reading specs from /usr/local/lib/gcc-lib/sparc-sun-solaris2.8/3.3/specs
Configured with: ../configure --disable-nls --with-as=/usr/ccs/bin/as --with-ld=
/usr/ccs/bin/ld
Thread model: posix
bool cOrderedList::LoadDatabaseRecords(cSQLite *Database_,const char *Command_) {
int retVal;
char str[4096];

RetrySQL:
RecordCount=0;
Database_->Prepare(Command_);
while ((retVal=Database_->Step())!=SQLITE_DONE) {
    switch (retVal) {
    case SQLITE_ROW:
        for (int i=0;i<FieldCount;i++) {
            if (FieldTypes[i]==Integer) {
                *((int*)   (Records+RecordCount*RecordSize+FieldOffsets[i]))=Database_->ColumnInt(i);
            } else {
                Database_->ColumnText(i,str);
                LTrim(str);
                RTrim(str);

                #if defined(_DEBUG)
                    if ((int) strlen(str)>=FieldSizes[i])
                        printf("Field not large enough: %s\n",Command_);
                #endif

                strncpy(Records+RecordCount*RecordSize+FieldOffsets[i],str,FieldSizes[i]);
                Records[RecordCount*RecordSize+FieldOffsets[i]+FieldSizes[i]-1]='\x0';
            }
        }
        RecordCount++;
        break;
    case SQLITE_BUSY:
        continue;
    case SQLITE_MISUSE:
        goto RetrySQL;
    default:
        break;
    }
}
return true;
}
Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
Frank
  • 1,406
  • 2
  • 16
  • 42
  • Care to show the actual code that causes this? That is, the file `cOrderedList.cpp` the lines around line 272, maybe the whole `LoadDatabaseRecords` function if it's not to big. – Some programmer dude Sep 19 '12 at 16:12
  • Have you followed `Rule of Three` ? – Mahesh Sep 19 '12 at 16:13
  • @Joachim Pileborg, This code works fine on RedHat Linux 4.0 with gcc . I will try to post the post the code. Thank yoou. – Frank Sep 19 '12 at 16:27
  • @Joachim Pileborg, I just edited the post to include the code for LoadDatabaserecords. Thank you. – Frank Sep 19 '12 at 16:31
  • @Joachim Pileborg, This code works fine on RedHat Linux 4 with gcc version 4.1.2 . Thank you. – Frank Sep 19 '12 at 16:35
  • @Joachim PIleborg, Here is the offrending code: for (int i=0;iColumnInt(i); Thank you very much. } – Frank Sep 19 '12 at 16:39
  • How, and how much, have you allocated space for the `Records` pointer? Also, if you have some problem with undefined behaviour it might work on one computer but not another. Of course, it might be that the old 3.3 version of GCC have a code generation bug as well. If no one can find anything you might have to check the generated assembler code. – Some programmer dude Sep 19 '12 at 16:46
  • @Joachim Pileborg, In this case. the gdb debugger says I have allocated 1700 bytes where Records=new char[(RecordSize*RecordCount)]; where RecordSize = 50 and RecordCount = 34. I will try to check with a different Solaris compiler such as CC. I will try to let you know the results. Thank you very much. – Frank Sep 19 '12 at 17:45
  • @Joachim Pileborg, I believe your idea that there is a code generation bug with gcc 3.3. But, how should I prove that by looking a the assembler code? When I use Sun Solaris compier CC, no segmentation fault occurs. Thank you very much. – Frank Sep 19 '12 at 17:56
  • @Mahesh, I am usng the C++ Rule of Three. Thank you. – Frank Sep 19 '12 at 17:59

3 Answers3

0

Maybe this operation: "(Records+RecordCount*RecordSize+FieldOffsets[i])" is returning a value that is over the size of the records bounds.

It is hard to tell looking at only this portion of the code, but this may be caused by differences between the sizeof(char) in both platforms...

Filipe Felisbino
  • 2,712
  • 25
  • 26
  • 1
    `sizeof(char)` is guaranteed by the standard to be one. – Some programmer dude Sep 19 '12 at 16:43
  • @filepenf, I just used the gdb debugger to verify that the operation: "(Records+RecordCount*RecordSize+FieldOffsets[i])"s not causing a buffer overrun. Joachim Pileborg thinks it might be a GCC 3.3 compiler bug. Do you concur with theory? THank you very much. – Frank Sep 19 '12 at 17:59
  • I really don't think that it might be a gcc bug. – Filipe Felisbino Sep 19 '12 at 21:01
  • How is the Records variable being allocated? What may be causing the buffer overrun is de-referencing the value returned from that operation. The result of ( 0xA0800 + 0 * 50 + 46 ). The problem is if the Records variable has less than 46 bytes... – Filipe Felisbino Sep 19 '12 at 21:30
  • 1
    @filipenf , Thisis how the Records member variable is allocated : Records = new char[(RecordCount * RecordSize)] where RecordCount =34 and RecordSize = 50. The following modifications fixes the problem *((char *)(Records+RecordCount*RecordSize+FieldOffsets[i])) = Database_->ColumnInt(i); The problem is a int* pointer misalignment. What is your opinion? Thank you for your reply. – Frank Sep 20 '12 at 04:43
  • I have just made a research and found out that this problem may be related to your processor. Since it expects ints are aligned in four-bytes boundaries and in your case probably it is getting a address that is not mod 4 the processor may be unwilling to do that. Just for clarification, what processor are you using in the solaris? – Filipe Felisbino Sep 20 '12 at 20:19
0

Good afternoon, the problem turns out out not be a gcc code generation bug or a buffer over-run. The following solution was tested on Solaris a few minutes ago using this code:

     int32_t x = Database->ColumnInt(i);
     memcpy(Records+RecordCount*RecordSize+FieldOffsets[i], &x, sizeof(int32_t));

Thank you for all of your answers and comments.

Frank
  • 1,406
  • 2
  • 16
  • 42
  • Good evening. This is also correct . I tested it on Sun Solaris 5.8 gcc 3.3 ---- *((char *)(Records+RecordCount*RecordSize+FieldOffsets[i])) = Database_->ColumnInt(i); – Frank Sep 20 '12 at 04:34
  • 1
    Good evening.The following modifications fixes the problem on HP Unix Itanium. ((char *)(Records+RecordCount*RecordSize+FieldOffsets[i])) = Database_->ColumnInt(i); The problem is a int pointer misalignment. Thank you. – Frank Sep 20 '12 at 06:18
  • Indeed. `FieldOffsets[i]==46` is not a valid alignment for 4-byte integers on SPARC. – MSalters Sep 20 '12 at 09:36
  • @MSalters, Thank you for your powerful argument. – Frank Sep 20 '12 at 12:24
0

A bit late, but none of the currently-posted answers address why the code posted fails.

This code

            *((int*)   (Records+RecordCount*RecordSize+FieldOffsets[i]))=Database_->ColumnInt(i);

violates 6.3.2.3 Pointers, paragraph 7 of the C standard:

... A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...

Note that this code may also violate strict aliasing, but I haven't analyzed it closely enough to be certain. The fact that Records is a char * may allow for the aliasing to an int value. But even if the code is correct under strict aliasing, it still has to meet all underlying system alignment requirements for that int value, else it violates the restrictions of 6.3.2.3 above.

Not all systems allow the "address anything as anything" that's the de facto x86 standard. SPARC systems such as the one in this question do not allow such "anything goes" addressing.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56