Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't #include standard library headers unconditionally #1461

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Expand Up @@ -80,10 +80,10 @@ jobs:
- env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' }
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
- env_vars: { RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DDETERMINISTIC -DSECP256K1_HAVE_STDIO_H=0' }
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
- env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes'}
- env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2, CPPFLAGS: '-DSECP256K1_HAVE_STDLIB_H=0', EXTRAFLAGS='--enable-external-default-callbacks'}
- env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
cc:
- 'gcc'
Expand Down
99 changes: 94 additions & 5 deletions include/secp256k1.h
Expand Up @@ -122,6 +122,46 @@ typedef int (*secp256k1_nonce_function)(
# endif
# endif

/* SECP_HAVE_X is 1 iff standard library header X is available.
*
* We guess the values of HAVE_X here for various X. You can always override our
* guess by providing a definition of the respective macro.
*
* Note to developers of the library: All SECP256K1_HAVE_X macros will always be
* defined after this section, so use #if instead #ifdef to check them. */
#if !defined(SECP256K1_HAVE_STDIO_H)
# if defined(__has_include)
# define SECP256K1_HAVE_STDIO_H (__has_include(<stdio.h>))
# elif defined(__STDC_HOSTED__)
# define SECP256K1_HAVE_STDIO_H __STDC_HOSTED__
# else
/* Unreachable with a confirming compiler. Guess "yes" as a last resort. */
# define SECP256K1_HAVE_STDIO_H 1
# endif
# if !SECP256K1_HAVE_STDIO_H && defined(SECP256K1_BUILD) && !defined(USE_EXTERNAL_DEFAULT_CALLBACKS)
# pragma message( \
"<stdio.h> appears unavailable, " \
"disabling debugging output for fatal errors in libsecp256k1. " \
"(#define SECP256K1_HAVE_STDIO_H 0 to suppress this message.)")
# endif
#endif
#if !defined(SECP256K1_HAVE_STDLIB_H)
# if defined(__has_include)
# define SECP256K1_HAVE_STDLIB_H (__has_include(<stdlib.h>))
# elif defined(__STDC_HOSTED__)
# define SECP256K1_HAVE_STDLIB_H __STDC_HOSTED__
# else
/* Unreachable with a confirming compiler. Guess "yes" as a last resort. */
# define SECP256K1_HAVE_STDLIB_H 1
# endif
# if !SECP256K1_HAVE_STDLIB_H && defined(SECP256K1_BUILD)
# pragma message( \
"<stdlib.h> appears unavailable, " \
"disabling dynamic memory allocation in libsecp256k1. " \
"(#define SECP256K1_HAVE_STDLIB_H 0 to suppress this message.)")
# endif
#endif

/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
Expand Down Expand Up @@ -190,6 +230,17 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_DEPRECATED(_msg)
#endif

/* Attribute for marking functions, types, and variables as unavailable */
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
# if __has_attribute(__unavailable__)
# define SECP256K1_UNAVAILABLE(_msg) __attribute__ ((__unavailable__(_msg)))
# else
# define SECP256K1_UNAVAILABLE(_msg)
# endif
#else
# define SECP256K1_UNAVAILABLE(_msg)
#endif

/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
Expand Down Expand Up @@ -285,7 +336,15 @@ SECP256K1_API void secp256k1_selftest(void);
*/
SECP256K1_API secp256k1_context *secp256k1_context_create(
unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
) SECP256K1_WARN_UNUSED_RESULT
#if !SECP256K1_HAVE_STDLIB_H
SECP256K1_UNAVAILABLE(
"Needs malloc/free but <stdlib.h> seems unavailable on this platform, "
"see secp256k1_prealloc.h for alternatives. "
"(#define SECP256K1_HAVE_STDLIB_H 1 to override.)"
)
#endif
;

/** Copy a secp256k1 context object (into dynamically allocated memory).
*
Expand All @@ -301,7 +360,15 @@ SECP256K1_API secp256k1_context *secp256k1_context_create(
*/
SECP256K1_API secp256k1_context *secp256k1_context_clone(
const secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT
#if !SECP256K1_HAVE_STDLIB_H
SECP256K1_UNAVAILABLE(
"Needs malloc/free but <stdlib.h> seems unavailable on this platform, "
"see secp256k1_prealloc.h for alternatives. "
"(#define SECP256K1_HAVE_STDLIB_H 1 to override.)"
)
#endif
;

/** Destroy a secp256k1 context object (created in dynamically allocated memory).
*
Expand All @@ -319,7 +386,15 @@ SECP256K1_API secp256k1_context *secp256k1_context_clone(
*/
SECP256K1_API void secp256k1_context_destroy(
secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1);
) SECP256K1_ARG_NONNULL(1)
#if !SECP256K1_HAVE_STDLIB_H
SECP256K1_UNAVAILABLE(
"Needs malloc/free but <stdlib.h> seems unavailable on this platform, "
"see secp256k1_prealloc.h for alternatives. "
"(#define SECP256K1_HAVE_STDLIB_H 1 to override.)"
)
#endif
;

/** Set a callback function to be called when an illegal argument is passed to
* an API call. It will only trigger for violations that are mentioned
Expand Down Expand Up @@ -402,7 +477,14 @@ SECP256K1_API void secp256k1_context_set_error_callback(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create(
const secp256k1_context *ctx,
size_t size
) SECP256K1_ARG_NONNULL(1);
) SECP256K1_ARG_NONNULL(1)
#if !SECP256K1_HAVE_STDLIB_H
SECP256K1_UNAVAILABLE(
"Needs malloc/free but <stdlib.h> seems unavailable on this platform. "
"(#define SECP256K1_HAVE_STDLIB_H 1 to override.)"
)
#endif
;

/** Destroy a secp256k1 scratch space.
*
Expand All @@ -413,7 +495,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_sc
SECP256K1_API void secp256k1_scratch_space_destroy(
const secp256k1_context *ctx,
secp256k1_scratch_space *scratch
) SECP256K1_ARG_NONNULL(1);
) SECP256K1_ARG_NONNULL(1)
#if !SECP256K1_HAVE_STDLIB_H
SECP256K1_UNAVAILABLE(
"Needs malloc/free but <stdlib.h> seems unavailable on this platform. "
"(#define SECP256K1_HAVE_STDLIB_H 1 to override.)"
)
#endif
;

/** Parse a variable-length public key into the pubkey object.
*
Expand Down
2 changes: 1 addition & 1 deletion src/hash.h
Expand Up @@ -7,7 +7,7 @@
#ifndef SECP256K1_HASH_H
#define SECP256K1_HASH_H

#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>

typedef struct {
Expand Down
2 changes: 1 addition & 1 deletion src/hash_impl.h
Expand Up @@ -10,7 +10,7 @@
#include "hash.h"
#include "util.h"

#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

Expand Down
2 changes: 2 additions & 0 deletions src/modinv32.h
Expand Up @@ -7,6 +7,8 @@
#ifndef SECP256K1_MODINV32_H
#define SECP256K1_MODINV32_H

#include <stdint.h>

#include "util.h"

/* A signed 30-bit limb representation of integers.
Expand Down
15 changes: 10 additions & 5 deletions src/modinv32_impl.h
Expand Up @@ -8,11 +8,8 @@
#define SECP256K1_MODINV32_IMPL_H

#include "modinv32.h"

#include "util.h"

#include <stdlib.h>

/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
Expand All @@ -21,6 +18,14 @@
*/

#ifdef VERIFY
/* Helper function to compute the absolute value of an int32_t.
* (We don't use abs/labs/llabs as they depend on the int sizes and require stdlib.h.) */
static int64_t secp256k1_modinv32_abs(int32_t v) {
VERIFY_CHECK(v > INT32_MIN);
if (v < 0) return -v;
return v;
}

jonasnick marked this conversation as resolved.
Show resolved Hide resolved
static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}};

/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */
Expand Down Expand Up @@ -415,8 +420,8 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
VERIFY_CHECK(secp256k1_modinv32_abs(u) <= (M30 + 1 - secp256k1_modinv32_abs(v))); /* |u|+|v| <= 2^30 */
VERIFY_CHECK(secp256k1_modinv32_abs(q) <= (M30 + 1 - secp256k1_modinv32_abs(r))); /* |q|+|r| <= 2^30 */

