Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/check_sast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ jobs:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
languages: ${{ matrix.language }}
build-mode: none
config-file: .github/codeql/codeql-config.yml

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
category: '/language:${{ matrix.language }}'
upload: False
Expand Down Expand Up @@ -127,7 +127,7 @@ jobs:
continue-on-error: true

- name: Upload SARIF
uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
sarif_file: sarif-results/${{ matrix.language }}.sarif
continue-on-error: true
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}
- uses: taiki-e/install-action@67729d5c413db75907f0ad1e39bb04b9c868ff60 # v2.85.7
- uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
ruby-version: '3.1'
bundler: none

- uses: taiki-e/install-action@67729d5c413db75907f0ad1e39bb04b9c868ff60 # v2.85.7
- uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
1 change: 1 addition & 0 deletions bignum.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "ruby/thread.h"
#include "ruby/util.h"
#include "ruby_assert.h"
#include "vm_core.h" /* for GET_EC() */

#if USE_GMP
RBIMPL_WARNING_PUSH()
Expand Down
12 changes: 12 additions & 0 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,17 @@ module_descendants_add(VALUE klass, struct descendants_traverse_data *data)
rb_class_foreach_subclass(klass, module_descendants_recursive, (VALUE)data);
}

// an include done in another box is not in the ancestors here if the includer
// has a classext per box, e.g. a module included into a builtin class
static bool
iclass_in_ancestors_p(VALUE iclass, VALUE includer)
{
for (VALUE p = includer; p; p = RCLASS_SUPER(p)) {
if (p == iclass) return true;
}
return false;
}

