Also add a check to find-doc-nits for HISTORY sections.
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26188)
.PHONY: doc-nits md-nits
doc-nits: build_generated_pods ## Evaluate OpenSSL documentation
- $(PERL) $(SRCDIR)/util/find-doc-nits -c -n -l -e
+ $(PERL) $(SRCDIR)/util/find-doc-nits -c -n -l -e -i
# This uses "mdl", the markdownlint application, which is written in ruby.
# The source is at https://github.com/markdownlint/markdownlint
make: *** [Makefile:3833: doc-nits] Error 1
```
+Additionally, public symbols added should contain an entry in the HISTORY
+section of their documentation explaining the exact OpenSSL version in which
+they have appeared for the first time. The option -i for "find-doc-nits"
+can be utilized to check for this. A completely new documentation file
+should also contain a HISTORY section with wording along this line, e.g.
+"These functions have been added in OpenSSL version xxx.".
+
Summary
-------
ASYNC_start_job, ASYNC_pause_job, ASYNC_get_current_job, ASYNC_get_wait_ctx(),
ASYNC_block_pause(), ASYNC_unblock_pause() and ASYNC_is_capable() were first
added in OpenSSL 1.1.0.
+ASYNC_set_mem_functions(), ASYNC_get_mem_functions() were added
+in OpenSSL 3.2.
=head1 COPYRIGHT
=head1 HISTORY
-The SSL_get_rpoll_descriptor() and SSL_get_wpoll_descriptor() functions were
+The BIO_get_rpoll_descriptor() and BIO_get_wpoll_descriptor() functions were
added in OpenSSL 3.2.
=head1 COPYRIGHT
-Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
L<BIO_s_bio(3)>, L<bio(7)>
+=head1 HISTORY
+
+BIO_s_dgram_pair(), BIO_new_bio_dgram_pair() were added in OpenSSL 3.2.
+
=head1 COPYRIGHT
-Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
=head1 COPYRIGHT
-Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
=head1 HISTORY
-CRYPTO_atomic_store() was added in OpenSSL 3.4.0
+CRYPTO_atomic_load_int(), OSSL_set_max_threads(), OSSL_get_max_threads(),
+OSSL_get_thread_support_flags() were added in OpenSSL 3.2.
+
+CRYPTO_atomic_store(), CRYPTO_atomic_add64(), CRYPTO_atomic_and()
+were added in OpenSSL 3.4.
=head1 COPYRIGHT
=head1 HISTORY
+EC_GROUP_to_params() was added in OpenSSL 3.2.
+
=over 2
=item *
=head1 COPYRIGHT
-Copyright 2013-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2013-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
=head1 HISTORY
+ERR_count_to_mark() was added in OpenSSL 3.2.
ERR_pop() was added in OpenSSL 3.3.
=head1 COPYRIGHT
-Copyright 2003-2023 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2003-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
occurs. In particular, -2 is returned when the function isn't supported by
the B<EVP_I<TYPE>> implementation.
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.4.
+
=head1 COPYRIGHT
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
In OpenSSL 3.1, B<DEFINE_LHASH_OF_EX>() was introduced and B<DEFINE_LHASH_OF>()
was deprecated.
+OPENSSL_LH_doall_arg_thunk(), OPENSSL_LH_set_thunks() were added in
+OpenSSL 3.3.
+
=head1 COPYRIGHT
Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
were deprecated in OpenSSL 3.0.
The memory-leak checking has been deprecated in OpenSSL 3.0 in favor of
clang's memory and leak sanitizer.
-OPENSSL_aligned_alloc(), CRYPTO_aligned_alloc() were added in OpenSSL 3.4.0
+OPENSSL_aligned_alloc(), CRYPTO_aligned_alloc(), OPENSSL_strtoul() were
+added in OpenSSL 3.4.
=head1 COPYRIGHT
PEM_read_bio_DHparams(), PEM_read_DHparams(),
PEM_write_bio_DHparams() and PEM_write_DHparams() were deprecated in 3.0.
+PEM_read_bio_X509_ACERT(), PEM_read_X509_ACERT(),
+PEM_write_bio_X509_ACERT(), PEM_write_X509_ACERT()
+were added in OpenSSL 3.4.
=head1 COPYRIGHT
PKCS12_SAFEBAG_set0_attrs() does not return a value.
+=head1 HISTORY
+
+This function was added in OpenSSL 3.2.
+
=head1 COPYRIGHT
-Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
=head1 HISTORY
-This call was added in OpenSSL 3.4.
+This function was added in OpenSSL 3.4.
=head1 COPYRIGHT
L<X509_sign(3)>,
L<X509_verify_cert(3)>
+=head1 HISTORY
+
+X509_ACERT_get_ext_d2i(), X509_ACERT_add1_ext_i2d(),
+X509_ACERT_get0_extensions() were added in OpenSSL 3.4.
+
=head1 COPYRIGHT
Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved.
The functions DSAparams_dup(), RSAPrivateKey_dup() and RSAPublicKey_dup() were
deprecated in 3.0.
+CMS_EnvelopedData_it(), CMS_SignedData_free(), CMS_SignedData_new()
+were added in OpenSSL 3.2.
+
+DIST_POINT_NAME_dup(), OSSL_IETF_ATTR_SYNTAX_free(), OSSL_IETF_ATTR_SYNTAX_it(),
+OSSL_IETF_ATTR_SYNTAX_new(), OSSL_ATTRIBUTES_SYNTAX_free(),
+OSSL_ATTRIBUTES_SYNTAX_it(), OSSL_ATTRIBUTES_SYNTAX_new(),
+OSSL_BASIC_ATTR_CONSTRAINTS_free(), OSSL_BASIC_ATTR_CONSTRAINTS_it(),
+OSSL_BASIC_ATTR_CONSTRAINTS_new(), OSSL_CMP_ATAVS_new(), OSSL_CMP_ATAVS_free(),
+OSSL_CMP_ATAVS_it(), OSSL_CMP_CRLSTATUS_free(), OSSL_CRMF_CERTTEMPLATE_dup(),
+OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup(), OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(),
+OSSL_TARGET_free(), OSSL_TARGET_it(), OSSL_TARGET_new(),
+OSSL_TARGETING_INFORMATION_free(), OSSL_TARGETING_INFORMATION_it(),
+OSSL_TARGETING_INFORMATION_new(), OSSL_TARGETS_free(),
+OSSL_TARGETS_it(), OSSL_TARGETS_new(), OSSL_IETF_ATTR_SYNTAX_VALUE_free(),
+OSSL_IETF_ATTR_SYNTAX_VALUE_it(), OSSL_IETF_ATTR_SYNTAX_VALUE_new(),
+OSSL_ISSUER_SERIAL_free(), OSSL_ISSUER_SERIAL_new(),
+OSSL_OBJECT_DIGEST_INFO_free(), OSSL_OBJECT_DIGEST_INFO_new(),
+OSSL_USER_NOTICE_SYNTAX_free(), OSSL_USER_NOTICE_SYNTAX_new(),
+OSSL_USER_NOTICE_SYNTAX_it(), PBMAC1PARAM_free(), PBMAC1PARAM_it(),
+PBMAC1PARAM_new(), X509_ACERT_dup(), X509_ACERT_free(), X509_ACERT_it(),
+X509_ACERT_new(), X509_ACERT_INFO_free(), X509_ACERT_INFO_it(),
+X509_ACERT_INFO_new(), X509_ACERT_ISSUER_V2FORM_free(),
+X509_ACERT_ISSUER_V2FORM_new()
+were added in OpenSSL 3.4.
+
+OSSL_ATTRIBUTE_DESCRIPTOR_free(), OSSL_ATTRIBUTE_DESCRIPTOR_new(),
+OSSL_ATTRIBUTE_DESCRIPTOR_it(), OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX_free(),
+OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX_it(), OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX_new(),
+OSSL_HASH_free(), OSSL_HASH_it(), OSSL_HASH_new(), OSSL_INFO_SYNTAX_free(),
+OSSL_INFO_SYNTAX_it(), OSSL_INFO_SYNTAX_new(), OSSL_INFO_SYNTAX_POINTER_free(),
+OSSL_INFO_SYNTAX_POINTER_it(), OSSL_INFO_SYNTAX_POINTER_new(),
+OSSL_PRIVILEGE_POLICY_ID_free(), OSSL_PRIVILEGE_POLICY_ID_it(),
+OSSL_PRIVILEGE_POLICY_ID_new(), OSSL_ROLE_SPEC_CERT_ID_free(),
+OSSL_ROLE_SPEC_CERT_ID_new(), OSSL_ROLE_SPEC_CERT_ID_it(),
+OSSL_ROLE_SPEC_CERT_ID_SYNTAX_free(), OSSL_ROLE_SPEC_CERT_ID_SYNTAX_new(),
+OSSL_ROLE_SPEC_CERT_ID_SYNTAX_it(), OSSL_DAY_TIME_BAND_free(),
+OSSL_DAY_TIME_BAND_it(), OSSL_DAY_TIME_BAND_new(),
+OSSL_DAY_TIME_free(), OSSL_DAY_TIME_it(), OSSL_DAY_TIME_new(),
+OSSL_NAMED_DAY_free(), OSSL_NAMED_DAY_it(), OSSL_NAMED_DAY_new(),
+OSSL_TIME_PERIOD_free(), OSSL_TIME_PERIOD_it(), OSSL_TIME_PERIOD_new(),
+OSSL_TIME_SPEC_ABSOLUTE_free(), OSSL_TIME_SPEC_ABSOLUTE_it(),
+OSSL_TIME_SPEC_ABSOLUTE_new(), OSSL_TIME_SPEC_DAY_free(),
+OSSL_TIME_SPEC_DAY_it(), OSSL_TIME_SPEC_DAY_new(),
+OSSL_TIME_SPEC_MONTH_free(), OSSL_TIME_SPEC_MONTH_it(),
+OSSL_TIME_SPEC_MONTH_new(), OSSL_TIME_SPEC_TIME_free(),
+OSSL_TIME_SPEC_TIME_it(), OSSL_TIME_SPEC_TIME_new(),
+OSSL_TIME_SPEC_WEEKS_free(), OSSL_TIME_SPEC_WEEKS_it(),
+OSSL_TIME_SPEC_WEEKS_new(), OSSL_TIME_SPEC_X_DAY_OF_free(),
+OSSL_TIME_SPEC_X_DAY_OF_it(), OSSL_TIME_SPEC_X_DAY_OF_new(),
+OSSL_TIME_SPEC_free(), OSSL_TIME_SPEC_it(), OSSL_TIME_SPEC_new()
+were added in OpenSSL 3.5.
+
=head1 COPYRIGHT
Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
=head1 HISTORY
-These functions are available in all versions of OpenSSL.
-
X509_get_notBefore() and X509_get_notAfter() were deprecated in OpenSSL
-1.1.0
+1.1.0.
+
+X509_ACERT_get0_notBefore(), X509_ACERT_get0_notAfter(),
+X509_ACERT_set1_notBefore(), X509_ACERT_set1_notAfter()
+were added in OpenSSL 3.4.
=head1 COPYRIGHT
X509_NAME_hash() was turned into a macro and deprecated in OpenSSL 3.0.
+X509_ACERT_get0_issuerName(), X509_ACERT_set1_issuerName()
+were added in OpenSSL 3.4.
+
=head1 COPYRIGHT
Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved.
X509_get_version(), X509_REQ_get_version() and X509_CRL_get_version() are
functions in OpenSSL 1.1.0, in previous versions they were macros.
+X509_ACERT_get_version(), X509_ACERT_set_version()
+were added in OpenSSL 3.4.
+
=head1 COPYRIGHT
Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved.
serialization. This is because some objects cache the encoding for
efficiency reasons.
+=head1 HISTORY
+
+d2i_OSSL_ATTRIBUTES_SYNTAX(), d2i_OSSL_BASIC_ATTR_CONSTRAINTS(),
+d2i_OSSL_CMP_ATAVS(), d2i_OSSL_IETF_ATTR_SYNTAX(),
+d2i_OSSL_TARGET(), d2i_OSSL_TARGETING_INFORMATION(),
+d2i_OSSL_TARGETS(), d2i_OSSL_USER_NOTICE_SYNTAX(),
+d2i_PBMAC1PARAM(), d2i_X509_ACERT(), d2i_X509_ACERT_bio(),
+d2i_X509_ACERT_fp(), i2d_OSSL_ATTRIBUTES_SYNTAX(),
+i2d_OSSL_BASIC_ATTR_CONSTRAINTS(), i2d_OSSL_CMP_ATAVS(),
+i2d_OSSL_IETF_ATTR_SYNTAX(), i2d_OSSL_TARGET(),
+i2d_OSSL_TARGETING_INFORMATION(), i2d_OSSL_TARGETS(),
+i2d_OSSL_USER_NOTICE_SYNTAX(), i2d_PBMAC1PARAM(), i2d_X509_ACERT(),
+i2d_X509_ACERT_bio(), i2d_X509_ACERT_fp()
+were added in OpenSSL 3.4.
+
+d2i_OSSL_ATTRIBUTE_DESCRIPTOR(), d2i_OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX(),
+d2i_OSSL_HASH(), d2i_OSSL_INFO_SYNTAX(),
+d2i_OSSL_INFO_SYNTAX_POINTER(), d2i_OSSL_PRIVILEGE_POLICY_ID(),
+d2i_OSSL_ROLE_SPEC_CERT_ID(), d2i_OSSL_ROLE_SPEC_CERT_ID_SYNTAX(),
+i2d_OSSL_ATTRIBUTE_DESCRIPTOR(), i2d_OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX(),
+i2d_OSSL_HASH(), i2d_OSSL_INFO_SYNTAX(),
+i2d_OSSL_INFO_SYNTAX_POINTER(), i2d_OSSL_PRIVILEGE_POLICY_ID(),
+i2d_OSSL_ROLE_SPEC_CERT_ID(), i2d_OSSL_ROLE_SPEC_CERT_ID_SYNTAX(),
+d2i_OSSL_DAY_TIME(), d2i_OSSL_DAY_TIME_BAND(), d2i_OSSL_NAMED_DAY(),
+d2i_OSSL_TIME_PERIOD(), d2i_OSSL_TIME_SPEC(),
+d2i_OSSL_TIME_SPEC_ABSOLUTE(), d2i_OSSL_TIME_SPEC_DAY(),
+d2i_OSSL_TIME_SPEC_MONTH(), d2i_OSSL_TIME_SPEC_TIME(),
+d2i_OSSL_TIME_SPEC_WEEKS(), d2i_OSSL_TIME_SPEC_X_DAY_OF(),
+i2d_OSSL_DAY_TIME(), i2d_OSSL_DAY_TIME_BAND(),
+i2d_OSSL_NAMED_DAY(), i2d_OSSL_TIME_PERIOD(),
+i2d_OSSL_TIME_SPEC(), i2d_OSSL_TIME_SPEC_ABSOLUTE(),
+i2d_OSSL_TIME_SPEC_DAY(), i2d_OSSL_TIME_SPEC_MONTH(),
+i2d_OSSL_TIME_SPEC_TIME(), i2d_OSSL_TIME_SPEC_WEEKS(),
+i2d_OSSL_TIME_SPEC_X_DAY_OF()
+were added in OpenSSL 3.5.
+
=head1 COPYRIGHT
Copyright 1998-2024 The OpenSSL Project Authors. All Rights Reserved.
our($opt_u);
our($opt_v);
our($opt_c);
+our($opt_i);
# Print usage message and exit.
sub help {
-m Name(s) of manuals to focus on. Default: man1,man3,man5,man7
-n Print nits in POD pages
-o Causes -e/-v to count symbols added since 1.1.1 as new (implies -v)
+ -i Checks for history entries available for symbols added since 3.0.0 as new
-u Count undocumented functions
-v Count new undocumented functions
EOF
exit;
}
-getopts('cdehlm:nouv');
+getopts('cdehlm:noiuv');
help() if $opt_h;
$opt_u = 1 if $opt_d;
if $contents =~ /=head1 $before.*=head1 $section/ms;
}
+# Check if HISTORY section is present and functionname ($2) is present in it
+# or a generic "(f)unction* added" term hints at several new functions in
+# the documentation (yes, this is an approximation only but it works :)
+sub find_functionname_in_history_section {
+ my $contents = shift;
+ my $functionname = shift;
+ my (undef, $rest) = split('=head1 HISTORY\s*', $contents);
+
+ if (not $rest) {
+ # No HISTORY section is a clear error now
+ return 0;
+ }
+ else {
+ my ($histsect, undef) = split('=head1 COPYRIGHT\s*', $rest);
+ if (index($histsect, $functionname) == -1) {
+ # OK, functionname is not in HISTORY section...
+ # last try: Check for presence of "*unction*added*"
+ return 0 if (not $histsect =~ /unction.*added.*/g);
+ }
+ }
+ return 1;
+}
+
# Check if a =head1 is duplicated, or a =headX is duplicated within a
# =head1. Treats =head2 =head3 as equivalent -- it doesn't reset the head3
# sets if it finds a =head2 -- but that is good enough for now. Also check
# Any of these values except 'public' may be prefixed with 'missing_'
# to indicate that they are known to be missing.
my %state;
+# history contains the same as state above for entries with version info != 3_0_0
+my %history;
# %missing is affected by loading util/missing*.txt. Values may be one of:
# 'crypto' : belongs in libcrypto (loaded from libcrypto.num)
# 'ssl' : belongs in libssl (loaded from libssl.num)
next if /^#/;
next if /\bNOEXIST\b/;
my @fields = split();
+ if ($type && ($type eq "crypto" || $type eq "ssl")) {
+ # 3rd field is version
+ if (not $fields[2] eq "3_0_0") {
+ $history{$fields[0].'(3)'} = $type.$fields[2];
+ }
+ }
die "Malformed line $. in $file: $_"
if scalar @fields != 2 && scalar @fields != 4;
$state{$fields[0].'(3)'} = $type // 'internal';
my $count = 0;
foreach my $func ( grep { $state{$_} eq $type } sort keys %state ) {
+ err("$type:", "function $func not in any history section")
+ if ($opt_i && defined $history{$func});
next if defined $name_map{$func}
|| defined $missing{$func};
my $name_sec = "$name($section)";
if ( !defined $name_map{$name_sec} ) {
$name_map{$name_sec} = $filename;
+ if ($history{$name_sec}) {
+ my $funcname = $name_sec;
+ my $contents = $podinfo{contents};
+ $funcname =~ s/\(.*//;
+ if (find_functionname_in_history_section($contents, $funcname)) {
+ # mark this function as found/no longer of interest
+ $history{$name_sec} = undef;
+ }
+ }
$state{$name_sec} //=
( $filename =~ /\/internal\// ? 'internal' : 'public' )
if $is_generic;