/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31;
Expand Down
2 changes: 1 addition & 1 deletion src/modinv64_impl.h
Expand Up @@ -28,7 +28,7 @@ typedef struct {

#ifdef VERIFY
/* Helper function to compute the absolute value of an int64_t.
* (we don't use abs/labs/llabs as it depends on the int sizes). */
* (We don't use abs/labs/llabs as they depend on the int sizes and require stdlib.h.) */
static int64_t secp256k1_modinv64_abs(int64_t v) {
VERIFY_CHECK(v > INT64_MIN);
if (v < 0) return -v;
Expand Down
4 changes: 4 additions & 0 deletions src/scratch_impl.h
Expand Up @@ -7,9 +7,12 @@
#ifndef SECP256K1_SCRATCH_IMPL_H
#define SECP256K1_SCRATCH_IMPL_H

#include <string.h>

#include "util.h"
#include "scratch.h"

#if SECP256K1_HAVE_STDLIB_H
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch));
void *alloc = checked_malloc(error_callback, base_alloc + size);
Expand All @@ -34,6 +37,7 @@ static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback,
free(scratch);
}
}
#endif

static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) {
if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) {
Expand Down
8 changes: 8 additions & 0 deletions src/secp256k1.c
Expand Up @@ -137,6 +137,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
return ret;
}

#if SECP256K1_HAVE_STDLIB_H
secp256k1_context* secp256k1_context_create(unsigned int flags) {
size_t const prealloc_size = secp256k1_context_preallocated_size(flags);
secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size);
Expand All @@ -147,6 +148,7 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) {

return ctx;
}
#endif

secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) {
secp256k1_context* ret;
Expand All @@ -159,6 +161,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context*
return ret;
}

#if SECP256K1_HAVE_STDLIB_H
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
secp256k1_context* ret;
size_t prealloc_size;
Expand All @@ -171,6 +174,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
ret = secp256k1_context_preallocated_clone(ctx, ret);
return ret;
}
#endif

void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
Expand All @@ -183,6 +187,7 @@ void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
}

#if SECP256K1_HAVE_STDLIB_H
void secp256k1_context_destroy(secp256k1_context* ctx) {
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));

Expand All @@ -194,6 +199,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
secp256k1_context_preallocated_destroy(ctx);
free(ctx);
}
#endif

void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
/* We compare pointers instead of checking secp256k1_context_is_proper() here
Expand All @@ -219,6 +225,7 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
ctx->error_callback.data = data;
}

#if SECP256K1_HAVE_STDLIB_H
secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
VERIFY_CHECK(ctx != NULL);
return secp256k1_scratch_create(&ctx->error_callback, max_size);
Expand All @@ -228,6 +235,7 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
VERIFY_CHECK(ctx != NULL);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
#endif

/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
* of the software.
Expand Down
29 changes: 25 additions & 4 deletions src/util.h
Expand Up @@ -9,16 +9,22 @@

#include "../include/secp256k1.h"

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#if SECP256K1_HAVE_STDIO_H
# include <stdio.h>
#endif
#if SECP256K1_HAVE_STDLIB_H
# include <stdlib.h>
#endif

#define STR_(x) #x
#define STR(x) STR_(x)
#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))

#if SECP256K1_HAVE_STDIO_H
/* Debug helper for printing arrays of unsigned char. */
#define PRINT_BUF(buf, len) do { \
printf("%s[%lu] = ", #buf, (unsigned long)len); \
Expand All @@ -38,6 +44,7 @@ static void print_buf_plain(const unsigned char *buf, size_t len) {
}
printf("\n}\n");
}
#endif

# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(2,7)
Expand Down Expand Up @@ -73,15 +80,27 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
cb->fn(text, (void*)cb->data);
}

#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS
#if !SECP256K1_HAVE_STDLIB_H && !defined(USE_EXTERNAL_DEFAULT_CALLBACKS)
# error "<stdlib.h> is not available. You need to use external default callbacks, see the documentation of secp256k1_context_set_illegal_callback."
#endif

#if SECP256K1_HAVE_STDLIB_H
static void secp256k1_default_illegal_callback_fn(const char* str, void* data) {
(void)data;
#if SECP256K1_HAVE_STDIO_H
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
#else
(void)str;
#endif
abort();
}
static void secp256k1_default_error_callback_fn(const char* str, void* data) {
(void)data;
#if SECP256K1_HAVE_STDIO_H
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
#else
(void)str;
#endif
abort();
}
#else
Expand Down Expand Up @@ -139,13 +158,15 @@ static const secp256k1_callback default_error_callback = {
#define VERIFY_CHECK(cond)
#endif

#if SECP256K1_HAVE_STDLIB_H
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
void *ret = malloc(size);
if (ret == NULL) {
secp256k1_callback_call(cb, "Out of memory");
}
return ret;
}
#endif

#if defined(__BIGGEST_ALIGNMENT__)
#define ALIGNMENT __BIGGEST_ALIGNMENT__
Expand Down