VirtualBox

Changeset 46720 in vbox


Ignore:
Timestamp:
Jun 21, 2013 10:07:31 AM (12 years ago)
Author:
vboxsync
Message:

Main/xml/Settings.cpp: limit snapshot depth to 250, avoiding crashes
Main/Snapshot: limit snapshot depth to 250
Main/Medium: eliminate some spurious error messages when saving a VM config

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/manual/user_ChangeLogImpl.xml

    r46524 r46720  
    2727        <para>Settings: global and per-VM default frontend configuration,
    2828          useful to select the use of alternative VM frontends</para>
     29      </listitem>
     30
     31      <listitem>
     32        <para>Settings: limit depth of snapshot tree to 250 levels, as more
     33          will lead to decreased performance and may trigger crashes</para>
    2934      </listitem>
    3035
  • trunk/include/VBox/settings.h

    r46667 r46720  
    5050#include <list>
    5151#include <map>
     52
     53/**
     54 * Maximum depth of the snapshot tree, to prevent stack overflows.
     55 * XPCOM has a relatively low stack size for its workers, and we have
     56 * to avoid crashes due to exceeding the limit both on reading and
     57 * writing config files.
     58 */
     59#define SETTINGS_SNAPSHOT_DEPTH_MAX 250
    5260
    5361namespace xml
     
    11961204    void readAutostart(const xml::ElementNode *pElmAutostart, Autostart *pAutostart);
    11971205    void readGroups(const xml::ElementNode *elmGroups, StringsList *pllGroups);
    1198     void readSnapshot(const xml::ElementNode &elmSnapshot, Snapshot &snap);
     1206    void readSnapshot(uint32_t depth, const xml::ElementNode &elmSnapshot, Snapshot &snap);
    11991207    void convertOldOSType_pre1_5(com::Utf8Str &str);
    12001208    void readMachine(const xml::ElementNode &elmMachine);
     
    12091217    void buildAutostartXML(xml::ElementNode *pElmParent, const Autostart *pAutostart);
    12101218    void buildGroupsXML(xml::ElementNode *pElmParent, const StringsList *pllGroups);
    1211     void buildSnapshotXML(xml::ElementNode &elmParent, const Snapshot &snap);
     1219    void buildSnapshotXML(uint32_t depth, xml::ElementNode &elmParent, const Snapshot &snap);
    12121220
    12131221    void bumpSettingsVersionIfNeeded();
  • trunk/src/VBox/Main/include/SnapshotImpl.h

    r42887 r46720  
    101101    const Utf8Str& getStateFilePath() const;
    102102
     103    uint32_t getDepth();
     104
    103105    ULONG getChildrenCount();
    104106    ULONG getAllChildrenCount();
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r45597 r46720  
    34263426    }
    34273427
     3428    /* Save the error information now, the implicit restore when this goes
     3429     * out of scope will throw away spurious additional errors created below. */
     3430    ErrorInfoKeeper eik;
    34283431    for (GuidList::const_iterator it = llRegistryIDs.begin();
    34293432         it != llRegistryIDs.end();
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r45367 r46720  
    496496
    497497/**
     498 * Returns the depth in the snapshot tree for this snapshot.
     499 *
     500 * @note takes the snapshot tree lock
     501 */
     502
     503uint32_t Snapshot::getDepth()
     504{
     505    AutoCaller autoCaller(this);
     506    AssertComRC(autoCaller.rc());
     507
     508    // snapshots tree is protected by machine lock
     509    AutoReadLock alock(m->pMachine COMMA_LOCKVAL_SRC_POS);
     510
     511    uint32_t cDepth = 0;
     512    ComObjPtr<Snapshot> pSnap(this);
     513    while (!pSnap.isNull())
     514    {
     515        pSnap = pSnap->m->pParent;
     516        cDepth++;
     517    }
     518
     519    return cDepth;
     520}
     521
     522/**
    498523 * Returns the number of direct child snapshots, without grandchildren.
    499524 * Does not recurse.
     
    791816             ++it)
    792817        {
    793             settings::Snapshot snap;
    794             rc = (*it)->saveSnapshotImpl(snap, aAttrsOnly);
    795             if (FAILED(rc)) return rc;
    796 
    797             data.llChildSnapshots.push_back(snap);
     818           // Use the heap to reduce the stack footprint. Each recursion needs
     819           // over 1K, and there can be VMs with deeply nested snapshots. The
     820           // stack can be quite small, especially with XPCOM.
     821
     822            settings::Snapshot *snap = new settings::Snapshot();
     823            rc = (*it)->saveSnapshotImpl(*snap, aAttrsOnly);
     824            if (FAILED(rc))
     825            {
     826                delete snap;
     827                return rc;
     828            }
     829            data.llChildSnapshots.push_back(*snap);
     830            delete snap;
    798831        }
    799832    }
     
    14201453    AssertReturn(mConsoleTaskData.mLastState == MachineState_Null, E_FAIL);
    14211454    AssertReturn(mConsoleTaskData.mSnapshot.isNull(), E_FAIL);
     1455
     1456    if (   mData->mCurrentSnapshot
     1457        && mData->mCurrentSnapshot->getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
     1458    {
     1459        return setError(VBOX_E_INVALID_OBJECT_STATE,
     1460                        tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
     1461                        mUserData->s.strName.c_str());
     1462    }
    14221463
    14231464    if (    !fTakingSnapshotOnline
     
    21082149    if (childrenCount > 1)
    21092150        return setError(VBOX_E_INVALID_OBJECT_STATE,
    2110                         tr("Snapshot '%s' of the machine '%s' cannot be deleted. because it has %d child snapshots, which is more than the one snapshot allowed for deletion"),
     2151                        tr("Snapshot '%s' of the machine '%s' cannot be deleted, because it has %d child snapshots, which is more than the one snapshot allowed for deletion"),
    21112152                        pSnapshot->getName().c_str(),
    21122153                        mUserData->s.strName.c_str(),
  • trunk/src/VBox/Main/xml/Settings.cpp

    r46667 r46720  
    34793479 * Snapshot structure.
    34803480 *
     3481 * @param depth
    34813482 * @param elmSnapshot
    34823483 * @param snap
    34833484 */
    3484 void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot,
     3485void MachineConfigFile::readSnapshot(uint32_t depth,
     3486                                     const xml::ElementNode &elmSnapshot,
    34853487                                     Snapshot &snap)
    34863488{
     3489    if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
     3490        throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), depth);
     3491
    34873492    Utf8Str strTemp;
    34883493
     
    35313536                if (pelmChildSnapshot->nameEquals("Snapshot"))
    35323537                {
    3533                     Snapshot child;
    3534                     readSnapshot(*pelmChildSnapshot, child);
    3535                     snap.llChildSnapshots.push_back(child);
     3538                    // Use the heap to reduce the stack footprint. Each
     3539                    // recursion needs over 1K, and there can be VMs with
     3540                    // deeply nested snapshots. The stack can be quite
     3541                    // small, especially with XPCOM.
     3542                    Snapshot *child = new Snapshot();
     3543                    readSnapshot(depth + 1, *pelmChildSnapshot, *child);
     3544                    snap.llChildSnapshots.push_back(*child);
     3545                    delete child;
    35363546                }
    35373547            }
     
    36703680                Snapshot snap;
    36713681                // this will recurse into child snapshots, if necessary
    3672                 readSnapshot(*pelmMachineChild, snap);
     3682                readSnapshot(1, *pelmMachineChild, snap);
    36733683                llFirstSnapshot.push_back(snap);
    36743684            }
     
    45514561             && (sc.controllerType == StorageControllerType_I82078)
    45524562           )
    4553             // floppy controller already got written into <Hardware>/<FloppyController> in writeHardware()
     4563            // floppy controller already got written into <Hardware>/<FloppyController> in buildHardwareXML()
    45544564            // for pre-1.9 settings
    45554565            continue;
     
    47514761 * for the root snapshot of a machine, if present; elmParent then points to the <Snapshots> node under the
    47524762 * <Machine> node to which <Snapshot> must be added. This may then recurse for child snapshots.
     4763 *
     4764 * @param depth
    47534765 * @param elmParent
    47544766 * @param snap
    47554767 */
    4756 void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent,
     4768void MachineConfigFile::buildSnapshotXML(uint32_t depth,
     4769                                         xml::ElementNode &elmParent,
    47574770                                         const Snapshot &snap)
    47584771{
     4772    if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
     4773        throw ConfigFileError(this, NULL, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX);
     4774
    47594775    xml::ElementNode *pelmSnapshot = elmParent.createChild("Snapshot");
    47604776
     
    47884804        {
    47894805            const Snapshot &child = *it;
    4790             buildSnapshotXML(*pelmChildren, child);
     4806            buildSnapshotXML(depth + 1, *pelmChildren, child);
    47914807        }
    47924808    }
     
    49254941    if (    (fl & BuildMachineXML_IncludeSnapshots)
    49264942         && llFirstSnapshot.size())
    4927         buildSnapshotXML(elmMachine, llFirstSnapshot.front());
     4943        buildSnapshotXML(1, elmMachine, llFirstSnapshot.front());
    49284944
    49294945    buildHardwareXML(elmMachine, hardwareMachine, storageMachine);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette