Skip to content

Instantly share code, notes, and snippets.

@Xliff
Created February 27, 2024 16:31
Show Gist options
  • Save Xliff/912683918767dd30bf381dbd3c2e2610 to your computer and use it in GitHub Desktop.
Save Xliff/912683918767dd30bf381dbd3c2e2610 to your computer and use it in GitHub Desktop.
Raku Segfault Bug Report - Feb 27, 2024

I have the following C code:

#include <glibtop.h>
#include <glibtop/procwd.h>
#include <glibtop/proclist.h>

#include <stdio.h>

#include <unistd.h>
#include <sys/types.h>

#include <glib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  glibtop_proclist buf;
	glibtop_proc_wd buf2;
	char **dirs, **dir;
	pid_t *pids;

  glibtop_init();

	pids = glibtop_get_proclist(&buf, GLIBTOP_KERN_PROC_ALL, 0);

  int i;
  printf("Processes: %ld\n", buf.number);
	for (i = 0; i < buf.number; i++) {
    pid_t pid = pids[i];

  	dirs = glibtop_get_proc_wd(&buf2, pid);

  	g_print("Process %u:\n"
  		" - root: '%s'\n"
  		" - exe: '%s'\n"
      " - working directories:\n",
  		(unsigned)pid, buf2.root, buf2.exe);

  	for (dir = dirs; *dir; ++dir)
  		g_print("   - '%s'\n", *dir);

  	g_strfreev(dirs);
  }

	glibtop_close();

	return 0;
}

It will print the path, executable and working directories of every running process, and will output something that looks like this:

Process 7994:
 - root: '/proc/7056/fdinfo'
 - exe: '/opt/google/chrome/chrome'
 - working directories:
   - '/proc/7056/fdinfo'
Process 8016:
 - root: '/'
 - exe: '/usr/bin/konsole'
 - working directories:
   - '/home/cbwood'
Process 8035:
 - root: '/'
 - exe: '/usr/bin/bash'
 - working directories:
   - '/home/cbwood/Projects/raku-GLib-Top'
Process 8318:
 - root: '/proc/7056/fdinfo'
 - exe: '/opt/google/chrome/chrome'
 - working directories:
   - '/proc/7056/fdinfo'

It runs perfectly, with no issues or segfaults.

Here is the standalone version of the NativeCall-enabled raku version:

use NativeCall;

constant pid_t := int32;

# cw: This works for latest ubuntu. Replace the location of your libgtop, here!
constant gtop is export ='gtop-2.0',v11;

constant GLIBTOP_KERN_PROC_ALL is export = 0;

sub glibtop_init
  returns Pointer
  is      native(gtop)
  is      export
{ * }

sub glibtop_close
  is      native(gtop)
  is      export
{ * }

class glibtop_proclist is repr<CStruct> is export {
	has uint64 $.flags  is rw;
	has uint64 $.number is rw;
	has uint64 $.total  is rw;
	has uint64 $.size   is rw;
}

# cw: 216 determined from constants
class glibtop_proc_wd is repr<CStruct> is export {
	has uint64	$.flags;
	has uint32  $.number;
	HAS uint8   @!root[216] is CArray;
	HAS uint8   @!exe[216]  is CArray;

	submethod BUILD {
	 	# @!root[$_] = 0 for 215;
	 	#  @!exe[$_] = 0 for 215;
	}

	method root ($encoding = 'utf8') {
    my @r = @!root[^216];

		nativecast( Str, CArray[uint8].new(@r) );
	}

	method exe ($encoding = 'utf8') {
    my @e = @!exe[^216];

		nativecast( Str, CArray[uint8].new(@e) );
	}

}

sub glibtop_get_proclist (
  glibtop_proclist $buf,
  int64            $which,
  int64            $arg
)
  returns CArray[pid_t]
  is      native(gtop)
  is      export
{ * }

sub glibtop_get_proc_wd (glibtop_proc_wd $buf, pid_t $pid)
  returns CArray[ CArray[uint8] ]
  is      native(gtop)
  is      export
{ * }

multi sub CStringArrayToArray (CArray[Str] $sa) is export {
  CArrayToArray($sa)
}

multi sub CArrayToArray(CArray $ca) is export {
  return Nil unless $ca;
  my ($i, @a) = (0);
  while $ca[$i] {
    @a.push: $ca[$i].clone;
    $i++;
  }
  @a;
}

sub MAIN {

  glibtop_init();

  my uint64 ($w, $a) = (GLIBTOP_KERN_PROC_ALL, 0);

  my @pids = CArrayToArray(
    glibtop_get_proclist(
      (my $buf = glibtop_proclist.new),
      $w,
      $a
    )
  );

  say("Processes: { $buf.number }");
  for @pids {
    my pid_t $p = $_;

    my $dirs = glibtop_get_proc_wd(
      (my $buf2 = glibtop_proc_wd.new),
      $p
    );

    say qq:to/OUTPUT/
      Process #{ $p }:
        - root: { $buf2.root}
        -  exe: { $buf2.exe }
        - working directories:
          { @dirs.join("\n    - ") }
      OUTPUT

  glibtop_close();
}

It does not and will segfault WAY before it gets to pid 1000. What I can get of it looks like this:

Process #6:
  - root: 
  -  exe: 


** (process:8702): WARNING **: 11:29:05.948: Could not read link /proc/8/root : Permission denied

** (process:8702): WARNING **: 11:29:05.948: Could not read link /proc/8/exe : Permission denied

** (process:8702): WARNING **: 11:29:05.948: Could not read link /proc/8/cwd : Permission denied

** (process:8702): WARNING **: 11:29:05.948: Could not read link /proc/8/task/8/cwd : Permission denied
free(): invalid pointer
./p6gtkexec: line 72:  8702 Aborted                 (core dumped) ${EXEC} --stagestats ${EXTRAS} ${INCLUDES} "$@"

Could someone please take a look at this and tell me what I might need to changed?

For the record, the CStructs involved have been SIZE verified against C. That doesn't mean that they are completely cleared from suspicion.

Thanks in advance to anyone who can take this up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment