0

Below are my codes...

main.cpp

/* header files are included here */

PCI_card card;

int main(void)
{
    card.init_card(0);

    return 0;
}

pci_card.h

#ifndef __PCI_CARD_H
#define __PCI_CARD_H

/* header files are included here */

typedef struct {
    int32_t card_index;
    int32_t user_counter;
} card_dev_t;

class PCI_card {
public:
    PCI_card() : dev_descriptor(-1) { enlarge_vector(); }

    int32_t init_card(int32_t card_num);

private:
    int32_t dev_descriptor;

public:
    static int32_t enlarge_vector();

private:
    static int32_t card_amount;
    static std::vector<card_dev_t> cards;
};

#endif

pci_card.cpp

/* header files are included here */

int32_t PCI_card::card_amount = -1;
std::vector<card_dev_t> PCI_card::cards;

int32_t PCI_card::init_card(int32_t card_num)
{
    if (card_num >= card_amount || card_num < 0)
        return -1;

    card_dev_t new_card = {
        .card_index = card_num,
        .user_counter = 1
    };

    cards[card_num] = new_card;
    dev_descriptor = card_num;

    return 0;
}

int32_t PCI_card::enlarge_vector()
{
    card_amount = 10;
    card_dev_t null_card = {
        .card_index = -1,
        .user_counter = -1
    };

    cards.resize(card_amount, null_card);

    return card_amount;
}

In main.cpp, card is defined as a global variable, and of course, it should be initialized before invoking main() function, and this can be seen clearly via gdb.

When initializing card, constructor of class PCI_card is invoked, the vector cards in this class is resized according to card_amount member variable. From the gdb, this vector does be initialized properly, it contains 10 elements.

Weird things happened before invoking main() function, the vector is reset. In gdb, the size of vector rolled back to 0, and of course, subsequent operations, such as subscript this vector, cause segment fault error.

I don't know what happen here.... it is too ridiculous...

Douglas Su
  • 3,214
  • 7
  • 29
  • 58
  • 4
    your vector static and now you have to know which one is initialized first. global objects or static ones. see here for the answer: http://stackoverflow.com/questions/1005685/c-static-initialization-order – Hayt Aug 25 '16 at 14:52
  • 2
    This isn't the problem, but names that contain two underscores (`__PCI_CARD_H`) and names that begin with an underscore followed by a capital letter are reserved for use by the implementation. Don't use them. – Pete Becker Aug 25 '16 at 15:13
  • @PeteBecker in C, it seems that macro variables start with underscores are common... I don't know if it has some side effects in c++... – Douglas Su Aug 27 '16 at 14:18

1 Answers1

0

It looks like you have hit a static initialization order fiasco. It is possible that PCI_card card; initialization will happen before std::vector<card_dev_t> PCI_card::cards. If that happen (and standard allows it) then PCI_card::enlarge_vector() will call resize (here enter UB) on not yet initialized vector. After its execution normal static initialization of PCI_card::cards will get executed - initializing vector to empty one. And this is why you see this behaviour:

In gdb, the size of vector rolled back to 0,

This is Undefined Behaviour so anything that you see in gdb is possible.

The solution is to either make cards non static, or use a static function with static field which will return it:

std::vector<card_dev_t>& getCards() {
   static std::vector<card_dev_t> cards;
   return cards;
}

this will ensure that cards will get initialized on first use of getCards.

marcinj
  • 48,511
  • 9
  • 79
  • 100