static void
module_descendants_recursive(VALUE entry, VALUE v)
{
Expand All @@ -2159,6 +2170,7 @@ module_descendants_recursive(VALUE entry, VALUE v)
if (!includer || UNDEF_P(includer)) return;
if (rb_objspace_garbage_object_p(includer)) return;
if (RCLASS_SINGLETON_P(includer)) return; // e.g. Object#extend
if (!iclass_in_ancestors_p(entry, includer)) return;
module_descendants_add(includer, data);
}
else {
Expand Down
1 change: 1 addition & 0 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/compile.h"
#include "internal/coverage.h"
#include "internal/complex.h"
#include "internal/encoding.h"
#include "internal/error.h"
Expand Down
84 changes: 25 additions & 59 deletions ext/coverage/coverage.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@

************************************************/

#include "internal/gc.h"
#include "internal/coverage.h"
#include "internal/hash.h"
#include "internal/thread.h"
#include "internal/sanitizers.h"
#include "ruby.h"
#include "vm_core.h"

static enum {
IDLE,
Expand Down Expand Up @@ -42,13 +39,13 @@ rb_coverage_supported(VALUE self, VALUE _mode)
{
ID mode = RB_SYM2ID(_mode);

return RBOOL(
return (
mode == rb_intern("lines") ||
mode == rb_intern("oneshot_lines") ||
mode == rb_intern("branches") ||
mode == rb_intern("methods") ||
mode == rb_intern("eval")
);
) ? Qtrue : Qfalse;
}

/*
Expand Down Expand Up @@ -242,60 +239,30 @@ branch_coverage(VALUE branches)
return b.result;
}

/*
* Fold a single method entry's contribution into the method coverage result.
* `add` is the number of calls to attribute to it (0 is used to make sure a
* defined-but-uncalled method shows up). Entries that resolve elsewhere (e.g.
* aliases) are skipped: their calls are attributed to the original definition
* via the [owner, mid, location] key, exactly like the old heap-walk did.
*/
static void
method_coverage_add(const rb_method_entry_t *me, long add, VALUE ncoverages)
method_coverage_i(const struct rb_coverage_method_data *method, void *data)
{
VALUE data[5];
const rb_method_entry_t *me2 = rb_resolve_me_location(me, data);
if (me != me2) return;

VALUE klass = me->owner;
if (RB_TYPE_P(klass, T_ICLASS)) return;

VALUE first_lineno = data[1];
if (FIX2LONG(first_lineno) <= 0) return;

VALUE path = data[0];
VALUE ncoverage = rb_hash_aref(ncoverages, path);
if (NIL_P(ncoverage)) return;

VALUE methods = rb_hash_aref(ncoverage, ID2SYM(rb_intern("methods")));
VALUE method_id = ID2SYM(me->def->original_id);
VALUE key = rb_ary_new_from_args(6, klass, method_id, data[1], data[2], data[3], data[4]);

VALUE rcount = rb_hash_aref(methods, key);
long count = NIL_P(rcount) ? 0 : FIX2LONG(rcount);
if (!POSFIXABLE(count + add)) {
count = FIXNUM_MAX;
}
else {
count += add;
VALUE ncoverages = *(VALUE *)data;
VALUE ncoverage = rb_hash_aref(ncoverages, method->path);

if (!NIL_P(ncoverage)) {
VALUE methods = rb_hash_aref(ncoverage, ID2SYM(rb_intern("methods")));
VALUE key = rb_ary_new_from_args(6, method->owner, method->method_id,
method->first_lineno, method->first_column,
method->last_lineno, method->last_column);
VALUE rcount = method->count;
VALUE previous = rb_hash_aref(methods, key);

if (NIL_P(rcount)) rcount = LONG2FIX(0);
if (NIL_P(previous)) previous = LONG2FIX(0);
if (!POSFIXABLE(FIX2LONG(rcount) + FIX2LONG(previous))) {
rcount = LONG2FIX(FIXNUM_MAX);
}
else {
rcount = LONG2FIX(FIX2LONG(rcount) + FIX2LONG(previous));
}
rb_hash_aset(methods, key, rcount);
}
rb_hash_aset(methods, key, LONG2FIX(count));
}

/* me_set entries: every defined method, so uncalled ones appear with count 0. */
static int
method_coverage_me_i(VALUE key, VALUE value, VALUE ncoverages)
{
method_coverage_add((const rb_method_entry_t *)key, 0, ncoverages);
return ST_CONTINUE;
}

/* cme2counter entries: call counts, attributed to the definition's key. */
static int
method_coverage_count_i(VALUE key, VALUE value, VALUE ncoverages)
{
long add = FIXNUM_P(value) ? FIX2LONG(value) : 0;
method_coverage_add((const rb_method_entry_t *)key, add, ncoverages);
return ST_CONTINUE;
}

static int
Expand Down Expand Up @@ -361,8 +328,7 @@ rb_coverage_peek_result(VALUE klass)
rb_hash_foreach(coverages, coverage_peek_result_i, ncoverages);

if (current_mode & COVERAGE_TARGET_METHODS) {
if (RTEST(me_set)) rb_hash_foreach(me_set, method_coverage_me_i, ncoverages);
if (RTEST(cme2counter)) rb_hash_foreach(cme2counter, method_coverage_count_i, ncoverages);
rb_coverage_each_method(method_coverage_i, &ncoverages);
}

rb_hash_freeze(ncoverages);
Expand Down
1 change: 0 additions & 1 deletion ext/objspace/object_tracing.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

**********************************************************************/

#include "internal.h"
#include "internal/gc.h"
#include "ruby/debug.h"
#include "objspace.h"
Expand Down
8 changes: 2 additions & 6 deletions ext/objspace/objspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,16 @@
**********************************************************************/

#include "internal.h"
#include "internal/class.h"
#include "internal/compilers.h"
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/objspace.h"
#include "internal/sanitizers.h"
#include "ruby/io.h"
#include "ruby/re.h"
#include "ruby/st.h"
#include "symbol.h"

#undef rb_funcall

#include "ruby/ruby.h"
#include "objspace.h"

/*
* call-seq:
Expand Down
19 changes: 7 additions & 12 deletions ext/objspace/objspace_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,18 @@

#include "id_table.h"
#include "internal.h"
#include "internal/array.h"
#include "internal/class.h"
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/io.h"
#include "internal/objspace.h"
#include "internal/string.h"
#include "internal/sanitizers.h"
#include "symbol.h"
#include "shape.h"
#include "node.h"
#include "objspace.h"
#include "ruby/debug.h"
#include "ruby/util.h"
#include "ruby/io.h"
#include "vm_callinfo.h"
#include "vm_sync.h"

RUBY_EXTERN const char ruby_hexdigits[];

#define BUFFER_CAPACITY 4096

Expand Down Expand Up @@ -443,7 +437,7 @@ dump_object(VALUE obj, struct dump_config *dc)

switch (imemo_type(obj)) {
case imemo_callinfo:
mid = vm_ci_mid((const struct rb_callinfo *)obj);
mid = rb_imemo_callinfo_mid(obj);
if (mid != 0) {
dump_append(dc, ", \"mid\":");
dump_append_id(dc, mid);
Expand All @@ -452,9 +446,10 @@ dump_object(VALUE obj, struct dump_config *dc)

case imemo_callcache:
{
VALUE klass = ((const struct rb_callcache *)obj)->klass;
if (klass != Qundef) {
mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
struct rb_imemo_callcache_data data;
if (rb_imemo_callcache_get_data(obj, &data)) {
VALUE klass = data.klass;
mid = data.called_id;
if (mid != 0) {
dump_append(dc, ", \"called_id\":");
dump_append_id(dc, mid);
Expand Down
1 change: 1 addition & 0 deletions ext/socket/raddrinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
************************************************/

#include "rubysocket.h"
#include <signal.h>

// GETADDRINFO_IMPL == 0 : call getaddrinfo/getnameinfo directly
// GETADDRINFO_IMPL == 1 : call getaddrinfo/getnameinfo without gvl (but uncancellable)
Expand Down
21 changes: 21 additions & 0 deletions imemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ size_t rb_iseq_memsize(const rb_iseq_t *iseq);
void rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating);
void rb_iseq_free(const rb_iseq_t *iseq);

ID
rb_imemo_callinfo_mid(VALUE obj)
{
RUBY_ASSERT(imemo_type(obj) == imemo_callinfo);
return vm_ci_mid((const struct rb_callinfo *)obj);
}

bool
rb_imemo_callcache_get_data(VALUE obj, struct rb_imemo_callcache_data *data)
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;

RUBY_ASSERT(imemo_type(obj) == imemo_callcache);

if (cc->klass == Qundef) return false;

data->klass = cc->klass;
data->called_id = vm_cc_cme(cc)->called_id;
return true;
}

const char *
rb_imemo_name(enum imemo_type type)
{
Expand Down
4 changes: 4 additions & 0 deletions internal/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,8 @@ void rb_box_cleanup_local_extension(VALUE cleanup);
void rb_initialize_mandatory_boxes(void);
void rb_box_init_done(void);
void rb_box_set_gem_flags(rb_box_gem_flags_t *);

/* variable.c */
void rb_autoload_copy_table_for_box(st_table *, const rb_box_t *);

#endif /* INTERNAL_BOX_H */
50 changes: 50 additions & 0 deletions internal/coverage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef INTERNAL_COVERAGE_H /*-*-C-*-vi:se ft=c:*/
#define INTERNAL_COVERAGE_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Internal header for Coverage.
*/
#include "ruby/ruby.h"

#define COVERAGE_INDEX_LINES 0
#define COVERAGE_INDEX_BRANCHES 1

#define COVERAGE_TARGET_LINES 1
#define COVERAGE_TARGET_BRANCHES 2
#define COVERAGE_TARGET_METHODS 4
#define COVERAGE_TARGET_ONESHOT_LINES 8
#define COVERAGE_TARGET_EVAL 16

struct rb_coverage_method_data {
VALUE owner;
VALUE method_id;
VALUE path;
VALUE first_lineno;
VALUE first_column;
VALUE last_lineno;
VALUE last_column;
VALUE count;
};

typedef void rb_coverage_method_callback(const struct rb_coverage_method_data *, void *);

RUBY_SYMBOL_EXPORT_BEGIN

VALUE rb_get_coverages(void);
void rb_set_coverages(VALUE coverages, int mode, VALUE cme2counter, VALUE me_set);
void rb_clear_coverages(void);
void rb_reset_coverages(void);
void rb_resume_coverages(void);
void rb_suspend_coverages(void);
void rb_coverage_each_method(rb_coverage_method_callback callback, void *data);

RUBY_SYMBOL_EXPORT_END

int rb_get_coverage_mode(void);
VALUE rb_default_coverage(int n);

#endif /* INTERNAL_COVERAGE_H */
Loading