Ici, je réponds à ma propre question. Je suppose que cela arrive tout le temps dans SO. BIGNUM dans OpenSSL est une structure compliquée qui contient un nombre arbitrairement grand, et donc créer et libérer des instances BIGNUM de manière répétée entraînera un surcoût considérable. Le contexte BIGNUM, ou BN_CTX, est créé et utilisé pour enregistrer cette surcharge.
Structure
La structure BN_CTX contient deux structures: BN_POOL
et BN_STACK
. Le BN_POOL
conserve un ensemble de bignums temporaires avec une liste liée, tandis que le BN_STACK
gère le cadre de pile.
sur Créer
Un exemple BN_CTX
ctx
est créé avec BN_CTX_new()
. Une fonction doit appeler BN_CTX_start()
pour obtenir une nouvelle trame de pile en premier. En appelant BN_CTX_get(ctx)
, OpenSSL cherche un bignum inutilisé dans le BN_POOL
de ctx
. S'il n'y a pas de temp bignum disponible, OpenSSL en crée un et le lie à la liste liée. Cela doit être fait avant de passer ctx
comme argument à d'autres fonctions.
Bien sûr, il existe un mécanisme pour empêcher l'utilisateur de créer trop de bignums temporaires. Le nombre prédéfini de bignums que vous pouvez créer dans un BN_POOL
est 16. Une fois la limite dépassée, une erreur de segmentation probable se produira au hasard dans la bibliothèque OpenSSL.
Sur la sortie
Une fois la fonction se fait avec l'instance BIGNUM il a obtenu de ctx
et est prêt à sortir, BN_CTX_end()
est appelé à libérer bignums temporaires, ce qui signifie que ces bignums deviennent « inutilisées » et peuvent être demandé par le prochain BN_CTX_get()
.
Enfin, probablement après plusieurs reprises de BN_CTX_start()
et BN_CTX_end()
, BN_CTX_end()
est appelé à libérer la structure BN_STACK
et bignums libres claires dans BN_POOL
.
Exemple de code
void foo(){
BN_CTX* ctx;
ctx = BN_CTX_new();
/* Using BIGNUM context in a series of BIGNUM operations */
bar(ctx);
bar(ctx);
bar(ctx);
/* Using BIGNUM context in a function called in loops */
while(/*condition*/){
bar(ctx);
}
BN_CTX_free(ctx);
}
Et voici la fonction bar()
void bar(BN_CTX* ctx){
BIGNUM *bn;
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
/* Do something with bn */
BN_CTX_end(ctx);
}
La fonction foo()
crée un nouveau contexte de BIGNUM et passer comme argument pour fonctionner bar()
. Lors de la première fois bar()
appelle BN_CTX_get()
, un bignum temporaire est créé et stocké dans le BN_POOL
et est retourné. BN_CTX_get()
dans le prochain bar()
ne créera pas de nouveau bignum mais à la place renvoie celui qu'il a créé en premier lieu. Ce bignum temporaire sera finalement libéré par BN_CTX_free()
en foo()
.
Conclusion
Quand la performance est dans le souci, utilisez BN_CTX
pour sauver la tête de la création BIGNUM en le faisant passer à des fonctions qui
- supposera des structures Bignum pour tenir des numéros temporaires grands et
- sont appelés séquentiellement pour effectuer certaines opérations bignum, ou
- sont appelés à plusieurs reprises dans des boucles. Sachez qu'il y a une limitation pour le nombre de bignums stockés dans
BN_CTX
Si les performances ne sont pas un problème, l'utilisation de
bn = BN_new();
if (bn)
BN_free(bn);
est très bien.
À quoi sert le cadre de la pile? – updogliu
Puisqu'un objet BN_CTX 'ctx' peut passer des fonctions aux fonctions, le cadre de la pile est un tas d'information utilisé pour suivre la profondeur de ces appels de fonction (qui passent' ctx' comme argument), et la taille de la mémoire allouée à 'ctx'. – ChiaraHsieh
Je suppose que c'est pour libérer des variables tmp fonction par fonction. S'il y a une fonction utilise deux tmp BIGNUMs 'bn1 = BN_CTX_get (ctx); bn2 = BN_CTX_get (ctx); 'Il n'y a aucun moyen (pour moi) de libérer 'bn1' mais pas' bn2'. Ils ne peuvent être sortis ensemble que sur BN_CTX_end. L'information de cadre de pile est de se rappeler que cette fonction utilise deux tmps 'bn1' et' bn2', je devine. – updogliu