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
3 changes: 2 additions & 1 deletion dev/design/issue-queue.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Reviewed issue queues

Snapshot: 2026-11-02, from live open issues, PRs and the #1649 phase contract.
Snapshot: 2026-11-04, from live open issues, PRs and the #1649 phase contract.
This is a bounded selection aid, not the complete backlog or fresh runtime
validation. Follow the [triage and claim protocol](../../docs/guides/issue-triage.md)
and recheck live issue comments/PRs before starting. Unlisted work is unreviewed
Expand Down Expand Up @@ -29,6 +29,7 @@ resolved before implementation. No new pass or failure is asserted here.
| Hash dereference assignment | [#1958](https://github.com/fglock/PerlOnJava/issues/1958) Undefined-reference autovivification | Normal / Active | Shared-runtime fix and focused regression pass on both backends; full `make` passes in [PR #1960](https://github.com/fglock/PerlOnJava/pull/1960). [Current claim](https://github.com/fglock/PerlOnJava/issues/1958#issuecomment-6626463414). Object-Hybrid 0.07's follow-on generated `can` dispatch failure is also addressed in that PR under #1959. |
| Dynamic class method lookup | [#1959](https://github.com/fglock/PerlOnJava/issues/1959) Object::Hybrid `tieable` promotion | Normal / Active | Generated `HASH_STATIC` declares a bodyless `can`; route it through that class's `AUTOLOAD` when present. Focused reproducer and full `make` pass on both backends. The full upstream suite advances beyond this failure but later exits at `IO::File::FILENO` (separate behavior). Candidate fix is in [PR #1960](https://github.com/fglock/PerlOnJava/pull/1960). |
| Scalar introspection | [#1954](https://github.com/fglock/PerlOnJava/issues/1954) `Scalar::Util::isdual` booleans | Normal / Active | Mars 0.05 passes on system Perl and failed assertions 10–11 on both PerlOnJava backends (run `20261103-123832-91742`). [Draft PR #1956](https://github.com/fglock/PerlOnJava/pull/1956) recognizes BOOLEAN values; focused boolean, explicit-dualvar and plain-string coverage plus all 13 Mars assertions pass on both backends, and full `make` passes. |
| Special-variable setters | [#1972](https://github.com/fglock/PerlOnJava/issues/1972) Writable effective UID (`$>`) | Normal / Active | `Proc-DaemonLite` 0.01 passes the full system-Perl suite but its `$> = $<` cleanup fails on both PerlOnJava backends (CPAN run `20261104-151051-20617`). POSIX `seteuid`, regression coverage and passing full `make` are in [draft PR #1974](https://github.com/fglock/PerlOnJava/pull/1974); the focused regression and `t/20compile.t` pass on both backends. [Current claim](https://github.com/fglock/PerlOnJava/issues/1972#issuecomment-6633993418). |
| POSIX filehandles | [#1932](https://github.com/fglock/PerlOnJava/issues/1932) `POSIX::isatty` glob handling | Normal / Active | IO-Pty-Easy 0.10 passes on system Perl; CPAN run `20261030-095654-34969` failed on both PerlOnJava backends because `*STDIN` reached a direct `RuntimeIO` cast. The helper-based fix and focused test pass on both backends; full `make` passes on `fix/posix-isatty-glob`. A fresh `jcpan -t IO::Pty::Easy` rerun timed out after `t/open-close.t` passed and fork-dependent tests skipped. |
| Stash iteration | [#1963](https://github.com/fglock/PerlOnJava/issues/1963) CODE globs copied from `each` | Normal / Active | DDC::Concordance 0.50 failed on both backends when `DDC::Any::mapstash` copied module-created closures from `each %stash`; system Perl passed. The slot snapshot/alias fix in [PR #1966](https://github.com/fglock/PerlOnJava/pull/1966) and eval-based regression pass both backends; all 471 DDC tests pass on the JVM backend, and the five affected files pass on the interpreter. |
| File-handle EOF state | [#1922](https://github.com/fglock/PerlOnJava/issues/1922) `IO::Handle::clearerr` | Normal / Active | `Log::Procmail` 0.14 passes on system Perl but failed on both PerlOnJava backends when reading appended data after EOF. The shared runtime fix and permanent regression are in [draft PR #1924](https://github.com/fglock/PerlOnJava/pull/1924); the full make gate and all 281 CPAN tests pass. Await review and CI. |
Expand Down
2 changes: 2 additions & 0 deletions docs/about/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ priorities and future plans.

- Preserve filehandle line-counter assignments made through localized `$.` scopes (#1965).

- Allow assignment to `$>` to update the process effective user ID through the platform POSIX layer (#1972).

- Resolve glob-backed filehandles in `POSIX::isatty` without assuming the glob value is a `RuntimeIO` (#1932).

- Add an initial CryptX Java XS bridge for binary/base64url helpers, functional digests, and HMAC using the existing JCA and Bouncy Castle providers (#1220).
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/perlonjava/runtime/nativ/NativeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ public static RuntimeScalar geteuid(int ctx, RuntimeBase... args) {
return new RuntimeScalar(posix.geteuid());
}

public static int seteuid(int uid) {
int result = posix.seteuid(uid);
if (result == -1) {
GlobalVariable.getGlobalVariable("main::!").set(posix.strerror(posix.errno()));
}
return result;
}

public static RuntimeScalar getgid(int ctx, RuntimeBase... args) {
return new RuntimeScalar(posix.getgid());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public interface FFMPosixInterface {
* @return Effective user ID
*/
int geteuid();

/** Set the effective user ID; return 0 on success and -1 on failure. */
int seteuid(int uid);

/**
* Get the real group ID.
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/org/perlonjava/runtime/nativ/ffm/FFMPosixLinux.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class FFMPosixLinux implements FFMPosixInterface {
// Method handles for simple functions (no errno capture needed)
private static MethodHandle getuidHandle;
private static MethodHandle geteuidHandle;
private static MethodHandle seteuidHandle;
private static MethodHandle getgidHandle;
private static MethodHandle getegidHandle;
private static MethodHandle getgroupsHandle;
Expand Down Expand Up @@ -181,6 +182,12 @@ private static synchronized void ensureInitialized() {
stdlib.find("geteuid").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_INT)
);

seteuidHandle = linker.downcallHandle(
stdlib.find("seteuid").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT),
captureErrno
);

getgidHandle = linker.downcallHandle(
stdlib.find("getgid").orElseThrow(),
Expand Down Expand Up @@ -628,6 +635,22 @@ public int geteuid() {
return -1;
}
}

@Override
public int seteuid(int uid) {
ensureInitialized();
try (Arena arena = Arena.ofConfined()) {
MemorySegment capturedState = arena.allocate(Linker.Option.captureStateLayout());
int result = (int) seteuidHandle.invokeExact(capturedState, uid);
if (result == -1) {
setErrno(capturedState.get(ValueLayout.JAVA_INT, errnoOffset));
}
return result;
} catch (Throwable e) {
setErrno(1); // EPERM
return -1;
}
}

@Override
public int getgid() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ public int getuid() {
public int geteuid() {
return CURRENT_UID;
}

@Override
public int seteuid(int uid) {
if (uid == CURRENT_UID) return 0;
setErrno(1); // EPERM: Windows identity changes are not emulated.
return -1;
}

@Override
public int getgid() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public boolean isNumberedCapture() {
/** Whether assignments must reach this special scalar's setter. */
public boolean hasSpecialAssignmentBehavior() {
return switch (variableId) {
case INPUT_LINE_NUMBER, HINTS, WARNING_BITS, REMOVED_ENCODING -> true;
case INPUT_LINE_NUMBER, HINTS, WARNING_BITS, REMOVED_ENCODING, EFFECTIVE_UID -> true;
default -> false;
};
}
Expand Down Expand Up @@ -155,6 +155,10 @@ public RuntimeScalar set(RuntimeScalar value) {
}
return scalarUndef;
}
if (variableId == Id.EFFECTIVE_UID) {
NativeUtils.seteuid(value.getInt());
return NativeUtils.geteuid(0);
}
return super.set(value);
}

Expand Down
20 changes: 20 additions & 0 deletions src/test/resources/unit/special_effective_uid_assignment.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use strict;
use warnings;
use Test::More;

# Assigning the current effective UID is safe and should remain a valid write
# even when real and effective IDs differ. Avoid changing this test process's
# privileges while still exercising the special variable setter.
plan skip_all => 'real and effective UIDs differ' if $< != $>;

my $effective_uid = $>;
my $assigned = eval {
$> = $<;
1;
};

ok($assigned, 'assignment to $> accepts the current real UID');
is($@, '', 'assignment to $> does not report a read-only scalar error');
is($>, $effective_uid, 'assignment preserves the effective UID');

done_testing;
Loading